Commit 629eac21 authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf

Day 6

parent 75e2a352
......@@ -22,9 +22,9 @@ in their <b>free time</b>, we welcome donations to help us manage the software.
<h1><a class="actionDay" id="link-day1">Day 1</a></h1>
<h1><a class="actionDay" id="link-day2">Day 2</a></h1>
<h1><a class="actionDay" id="link-day3">Day 3</a></h1>
<h1><a class="actionDay" id="link-day4" style="font-weight: bold;">Day 4</a></h1>
<h1><a class="actionDay" id="link-day5" style="font-weight: bold;">Day 5</a></h1>
<h1>Day 6</h1>
<h1><a class="actionDay" id="link-day4">Day 4</a></h1>
<h1><a class="actionDay" id="link-day5">Day 5</a></h1>
<h1><a class="actionDay" id="link-day6" style="font-weight: bold;">Day 6</a></h1>
<h1>Day 7</h1>
<h1>Day 8</h1>
<h1>Day 9</h1>
......@@ -111,7 +111,7 @@ function vlcskins($img,$thumb, $skin){
?>
</div>
<div id="day5" class="selected">
<div id="day5" style="display: none;">
<h1>Day 5: Small photo from the VideoLAN team from FOSDEM</h1>
<br />
<p>For our 5<sup>th</sup> day, we'd like to share a small <b>photo</b> we've done during the <a href="http://fosdem.org">FOSDEM</a>
......@@ -122,6 +122,38 @@ function vlcskins($img,$thumb, $skin){
<br />
</div>
<div id="day6" class="selected">
<h1>Day 6: Best extensions for VLC</h1>
<br />
<h2>VLC extensions</h2>
<p>For our 6<sup>th</sup> day, we'd like to speak about <b>extensions</b> for VLC and provide a few.</p>
<p>Extensions in VLC are not very popular yet, because we are missing a few functionnalities.<br />
Still, some are already cool to use.</p>
<p>Extensions in VLC can add new features that we don't want to support in the main core, or that we cannot.</p>
<h2>Some extensions</h2>
<br />
<h3>VLC extension: subtitles downloader</h3>
<p>This small extension allows you to get subtitles directly from web databases<br />
<a href="http://anonym.to/?http://ale5000.altervista.org/vlc/extensions/subtitles-mod.lua">Download it now!</a></p>
<br />
<h3>VLC extensions: movie information</h3>
<p>These are, in fact, 4 extension to get more information about the movie currently playing:
<br /><a href="http://git.videolan.org/?p=vlc.git;a=blob_plain;f=share/lua/extensions/allocine-fr.lua;hb=HEAD">Allocine.fr extension</a>
<br /><a href="http://git.videolan.org/?p=vlc.git;a=blob_plain;f=share/lua/extensions/imdb.lua;hb=HEAD">IMDB.com extension</a>
<br /><a href="lua/moviedb.lua">themoviedb.org extension</a>
<br /><a href="lua/tvdb.lua">thetvdb.com extension</a></p>
<p><b>NB:</b> the legality of the use of these extension is not clear yet. If you have any info, please share with us.</p>
<br />
<h3>VLC extension: Add Similar files</h3>
<p>This extension will find the similar files in the same folder (like for TV shows)<br />
than the file playing and add them to the playlist.<br />
<a href="lua/addsimilar.lua">Download it now!</a></p>
<br />
<p><em style="font-style: italic;">Sorry, but because of the FOSDEM event, this day 6, that was supposed to be out on sunday, went out on monday :D</em></p>
<br />
</div>
</div>
<script type='text/javascript'>
......
--[[
Add Similar, testing version
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
--]]
--[[ Extension description ]]
function descriptor()
return { title = "Add Similar" ;
version = "alpha" ;
author = "VideoLAN" ;
shortdesc = "Quickly adds files similar to the one you're playing";
description = "<h1>Add Similar</h1>"
.. "When you're playing a file, use Add Similar to"
.. "easily add files that are similar (like those in a series).";
capabilities = { "input-listener", "meta-listener" } }
end
--[[ Global vars ]]
path = nil
target = nil
--[[ Hooks ]]
-- Activation hook
function activate()
vlc.msg.dbg("[Add Similar] Activated")
start()
end
-- Deactivation hook
function deactivate()
vlc.msg.dbg("[Add Similar] Deactivated")
end
--[[ Start ]]
function start()
item = vlc.item or vlc.input.item() -- check if an item is playing
if not item then -- return an alert box explaining what the user should do
alert("Using Add Similar",
"When you're playing a file, use Add Similar to "
.. "automatically add other files in its folder that are like "
.. "the one you're playing."
.."<br /><br />To use Add Similar, start playing a file.")
vlc.msg.dbg("[Add Similar] No item has been selected.")
else
find_similar(item) -- starts the "Find Similar" process
end
end
function find_similar(item)
vlc.msg.dbg("[Add Similar] File selected: "..vlc.strings.decode_uri((item:uri())))
-- Check the protocol (currently, only file:/// is supported)
if string.find(item:uri(), "file:///") then
similar_media = find_files(item) -- delegate to the find_files
vlc.msg.dbg("[Add Similar] Files found: "..table.concat(similar_media," , "))
else
similar_media = {}
vlc.msg.dbg("[Add Similar] Unsupported media type.")
alert("Unsupported media type", "We're sorry, but Add Similar only works on local files right now.")
end
-- Did it return anything?
if #similar_media == 0 then -- If nothing was returned, inform the user
vlc.msg.info("[Add Similar] didn't find similar files")
alert("No similar files could be found.", "")
else -- Add the files
vlc.msg.info("[Add Similar] found similar files")
for _,file in pairs(similar_media) do
local new_item = {}
new_item.path = "file:///"..path..file
new_item.name = file
vlc.msg.dbg("[Add Similar] adding: "..path..file)
vlc.playlist.enqueue({new_item})
end
vlc.deactivate()
end
end
-- This function will find files and add them to a table, which it returns.
function find_files(item)
-- Scour the directory for files (Starts at position 9 to get rid of "file:///") (TODO: Clean this up!)
path = vlc.strings.decode_uri(string.sub(item:uri(), 9 , -(string.find(string.reverse(item:uri()), "/", 0, true))))
target = vlc.strings.decode_uri(string.sub(item:uri(), string.len(item:uri())+2-(string.find(string.reverse(item:uri()), "/", 0, true))), -0)
vlc.msg.dbg("[Add Similar] Target file: "..target)
vlc.msg.dbg("[Add Similar] Loading directory: "..path)
-- Load directory contents into a table
local contents = vlc.net.opendir(path)
-- TEST 1: Split the filename into words
local keywords = split(target,"[%p%s]")
vlc.msg.dbg("[Add Similar] Keywords: "..table.concat(keywords," \\ "))
-- TEST 2: Analyze the filename to find its structure
local structure = split(target,"[^%p]+")
vlc.msg.dbg("[Add Similar] Structure: "..table.concat(structure))
-- TEST 3: Look for keywords (second pass)
score= {}
for _, file in pairs(contents) do
vlc.msg.dbg("[Add Similar] "..file)
if not (file == target or file == '.' or file == '..') then
-- TEST 1: Look for matches in words in the file
local file_keywords = split(file,"[%p%s]")
local matches = 0
for _,key in pairs(keywords) do
for _,file_key in pairs(file_keywords) do
if (file_key == key) then
matches = matches + 1
end
end
end
vlc.msg.dbg(" Matches: "..matches)
vlc.msg.dbg(" Probability: "..(matches/#keywords))
increment = ((matches/#keywords)*100)*0.40
score[file] = score[file] or 0
score[file] = score[file] + increment
vlc.msg.dbg(" Score added: "..increment)
-- TEST 2: Look for similarities in file structure
local file_structure = split(target,"[^%p]+")
if table.concat(file_structure)==table.concat(structure) then
increment = 40
vlc.msg.dbg(" Structure match: true")
score[file] = score[file] or 0
score[file] = score[file] + increment
vlc.msg.dbg(" Score added: "..increment)
end
score[file] = score[file] or 0
vlc.msg.dbg(" Final score: "..score[file])
else
vlc.msg.dbg(" Not analyzed")
end
end
local cutoff = 60 -- arbitrary value
-- Return similar media
local similar_media = {}
for file,p in pairs(score) do
if p > cutoff then
table.insert(similar_media,file)
end
end
return similar_media
end
--[[ UTILITY FUNCTIONS ]]--
-- Create an alertbox, also quitting the extension
function alert(title,message)
local dialog = vlc.dialog("Add Similar")
dialog:add_label("<h2>"..title.."</h2>", 1, 1, 5, 10)
dialog:add_label(message, 1, 14, 5, 5, 200)
dialog:add_button("OK", function () dialog:delete() vlc.deactivate(); return nil end, 3, 20, 1, 5)
end
function close() -- when the messagebox is closed
vlc.deactivate()
end
-- Splits a string into a table, based on a patterns (from: http://http://lua-users.org/wiki/SplitJoin )
function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t,cap)
end
return t
end
\ No newline at end of file
--[[
Retrieve movie information from themoviedb.org
]]
--global variables
APIKEY = "c2c73ebd1e25cbc29cf61158c04ad78a" --key for the TMDb API
CHUNK_SIZE = 65000 --how many characters to read at once from the stream
dialog = nil --dialog box
search_box = nil --search box
wait_label = nil --"Searching for ..." label
movie_list = {} --movies from search result
movie_frame = nil --displays the movie overview
result_list = nil --listbox that display search results
open = nil --button that opens the selected movie
title = "" --search box input
-- Script descriptor, called when the extensions are scanned
function descriptor()
return { title = "TMDb - themoviedb.org" ;
version = "1.0" ;
author = "Anonymous" ;
url = 'http://www.themoviedb.org/';
shortdesc = "themoviedb.org";
description = "<center><b>themoviedb.org</b></center><br />"
.. "Get information about movies from the themoviedb.org (TMDb).<br />"
.. "This extension will show you the tagline, director, screenwriters, "
.. "genres, cast, links to the trailer video and homepage, "
.. "and a link to the movie's TMDb page." ;
capabilities = { "input-listener" } }
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
-- Dialog closed
function close()
-- Deactivate this extension
vlc.deactivate()
end
-- Create the main dialog with a simple search bar
function create_dialog()
dialog = vlc.dialog("TMDb")
dialog:add_label("<b>Movie Title:</b>", 1, 1, 1, 1)
local item = vlc.input.item()
text = dialog:add_text_input(item and item:name() or "", 2, 1, 1, 1)
dialog:add_button("Search", search, 3, 1, 1, 1)
dialog:show()
end
--Called when user hits the search button
function search()
--Clear results from previous search
movie_list = {}
--Fetch search box input, set message
title=text:get_text()
local message = "Searching for <a href=\"http://www.themoviedb.org/search?search="
.. title .. "\">" .. title .. "</a> ..."
--Delete unnecessary widgets
if movie_frame ~= nil then
dialog:del_widget(movie_frame)
movie_frame=nil
end
if result_list ~= nil then
dialog:del_widget(result_list)
result_list=nil
dialog:del_widget(open)
open=nil
end
--Create wait label if it hasn't been created yet
if not wait_label then
wait_label = dialog:add_label(message, 1, 2, 3, 1)
else
wait_label:set_text(message)
end
dialog:update()
--Get search results from the TMDb API
local url = "http://api.themoviedb.org/2.1/Movie.search/en/xml/"..APIKEY.."/"..title
local s, msg = vlc.stream(url)
--Streaming error
if not s then
wait_label:set_text("An error occured while searching for <a href=\"http://www.themoviedb.org/search?search="
.. title .. "\">" .. title .. "</a>." )
vlc.msg.warn("[IMDb] " .. msg)
return
end
--Read stream into variable data
local data = ""
local chunk = s:read(CHUNK_SIZE)
repeat
data = data .. chunk
chunk = s:read(CHUNK_SIZE)
until string.len(chunk) == 0
--Pattern to match
local pattern = "<movie>.-<original_name>(.-)</original_name>.-<id>(.-)</id>.-<released>(%d-)%-%d-%-%d-</released>.-</movie>"
--Add results to movie_list
for title, id, year in string.gmatch(data, pattern) do
add_movie( {["title"]=title, ["id"]=id, ["year"]=year} )
end
--There are no matches
if table.getn(movie_list) == 0 then
wait_label:set_text("No matches found for " .. "<a href=\"http://www.themoviedb.org/search?search="
.. title .. "\">" .. title .. "</a>." )
dialog:update()
--If there is only one match, then it is a direct hit
elseif table.getn(movie_list) == 1 then
load_moviepage(movie_list[1])
--If there is more than one match, display results list
else
load_results()
end
end
--Adds a movie to movie_list
--This wrapper function is needed to prevent duplicates
function add_movie(movie)
local add=true
--iterate through movie_list to see if there is a movie with the same ID
for i, m in ipairs(movie_list) do
if movie.id == m.id then
add=false
break
end
end
if add then table.insert(movie_list, movie) end
end
--Display movie information
function load_moviepage(movie)
wait_label:set_text("Loading information for <a href=\"http://www.themoviedb.org/movie/" .. movie.id ..
"\">" .. movie.title .. "</a>...")
dialog:update()
--Remove unnecessary widgets
if result_list ~= nil then
dialog:del_widget(result_list)
result_list=nil
dialog:del_widget(open)
open=nil
end
--Get movie information from the TMDb API
local url = "http://api.themoviedb.org/2.1/Movie.getInfo/en/xml/"..APIKEY.."/" .. movie.id
local s, msg = vlc.stream(url)
--Streaming error
if not s then
wait_label:set_text("An error occured while loading <a href=\"http://www.themoviedb.org/movie/" .. movie.id
.. "\">" .. movie.title .. "</a>." )
vlc.msg.warn("[IMDb] " .. msg)
return
end
--Read stream into variable data
local data = ""
local chunk = s:read(CHUNK_SIZE)
repeat
data = data .. chunk
chunk = s:read(CHUNK_SIZE)
until string.len(chunk) == 0
--Hide wait label
dialog:del_widget(wait_label)
wait_label = nil
--Build html string for movie_frame
local text = "<h2>" .. movie.title .. " (" .. movie.year .. ")</h2>"
--Tagline
if string.find(data, "<tagline>([^<]-)</tagline>") ~= nil then
local tagline = string.match(data, "<tagline>([^<]-)</tagline>")
if string.len(tagline) > 0 then
text = text .. "<b>Tagline</b><br />" .. tagline .. "<br /><br />"
end
end
--Overview
if string.find(data, "<overview>([^<]-)</overview>") ~= nil then
local overview = string.match(data, "<overview>([^<]-)</overview>")
if string.len(overview) > 0 then
text = text .. "<b>Overview</b><br />" .. overview .. "<br /><br />"
end
end
--Director
if string.find(data, "<person name=\"([^\"]-)\" character=\"\" job=\"Director\"") ~= nil then
local director = string.match(data, "<person name=\"([^\"]-)\" character=\"\" job=\"Director\"")
if string.len(director) > 0 then
text = text .. "<b>Director</b><br />" .. director .. "<br /><br />"
end
end
--Screenplay / Story writers
local screenplay_pattern = "<person name=\"([^\"]-)\" character=\"\" job=\"Screenplay\""
if string.find(data, screenplay_pattern) ~= nil then
text = text .. "<b>Screenplay by</b><br />"
for screenplay in string.gmatch(data, screenplay_pattern) do
if string.len(screenplay) > 0 then
text = text .. screenplay .. "<br />"
end
end
text = text .. "<br />"
end
--Genres
if string.find(data, "<category type=\"genre\" name=\"([^\"]-)\"") ~= nil then
text = text .. "<b>Genres</b><br />"
for genre in string.gmatch(data, "<category type=\"genre\" name=\"([^\"]-)\"") do
if string.len(genre) > 0 then
text = text .. genre .. "<br />"
end
end
text = text .. "<br />"
end
--Cast
local actor_pattern = "<person name=\"([^\"]-)\" character=\"([^\"]-)\" job=\"Actor\""
if string.find(data, actor_pattern) ~= nil then
text = text .. "<b>Cast</b><br />"
for actor, role in string.gmatch(data, actor_pattern) do
if string.len(actor) > 0 and string.len(role) > 0 then
text = text .. actor .. " as <i>" .. role .. "</i><br />"
end
end
text = text .. "<br />"
end
--Link to trailer video
if string.find(data, "<trailer>([^<]-)</trailer>") ~= nil then
local trailer = string.match(data, "<trailer>([^<]-)</trailer>")
if string.len(trailer) > 0 then
text = text .. "<b>Trailer</b><br />" .. "<a href=\"" .. trailer .. "\">" .. trailer .. "</a><br /><br />"
end
end
--Link to homepage
if string.find(data, "<homepage>([^<]-)</homepage>") ~= nil then
local homepage = string.match(data, "<homepage>([^<]-)</homepage>")
if string.len(homepage) > 0 then
text = text .. "<b>Homepage</b><br />" .. "<a href=\"" .. homepage .. "\">" .. homepage .. "</a><br /><br />"
end
end
--Link to TMDb page
text = text .. "<b>Source TMDb page:</b><br />"
url = "http://www.themoviedb.org/movie/" .. movie.id
text = text .. "<a href=\"" .. url .. "\">" .. url .. "</a><br />"
movie_frame = dialog:add_html(text, 1, 3, 3, 1)
end
--Display search results
function load_results()
wait_label:set_text(table.getn(movie_list) .. " results for <a href=\"http://www.themoviedb.org/search?search="
.. title .. "\">" .. title .. "</a>." )
result_list = dialog:add_list(1, 3, 3, 1)
open = dialog:add_button("Open", open_movie, 3, 4, 1, 1)
--Add search results to listbox
for i, movie in ipairs(movie_list) do
result_list:add_value(movie.title .. " (" .. movie.year .. ")", i)
end
end
--Open selected movie
function open_movie()
--Get index of select movie
local select = result_list:get_selection()
if not select then return end
local index = nil
for i, v in pairs(select) do
index=i
break
end
--Load movie page
if not index then return end
load_moviepage(movie_list[index])
end
require "simplexml"
function descriptor()
return { title = "TheTVDB" ;
version = "1.0" ;
author = "Seva Deribas" ;
url = 'http://www.thetvdb.com/';
shortdesc = "An open database for television fans.";
description = "Read info about series fetched from TheTVDB database.";
capabilities = { "input-listener" } }
end
function activate()
create_dialog()
end
function deactivate()
end
function close()
vlc.deactivate()
end
function create_dialog()
dlg = vlc.dialog("TVDB")
dlg:add_label("Series name:", 1, 1, 1, 1)
local item = vlc.input.item()
series_name = dlg:add_text_input(item and item:name() or "Input series name here", 2, 1, 1, 1)
dlg:add_button("Search", get_info, 3, 1, 1, 1)
dlg:show()
end
function get_info()
local title_table = {}
local index = 1
local count = 1
local title = series_name:get_text()
if title_list then
dlg:del_widget(title_list)
dlg:del_widget(button_open)
dlg:del_widget(summary_label)
title_list = nil
button_open = nil
end
title_list = dlg:add_list("", 1, 3, 3, 1)
--name = txt:get_text()
if no_results then
dlg:del_widget(no_results)
no_results = nil
end
url = "http://thetvdb.com/api/GetSeries.php?seriesname=" .. title
local waitmsg = 'Searching for <a href="' .. url .. '">' .. title .. "</a> on theTVDB..."
if not waitlbl then
waitlbl = dlg:add_label(waitmsg, 1, 2, 3, 1)
else
waitlbl:set_text(waitmsg)
end
dlg:update()
xml = simplexml.parse_url(url)
--vlc.msg.dbg(xml)
if xml == nil then
no_results = dlg:add_label("The search returned no results (Could be a server error).", 1, 2)
if summary_label then dlg:del_widget(summary_label) end
dlg:show()
return
end
for i, v in pairs(xml.children) do
--vlc.msg.dbg(v.name)
if v.name == "Series" then
title_table[count] = v.children[3].children[1]
count = count + 1
end
end
count = 1
for i, v in pairs(title_table) do
title_list:add_value(v, count)
count = count + 1
end
waitlbl:set_text(count - 1 .. " results found for <a href=\"" .. url .. "\">" .. title .. "</a>.")
button_open = dlg:add_button("Open", show_info, 1, 4, 1, 1)
dlg:show()
end
function show_info()
title = title_list:get_selection()
for i, v in pairs(title) do
selection = v
end
for i, v in pairs(xml.children) do
--vlc.msg.dbg(v.name)
if v.children[3].children[1] == selection then
summary = v.children[5].children[1]
end
end
if summary ~= nil then
row = 4
length = string.len(summary)
w = 1
artist_info = ""
summary_label = dlg:add_html(summary, 2, 3, 1, 1)
else
dlg:add_label("The overview for these series is currently anavailable.")
end
dlg:show()
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment