]> git.sesse.net Git - vlc/blob - share/lua/extensions/imdb.lua
2eaa7e5edfe6ddaef9909c113b43a8321d2755dc
[vlc] / share / lua / extensions / imdb.lua
1 --[[
2  Get information about a movie from IMDb
3
4  Copyright © 2009-2010 VideoLAN and AUTHORS
5
6  Authors:  Jean-Philippe André (jpeg@videolan.org)
7
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.
12
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.
17
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.
21 --]]
22
23 dlg = nil
24 txt = nil
25 function descriptor()
26     return { title = "IMDb - The Internet Movie Database" ;
27              version = "0.1" ;
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." ;
35              capabilities = {} }
36 end
37
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")
43     end
44     if (title ~= nil) then
45         txt:set_text(title)
46     end
47 end
48
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
57 end
58
59 function activate()
60     create_dialog()
61 end
62
63 function deactivate()
64 end
65
66 -- Dialog closed
67 function close()
68     -- Deactivate this extension
69     vlc.deactivate()
70 end
71
72 -- Some global variables: widgets
73 list = nil
74 button_open = nil
75 titles = nil
76 html = nil
77
78 function click_okay()
79     vlc.msg.dbg("Searching for " .. txt:get_text() .. " on IMDb")
80
81     if html then
82         dlg:del_widget(html)
83         html = nil
84     end
85
86     if (not list) then
87         list = dlg:add_list(1, 3, 4, 1)
88         button_open = dlg:add_button("Open", "click_open", 1, 4, 4, 1)
89     end
90
91     -- Clear previous results
92     list:clear()
93
94     -- Search IMDb
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)
98
99     -- Fetch HTML data
100     local data = s:read(65000)
101
102     -- Find titles
103     titles = {}
104     local count = 0
105
106     idxEnd = 1
107     while idxEnd ~= nil do
108         -- Find title types
109         _, idxEnd, titleType = string.find(data, "<b>([^<]*Titles[^<]*)</b>", idxEnd)
110         _, _, nextTitle = string.find(data, "<b>([^<]*Titles[^<]*)</b>", idxEnd)
111         if (not titleType) then
112             break
113         else
114             -- Find current scope
115             if (not nextTitle) then
116                 _, _, table = string.find(data, "<table>(.*)</table>", idxEnd)
117             else
118                 nextTitle = string.gsub(nextTitle, "%(", "%%(")
119                 nextTitle = string.gsub(nextTitle, "%)", "%%)")
120                 _, _, table = string.find(data, "<table>(.*)</table>.*"..nextTitle, idxEnd)
121             end
122             -- Find all titles in this scope
123             if (not table) then break end
124             pos = 0
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
132                 count = count + 1
133                 _, _, imdbID = string.find(link, "/([^/]+)/$")
134                 title = replace_html_chars(title)
135                 titles[count] = { id = imdbID ; title = title ; year = year ; link = link }
136             end
137         end
138     end
139
140     for idx, title in ipairs(titles) do
141         list:add_value("[" .. title.id .. "] " .. title.title .. " (" .. title.year .. ")", idx)
142     end
143 end
144
145 function click_open()
146     selection = list:get_selection()
147     if (not selection) then return 1 end
148     if (not html) then
149         html = dlg:add_html("Loading IMDb page...", 1, 3, 4, 1)
150         -- userLink = dlg:add_label("", 1, 4, 5, 1)
151     end
152
153     dlg:del_widget(list)
154     dlg:del_widget(button_open)
155     list = nil
156     button_open = nil
157
158     local sel = nil
159     for idx, selectedItem in pairs(selection) do
160         sel = idx
161         break
162     end
163     imdbID = titles[sel].id
164     url = "http://www.imdb.org/title/" .. imdbID .. "/"
165
166     -- userLink:set_text("<a href=\"url\">" .. url .. "</a>")
167
168     local s = vlc.stream(url)
169     data = s:read(65000)
170
171     text = "<h1>" .. titles[sel].title .. " (" .. titles[sel].year .. ")</h1>"
172     text = text .. "<h2>Overview</h2><table>"
173
174     -- Director
175     local director = nil
176     _, nextIdx, _ = string.find(data, "<div id=\"director-info\"", 1, true)
177     if (nextIdx) then
178         _, _, director = string.find(data, "<a href[^>]+>([%w%s]+)</a>", nextIdx)
179     end
180     if (not director) then
181         director = "(Unknown)"
182     end
183     text = text .. "<tr><td><b>Director</b></td><td>" .. director .. "</td></tr>"
184
185     -- Main genres
186     local genres = "<tr><td><b>Genres</b></td>"
187     local first = true
188     for genre, _ in string.gmatch(data, "/Sections/Genres/(%w+)/\">") do
189         if (first) then
190             genres = genres .. "<td>" .. genre .. "</td></tr>"
191         else
192             genres = genres .. "<tr><td /><td>" .. genre .. "</td></tr>"
193         end
194         first = false
195     end
196     text = text .. genres
197
198     -- List main actors
199     local actors = "<tr><td><b>Cast</b></td>"
200     first = true
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
202         if (not first) then
203             actors = actors .. "<tr><td />"
204         end
205         actors = actors .. "<td>" .. nm .. "</td><td><i>" .. char .. "</i></td></tr>"
206         first = false
207     end
208     text = text .. actors .. "</table>"
209
210     text = text .. "<h2>Plot Summary</h2>"
211     s = vlc.stream(url .. "plotsummary")
212     data = s:read(65000)
213
214     -- We read only the first summary
215     _, _, summary = string.find(data, "<p class=\"plotpar\">([^<]+)")
216     if (not summary) then
217         summary = "(Unknown)"
218     end
219     text = text .. "<p>" .. summary .. "</p>"
220     text = text .. "<p><h2>Source IMDb</h2><a href=\"" .. url .. "\">" .. url .. "</a></p>"
221
222     html:set_text(text)
223 end
224
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?)
231         dec = 0
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
236             end
237             dec = dec * 16 + cc
238         end
239         txt = string.gsub(txt, "&#x" .. num .. ";", string.char(dec))
240     end
241     return txt
242 end
243