2 Get information about a movie from IMDb
4 Copyright © 2009-2010 VideoLAN and AUTHORS
6 Authors: Jean-Philippe André (jpeg@videolan.org)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 return { title = "IMDb - The Internet Movie Database" ;
28 author = "Jean-Philippe André" ;
29 url = 'http://www.imdb.org/';
30 description = "<center><b>The Internet Movie Database</b></center>\n"
31 .. "Get information about movies from the Internet "
32 .. "Movie Database (IMDb).\nThis Extension will show "
33 .. "you the cast, a short plot summary and a link to "
34 .. "the web page on imdb.org." ;
38 -- Update title text field. Removes file extensions.
39 function update_title()
40 local title = vlc.input.get_title()
41 if (title ~= nil) then
42 title = string.gsub(title, "(.*)(%.%w+)$", "%1")
44 if (title ~= nil) then
49 function create_dialog()
50 dlg = vlc.dialog("IMDb Search")
51 dlg:add_label("The Internet Movie Database", 1, 1, 4, 1)
52 dlg:add_label("<b>Movie Title</b>", 1, 2, 1, 1)
53 txt = dlg:add_text_input(vlc.input.get_title(), 2, 2, 1, 1)
54 dlg:add_button("Okay", "click_okay", 3, 2, 1, 1)
55 dlg:add_button("*", "update_title", 4, 2, 1, 1)
56 dlg:show() -- Show, if not already visible
68 -- Deactivate this extension
72 -- Some global variables: widgets
79 vlc.msg.dbg("Searching for " .. txt:get_text() .. " on IMDb")
87 list = dlg:add_list(1, 3, 4, 1)
88 button_open = dlg:add_button("Open", "click_open", 1, 4, 4, 1)
91 -- Clear previous results
95 local url = "http://www.imdb.com/find?s=all&q="
96 local title = string.gsub(txt:get_text(), " ", "+")
97 local s = vlc.stream(url .. title)
100 local data = s:read(65000)
107 while idxEnd ~= nil do
109 _, idxEnd, titleType = string.find(data, "<b>([^<]*Titles[^<]*)</b>", idxEnd)
110 _, _, nextTitle = string.find(data, "<b>([^<]*Titles[^<]*)</b>", idxEnd)
111 if (not titleType) then
114 -- Find current scope
115 if (not nextTitle) then
116 _, _, table = string.find(data, "<table>(.*)</table>", idxEnd)
118 nextTitle = string.gsub(nextTitle, "%(", "%%(")
119 nextTitle = string.gsub(nextTitle, "%)", "%%)")
120 _, _, table = string.find(data, "<table>(.*)</table>.*"..nextTitle, idxEnd)
122 -- Find all titles in this scope
123 if (not table) then break end
125 while (pos ~= nil) do
126 _, _, link = string.find(table, "<a href=\"([^\"]+title[^\"]+)\"", pos)
127 if (not link) then break end -- this would not be normal behavior...
128 _, pos, title = string.find(table, "<a href=\"" .. link .. "\"[^>]*>([^<]+)</a>", pos)
129 if (not title) then break end -- this would not be normal behavior...
130 _, _, year = string.find(table, "\((%d+)\)", pos)
131 -- Add this title to the list
133 _, _, imdbID = string.find(link, "/([^/]+)/$")
134 title = replace_html_chars(title)
135 titles[count] = { id = imdbID ; title = title ; year = year ; link = link }
140 for idx, title in ipairs(titles) do
141 list:add_value("[" .. title.id .. "] " .. title.title .. " (" .. title.year .. ")", idx)
145 function click_open()
146 selection = list:get_selection()
147 if (not selection) then return 1 end
149 html = dlg:add_html("Loading IMDb page...", 1, 3, 4, 1)
150 -- userLink = dlg:add_label("", 1, 4, 5, 1)
154 dlg:del_widget(button_open)
159 for idx, selectedItem in pairs(selection) do
163 imdbID = titles[sel].id
164 url = "http://www.imdb.org/title/" .. imdbID .. "/"
166 -- userLink:set_text("<a href=\"url\">" .. url .. "</a>")
168 local s = vlc.stream(url)
171 text = "<h1>" .. titles[sel].title .. " (" .. titles[sel].year .. ")</h1>"
172 text = text .. "<h2>Overview</h2><table>"
176 _, nextIdx, _ = string.find(data, "<div id=\"director-info\"", 1, true)
178 _, _, director = string.find(data, "<a href[^>]+>([%w%s]+)</a>", nextIdx)
180 if (not director) then
181 director = "(Unknown)"
183 text = text .. "<tr><td><b>Director</b></td><td>" .. director .. "</td></tr>"
186 local genres = "<tr><td><b>Genres</b></td>"
188 for genre, _ in string.gmatch(data, "/Sections/Genres/(%w+)/\">") do
190 genres = genres .. "<td>" .. genre .. "</td></tr>"
192 genres = genres .. "<tr><td /><td>" .. genre .. "</td></tr>"
196 text = text .. genres
199 local actors = "<tr><td><b>Cast</b></td>"
201 for nm, char in string.gmatch(data, "<td class=\"nm\"><a[^>]+>([%w%s]+)</a></td><td class=\"ddd\"> ... </td><td class=\"char\"><a[^>]+>([%w%s]+)</a>") do
203 actors = actors .. "<tr><td />"
205 actors = actors .. "<td>" .. nm .. "</td><td><i>" .. char .. "</i></td></tr>"
208 text = text .. actors .. "</table>"
210 text = text .. "<h2>Plot Summary</h2>"
211 s = vlc.stream(url .. "plotsummary")
214 -- We read only the first summary
215 _, _, summary = string.find(data, "<p class=\"plotpar\">([^<]+)")
216 if (not summary) then
217 summary = "(Unknown)"
219 text = text .. "<p>" .. summary .. "</p>"
220 text = text .. "<p><h2>Source IMDb</h2><a href=\"" .. url .. "\">" .. url .. "</a></p>"
225 -- Convert some HTML characters into UTF8
226 function replace_html_chars(txt)
227 if (not txt) then return nil end
228 -- return vlc.strings.resolve_xml_special_chars(txt)
229 for num in string.gmatch(txt, "&#x(%x+);") do
230 -- Convert to decimal (any better way?)
232 for c in string.gmatch(num, "%x") do
233 cc = string.byte(c) - string.byte("0")
234 if (cc >= 10 or cc < 0) then
235 cc = string.byte(string.lower(c)) - string.byte("a") + 10
239 txt = string.gsub(txt, "&#x" .. num .. ";", string.char(dec))