From ac07c98252cdcbacf3340f2b5522f808169331dd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Andr=C3=A9?= Date: Thu, 3 Jun 2010 03:15:46 +0800 Subject: [PATCH] imdb.lua: Redesign, fix some bugs --- share/lua/extensions/imdb.lua | 263 +++++++++++++++++++++++----------- 1 file changed, 181 insertions(+), 82 deletions(-) diff --git a/share/lua/extensions/imdb.lua b/share/lua/extensions/imdb.lua index 7db185903b..a271801f86 100644 --- a/share/lua/extensions/imdb.lua +++ b/share/lua/extensions/imdb.lua @@ -20,11 +20,25 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. --]] -dlg = nil -txt = nil +-- TODO: Use simplexml module to simplify parsing + +-- Global variables +url = nil -- string +title = nil -- string +titles = {} -- table, see code below + +-- Some global variables: widgets +dlg = nil -- dialog +txt = nil -- text field +list = nil -- list widget +button_open = nil -- button widget +html = nil -- rich text (HTML) widget +waitlbl = nil -- text label widget + +-- Script descriptor, called when the extensions are scanned function descriptor() return { title = "IMDb - The Internet Movie Database" ; - version = "0.1" ; + version = "1.0" ; author = "Jean-Philippe André" ; url = 'http://www.imdb.org/'; shortdesc = "The Internet Movie Database"; @@ -36,93 +50,174 @@ function descriptor() capabilities = { "input-listener" } } end +-- Remove trailing & leading spaces +function trim(str) + if not str then return "" end + return string.gsub(str, "^%s*(.*)+%s$", "%1") +end + -- Update title text field. Removes file extensions. function update_title() local item = vlc.input.item() - local title = item and item:name() - if title ~= nil then - title = string.gsub(title, "(.*)(%.%w+)$", "%1") + local name = item and item:name() + if name ~= nil then + name = string.gsub(name, "(.*)(%.%w+)$", "%1") end - if title ~= nil then - txt:set_text(title) + if name ~= nil then + txt:set_text(trim(name)) end end +-- Function called when the input (media being read) changes function input_changed() update_title() end -function create_dialog() - dlg = vlc.dialog("IMDb Search") - dlg:add_label("The Internet Movie Database", 1, 1, 4, 1) - dlg:add_label("Movie Title", 1, 2, 1, 1) - local item = vlc.input.item() - txt = dlg:add_text_input(item and item:name() or "", 2, 2, 1, 1) - dlg:add_button("Okay", click_okay, 3, 2, 1, 1) - dlg:add_button("*", update_title, 4, 2, 1, 1) - dlg:show() -- Show, if not already visible -end - +-- First function to be called when the extension is activated function activate() create_dialog() end +-- This function is called when the extension is disabled function deactivate() end +-- Create the main dialog with a simple search bar +function create_dialog() + dlg = vlc.dialog("IMDb") + dlg:add_label("Movie Title:", 1, 1, 1, 1) + local item = vlc.input.item() + txt = dlg:add_text_input(item and item:name() or "", 2, 1, 1, 1) + dlg:add_button("Search", click_okay, 3, 1, 1, 1) + -- Show, if not already visible + dlg:show() +end + -- Dialog closed function close() -- Deactivate this extension vlc.deactivate() end --- Some global variables: widgets -list = nil -button_open = nil -titles = nil -html = nil - +-- Called when the user presses the "Search" button function click_okay() - vlc.msg.dbg("Searching for " .. txt:get_text() .. " on IMDb") + vlc.msg.dbg("[IMDb] Searching for " .. txt:get_text()) + + -- Search IMDb: build URL + title = string.gsub(string.gsub(txt:get_text(), "[%p%s%c]", "+"), "%++", " ") + url = "http://www.imdb.com/find?s=all&q=" .. string.gsub(title, " ", "+") + -- Recreate dialog structure: delete useless widgets if html then dlg:del_widget(html) html = nil end - if not list then - list = dlg:add_list(1, 3, 4, 1) - button_open = dlg:add_button("Open", click_open, 1, 4, 4, 1) + if list then + dlg:del_widget(list) + dlg:del_widget(button_open) + list = nil + button_open = nil end - -- Clear previous results - list:clear() + -- Ask the user to wait some time... + local waitmsg = 'Searching for ' .. title .. " on IMDb..." + if not waitlbl then + waitlbl = dlg:add_label(waitmsg, 1, 2, 3, 1) + else + waitlbl:set_text(waitmsg) + end + dlg:update() - -- Search IMDb - local url = "http://www.imdb.com/find?s=all&q=" - local title = string.gsub(txt:get_text(), " ", "+") - local s, msg = vlc.stream(url .. title) + -- Download the data + local s, msg = vlc.stream(url) if not s then - vlc.msg.warn(msg) + vlc.msg.warn("[IMDb] " .. msg) + waitlbl:set_text('Sorry, an error occured while searching for ' .. title .. ".
Please try again later.") return end -- Fetch HTML data local data = s:read(65000) + if not data then + vlc.msg.warn("[IMDb] Not data received!") + waitlbl:set_text('Sorry, an error occured while searching for ' .. title .. ".
Please try again later.") + return + end + + -- Probe result & parse it + if string.find(data, "
Overview
") then + -- We found a direct match + parse_moviepage(data) + else + -- We have a list of results to parse + parse_resultspage(data) + end +end + +-- Called when clicked on the "Open" button +function click_open() + -- Get user selection + selection = list:get_selection() + if not selection then return end + + local sel = nil + for idx, selectedItem in pairs(selection) do + sel = idx + break + end + if not sel then return end + local imdbID = titles[sel].id + + -- Update information message + url = "http://www.imdb.org/title/" .. imdbID .. "/" + title = titles[sel].title + + dlg:del_widget(list) + dlg:del_widget(button_open) + list = nil + button_open = nil + waitlbl:set_text("Loading IMDb page for " .. title .. ".") + dlg:update() + + local s, msg = vlc.stream(url) + if not s then + waitlbl:set_text('Sorry, an error occured while looking for ' .. title .. ".") + vlc.msg.warn("[IMDb] " .. msg) + return + end + + data = s:read(65000) + if data and string.find(data, "
Overview
") then + parse_moviepage(data) + else + waitlbl:set_text('Sorry, no results found for ' .. title .. ".") + end +end + +-- Parse the results page and find titles, years & URL's +function parse_resultspage(data) + vlc.msg.dbg("[IMDb] Analysing results page") -- Find titles titles = {} local count = 0 - idxEnd = 1 + local idxEnd = 1 while idxEnd ~= nil do -- Find title types + local titleType = nil _, idxEnd, titleType = string.find(data, "([^<]*Titles[^<]*)", idxEnd) - _, _, nextTitle = string.find(data, "([^<]*Titles[^<]*)", idxEnd) + local _, _, nextTitle = string.find(data, "([^<]*Titles[^<]*)", idxEnd) if not titleType then break else -- Find current scope + local table = nil if not nextTitle then _, _, table = string.find(data, "(.*)
", idxEnd) else @@ -130,63 +225,59 @@ function click_okay() nextTitle = string.gsub(nextTitle, "%)", "%%)") _, _, table = string.find(data, "(.*)
.*"..nextTitle, idxEnd) end - -- Find all titles in this scope + if not table then break end - pos = 0 + local pos = 0 + local thistitle = nil + + -- Find all titles in this scope while pos ~= nil do - _, _, link = string.find(table, "]*>([^<]+)", pos) - if not title then break end -- this would not be normal behavior... - _, _, year = string.find(table, "\((%d+)\)", pos) + _, pos, thistitle = string.find(table, "]*>([^<]+)", pos) + if not thistitle then break end -- this would not be normal behavior... + local _, _, year = string.find(table, "\((%d+)\)", pos) -- Add this title to the list count = count + 1 - _, _, imdbID = string.find(link, "/([^/]+)/$") - title = replace_html_chars(title) - titles[count] = { id = imdbID ; title = title ; year = year ; link = link } + local _, _, imdbID = string.find(link, "/([^/]+)/$") + thistitle = replace_html_chars(thistitle) + titles[count] = { id = imdbID ; title = thistitle ; year = year ; link = link } end end end - for idx, title in ipairs(titles) do - list:add_value("[" .. title.id .. "] " .. title.title .. " (" .. title.year .. ")", idx) - end -end - -function click_open() - selection = list:get_selection() - if not selection then return 1 end - if not html then - html = dlg:add_html("Loading IMDb page...", 1, 3, 4, 1) - -- userLink = dlg:add_label("", 1, 4, 5, 1) + -- Did we find anything at all? + if not count or count == 0 then + waitlbl:set_text('Sorry, no results found for ' .. title .. ".") + return end - dlg:del_widget(list) - dlg:del_widget(button_open) - list = nil - button_open = nil + -- Sounds good, we found some results, let's display them + waitlbl:set_text(count .. " results found for " .. title .. ".") + list = dlg:add_list(1, 3, 3, 1) + button_open = dlg:add_button("Open", click_open, 3, 4, 1, 1) - local sel = nil - for idx, selectedItem in pairs(selection) do - sel = idx - break + for idx, title in ipairs(titles) do + --list:add_value("[" .. title.id .. "] " .. title.title .. " (" .. title.year .. ")", idx) + list:add_value(title.title .. " (" .. title.year .. ")", idx) end - imdbID = titles[sel].id - url = "http://www.imdb.org/title/" .. imdbID .. "/" +end - -- userLink:set_text("" .. url .. "") +-- Parse a movie description page +function parse_moviepage(data) + -- Title & year + title = string.gsub(data, "^.*(.*).*$", "%1") + local text = "

" .. title .. "

" + text = text .. "

Overview

" - local s, msg = vlc.stream(url) - if not s then - vlc.msg.warn(msg) - return + -- Real URL + url = string.gsub(data, "^.*" - text = text .. "

Overview

" - -- Director local director = nil _, nextIdx, _ = string.find(data, "
]+>([%w%s]+)
... ]+>([%w%s]+)") do if not first then actors = actors .. "
" @@ -223,13 +314,21 @@ function click_open() end text = text .. actors .. "
" + waitlbl:set_text("
" .. title .. "
") + if list then + dlg:del_widget(list) + dlg:del_widget(button_open) + end + html = dlg:add_html(text .. "
Loading summary...", 1, 3, 3, 1) + dlg:update() + text = text .. "

Plot Summary

" - s, msg = vlc.stream(url .. "plotsummary") + local s, msg = vlc.stream(url .. "plotsummary") if not s then - vlc.msg.warn(msg) + vlc.msg.warn("[IMDb] " .. msg) return end - data = s:read(65000) + local data = s:read(65000) -- We read only the first summary _, _, summary = string.find(data, "

([^<]+)") -- 2.39.2