]> git.sesse.net Git - vlc/blob - share/lua/extensions/allocine-fr.lua
Lua: Allocine, grow buffer up to 500k
[vlc] / share / lua / extensions / allocine-fr.lua
1 --[[
2  Allocine Extension for VLC media player 1.1
3  French website only
4
5  Copyright © 2010 VideoLAN and AUTHORS
6
7  Authors:  Jean-Philippe André (jpeg@videolan.org)
8
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 --]]
23
24 -- Lua modules
25 require "simplexml"
26
27 -- Global variables
28 dlg = nil     -- Dialog
29 title = nil   -- Text input widget
30 message = nil -- Label
31 list = nil    -- List widget
32 okay = nil    -- Okay button
33 html = nil    -- HTML box
34 films = {}
35
36 -- Extension description
37 function descriptor()
38     return { title = "Allociné (France)" ;
39              version = "1.0" ;
40              author = "VideoLAN" ;
41              url = 'http://www.allocine.fr/';
42              shortdesc = "Allocine.com";
43              description = "<center><b>ALLOCINE.COM</b></center>"
44                         .. "Récupère des informations sur le média en cours "
45                         .. "de lecture depuis Allocine.fr, telles que :<br />"
46                         .. "- Casting,<br />- Résumé,<br />- Note des utilisateurs,"
47                         .. "<br />- Lien direct vers la fiche du film sur "
48                         .. "<a href=\"http://www.allocine.fr\">allocine.fr</a>." ;
49              capabilities = { "input-listener", "meta-listener" } }
50 end
51
52 -- Activation hook
53 function activate()
54     vlc.msg.dbg("[ALLOCINE.COM] Welcome on Allocine.fr")
55     create_dialog()
56 end
57
58 -- Deactivation hook
59 function deactivate()
60     vlc.msg.dbg("[ALLOCINE.COM] Bye bye!")
61 end
62
63 -- Dialog close hook
64 function close()
65     -- Deactivate this extension
66     vlc.deactivate()
67 end
68
69 -- Input change hook
70 function input_changed()
71     title:set_text(get_title())
72 end
73
74 -- Meta change hook
75 function meta_changed()
76     title:set_text(get_title())
77 end
78
79 -- Create the dialog
80 function create_dialog()
81     dlg = vlc.dialog("ALLOCINE.COM")
82     dlg:add_label("<b>Titre du film:</b>", 1, 1, 1, 1)
83     title = dlg:add_text_input(get_title(), 2, 1, 1, 1)
84     dlg:add_button("Rechercher", click_chercher, 3, 1, 1, 1)
85 end
86
87 -- Get clean title from filename
88 function get_title(str)
89     local item = vlc.item or vlc.input.item()
90     if not item then
91         return ""
92     end
93     local metas = item:metas()
94     if metas["title"] then
95         return metas["title"]
96     else
97         local filename = string.gsub(item:name(), "^(.+)%.%w+$", "%1")
98         return trim(filename or item:name())
99     end
100 end
101
102 -- Remove leading and trailing spaces
103 function trim(str)
104     if not str then return "" end
105     return string.gsub(str, "^%s*(.-)%s*$", "%1")
106 end
107
108 -- Lookup for this movie title
109 function click_chercher()
110     -- Get title
111     local name = title:get_text()
112     if not name or name == "" then
113         vlc.msg.dbg("[ALLOCINE.COM] No title")
114         return
115     end
116
117     -- Update dialog
118     if list then
119         dlg:del_widget(list)
120         list = nil
121     end
122
123     -- Transform spaces and dots into +
124     name = string.gsub(string.gsub(name, "[%p%s%c]", "+"), "%++", "+")
125
126     -- Build URL
127     local url = "http://www.allocine.fr/recherche/?q=" .. name
128
129     -- Please wait...
130     local message_text = "Recherche <a href=\"" .. url .. "\">" .. string.gsub(name, "%+", " ") .. "</a> sur Allociné..."
131     if not message then
132         message = dlg:add_label(message_text, 1, 2, 3, 1)
133     else
134         message:set_text(message_text)
135     end
136     if list then dlg:del_widget(list) end
137     if okay then dlg:del_widget(okay) end
138     if html then dlg:del_widget(html) end
139     list = nil
140     okay = nil
141     html = nil
142     dlg:update()
143
144     -- Open URL
145     local s, msg = vlc.stream(url)
146     if not s then
147         vlc.msg.warn("[ALLOCINE.COM] " .. msg)
148     end
149
150     -- Fetch HTML data (max 65 kb)
151     local data = s:read(65535)
152
153     -- Clean data
154     data = string.gsub(data, "<b>", "")
155     data = string.gsub(data, "</b>", "")
156     data = string.gsub(data, "%s+", " ")
157
158     -- Data storage
159     films = {}
160
161     -- Find categories
162     for category in string.gmatch(data, "<[hH]2>%s*([^<]+)%s*</[hH]2>") do
163         local category = trim(category)
164
165         -- Split substring corresponding to this table
166         local _, first = string.find(data, "<[hH]2>%s*" .. category .. "%s*</[hH]2>")
167         first, _ = string.find(data, "<table", first)
168         local _, last = string.find(data, "</table>", first)
169
170         -- Find movies and TV shows
171         if category == "Films" or category == "Séries TV" then
172             -- Read <table> tag as xml
173             local substring = string.sub(data, first, last or -1)
174
175             local xml = simplexml.parse_string(substring)
176             for _, tr in ipairs(xml.children) do
177                 -- Get film title & year
178                 local film_title = nil
179                 local film_year = nil
180                 local node = tr.children[2] -- td
181                 if node then node = node.children[1] end -- div (1)
182                 if node then node = node.children[1] end -- div (2)
183                 local subnode = nil
184                 if node then
185                     for _, subnode in ipairs(node.children) do
186                         if subnode.name == "a" and type(subnode.children[1]) == "string" then
187                             film_title = trim(subnode.children[1]) -- content of a tag
188                         else if subnode.name == "span" and type(subnode.children[1]) == "string" then
189                             film_year = trim(subnode.children[1])
190                         end end
191                     end
192                 end
193
194                 -- Get film cover & URL
195                 local film_image = nil
196                 local film_url = nil
197                 local node = tr.children[1] -- td
198                 if node then node = node.children[1] end -- a
199                 if node and node.name == "a" then
200                     film_url = node.attributes["href"]
201                     node = node.children[1]
202                     if node and node.name == "img" then
203                         film_image = node.attributes["src"]
204                     end
205                 end
206
207                 -- Append fetched information
208                 if film_title then
209                     if string.sub(film_url, 1, 4) ~= "http" then
210                         film_url = "http://www.allocine.fr" .. film_url
211                     end
212                     films[#films+1] = { url = film_url ; image = film_image ; year = film_year ; title = film_title }
213                 end
214             end
215         end
216     end
217
218     -- Print information
219     -- No results found
220     if #films == 0 then
221         message_text = "<center>Aucun résultat trouvé pour <b>" .. string.gsub(name, "%+", " ") .. "</b>.</center>"
222                     .. "Vous pouvez aussi chercher directement sur <a href=\"" .. url .. "\">Allociné</a>."
223         message:set_text(message_text)
224     end
225
226     -- Only one movie or TV show matches, let's open its page directly
227     if #films == 1 then
228         message_text = "<center><a href=\"" .. films[1].url .. "\">" .. films[1].title .. "</a></center>"
229         message:set_text(message_text)
230         dlg:update()
231         open_fiche(films[1].url)
232     end
233
234     -- More than 1 match, display a list
235     if #films > 1 then
236         message_text = tostring(#films) .. " films ou séries TV trouvés sur Allociné :"
237         message:set_text(message_text)
238         list = dlg:add_list(1, 3, 3, 1)
239         for idx, film in ipairs(films) do
240             local txt = film.title
241             if film.year then txt = txt .. " (" .. film.year .. ")" end
242             list:add_value(txt, idx)
243         end
244         okay = dlg:add_button("Voir la fiche", click_okay, 3, 4, 1, 1)
245     end
246 end
247
248 -- Click after selection
249 function click_okay()
250     if not films or not #films then return end
251     local selection = list:get_selection()
252     if not selection then return end
253
254     local sel, _ = next(selection, nil)
255     if not sel then return end
256
257     message_text = "<center><a href=\"" .. films[sel].url .. "\">" .. films[sel].title .. "</a></center>"
258     message:set_text(message_text)
259     dlg:update()
260     open_fiche(films[sel].url)
261 end
262
263 -- Open a movie's information page
264 function open_fiche(url)
265     if okay then
266         dlg:del_widget(okay)
267         okay = nil
268     end
269     if list then
270         dlg:del_widget(list)
271         list = nil
272     end
273
274     if not html then
275         html = dlg:add_html("<center><i>Chargement en cours...</i></center>", 1, 3, 3, 1)
276     end
277     dlg:update()
278
279     -- Open stream
280     local s = vlc.stream(url)
281     -- Read max 500k (Note: 65k is not enough for the average note)
282     local data = s:read(500000)
283
284     -- Buffer & temp variables
285     local first = nil
286     local last = nil
287     local page = nil
288     local sub = nil
289     local name = nil
290
291     first, _ = string.find(data, '<div class="rubric">')
292
293     if not first then
294         message:set_text("<h2>Erreur !</h2>Désolé, une erreur est survenue pendant le chargement de la fiche.<br />"
295                       .. "<a href=\"" .. url .. "\">Cliquez ici pour consulter la page sur Allociné.fr</a>.")
296         dlg:del_widget(html)
297         return
298     end
299
300     -- Extract information
301     local last, _ = string.find(data, '<ul id="link_open"')
302     if not last then
303         last, _ = string.find(data, 'notationbar')
304     end
305     sub = string.sub(data, first, last-1)
306
307     -- Clean data
308     sub = string.gsub(sub, "%s+", " ")
309     sub = string.gsub(sub, "</?p>", "<br/>")
310     sub = string.gsub(sub, "</?div[^>]*>", "")
311     sub = string.gsub(sub, "</?span[^>]*>", "")
312     sub = string.gsub(sub, "<%!%-%-[^%-]+%-%->", "")
313     sub = string.gsub(sub, "<br%s*/>%s*<br%s*/>", "<br/>")
314     page = string.gsub(sub, "Synopsis :.*$", "")
315
316     -- Style
317     local synopsis = string.gsub(sub, ".*Synopsis :(.*)", "<h2>Synposis</h2>%1")
318
319     -- Note
320     first, _ = string.find(data, "Note Moyenne:")
321     if first then
322         local _, note = string.find(data, "span class=\"lighten\">%(", first)
323         if note then
324             note = string.sub(data, note+1, note+3)
325             note = string.gsub(note, "%).*$", "")
326             page = page .. "Note moyenne: <b>" .. note .. " / 4</b>"
327             local nbpeople = string.gsub(data, ".*pour (%d+) notes.*", "%1")
328             if nbpeople then
329                 page = page .. " (" .. nbpeople .. " votes)"
330             end
331         end
332     end
333
334     -- Synopsis
335     page = page .. synopsis
336
337     -- Movie title
338     if string.find(data, '<h1>.*</h1>') then
339         name = string.gsub(data, '^.*<h1>%s*(.*)%s*</h1>.*$', '%1')
340         name = trim(name)
341     end
342
343     page = page .. "<h2>Source</h2>"
344     if name then
345         page = page .. name .. " sur <a href='" .. url .. "'>Allociné</a>"
346     else
347         page = page .. "<a href='" .. url .. "'>Allociné</a>"
348     end
349
350     page = string.gsub(page, "href=([\"'])/", "href=%1http://www.allocine.fr/")
351     html:set_text(page)
352 end