[vlc-devel] Create AutoSubtitles.lua from chintan9 on github

chintan prajapati chintanbprajapati at gmail.com
Fri May 3 17:15:50 CEST 2013


-- Global variables
dlg = nil
dialog_is_opened = false
dialog_is_hidden = false
update_title_needed = false
website = nil
language = nil
main_text_input = nil
search_button = nil
load_button = nil
subtitles_list = nil
subtitles_result = nil
type_text_input = nil

-- Extension description
function descriptor()
  return {
		title = "AutoSubtitles";
		version = "1";
		author = "jean caffou";
		url = 'http://www.kafol.net';
		description = "";
		shortdesc = "";
		capabilities = { "input-listener" ; "meta-listener" }
	}
end

-- Get clean title from filename
function get_title(str)
    local item = vlc.item or vlc.input.item()
    if not item then
        return ""
    end

    local metas = item:metas()
    if metas["title"] then
        return metas["title"]
    else

        local filename = string.gsub(item:name(), "^(.+)%.%w+$", "%1")
        return trim(filename or item:name())
    end
end

-- Remove leading and trailing spaces
function trim(str)
    if not str then return "" end
    return string.gsub(str, "^%s*(.-)%s*$", "%1")
end

-- Function triggered when the extension is activated
function activate()
	new_dialog("Download subtitles")
	return show_dialog_download()
end

-- Function triggered when the extension is deactivated
function deactivate()
	if dialog_is_opened then
		close()
	else

		reset_variables()

		dlg = nil
	end

	return true
end

-- self explanatory
function reset_variables()
	update_title_needed = false
	website = nil
	language = nil
	main_text_input = nil
	search_button = nil
	load_button = nil
	subtitles_list = nil
	subtitles_result = nil
	type_text_input = nil
end

-- Function triggered when the dialog is closed
function close()
	return true
end

-- Current input changed
function input_changed()
	vlc.msg.dbg("Input is changed")
	update_title()
	click_search()
end

-- Update title in search dialog
function update_title()
	if dialog_is_hidden or not update_title_needed then return true end
	main_text_input:set_text(get_title())
	dlg:update()
	return false
end

function show_dialog_download()
	-- column, row, colspan, rowspan
	dlg:add_label("<right><b>Database: </b></right>", 1, 1, 1, 1)
	website = dlg:add_dropdown(2, 1, 3, 1)

	dlg:add_label("<right><b>Language: </b></right>", 1, 2, 1, 1)
	language = dlg:add_dropdown(2, 2, 3, 1)

	dlg:add_label("<right><b>Search: </b></right>", 1, 3, 1, 1)
	main_text_input = dlg:add_text_input("", 2, 3, 1, 1)
	search_button = dlg:add_button("Search", click_search, 3, 3, 1, 1)
	--dlg:add_button("Hide", hide_dialog, 4, 3, 1, 1)

	for idx, ws in ipairs(websites) do
		website:add_value(ws.title, idx)
	end

	for idx, ws in ipairs(languages) do
		language:add_value(ws.title, idx)
	end

	update_title_needed = true
	update_title()
	click_search()
	dlg:update()
	return true
end

function new_dialog(title)
	if(dlg == nil) then
		dlg = vlc.dialog(title)
	end
end

function hide_dialog()
	dialog_is_hidden = true
	dlg:hide()
end

function click_search()
	local search_term = main_text_input:get_text()
	if(search_term == "") then return false end

	local old_button_name = search_button:get_text()
	search_button:set_text("Wait...")
	if subtitles_list ~= nil then subtitles_list:clear() end
	dlg:update()

	subtitles_result = nil

	local idx = website:get_value()
	local idx2 = language:get_value()
	if idx < 1 or idx2 < 1 then vlc.msg.err("Invalid index in dropdown")
search_button:set_text(old_button_name) return false end

	local ws = websites[idx]
	local lang = languages[idx2]
	local url = ws.urlfunc(search_term,lang.tag)

	-- vlc.msg.info("Url: '" .. url .. "'")
	local stream = vlc.stream(url)
	if stream == nil then vlc.msg.err("The site of subtitles isn't
reachable") search_button:set_text(old_button_name) return false end

	local reading = "blah"
	local xmlpage = ""
	while(reading ~= nil and reading ~= "") do
		reading = stream:read(65653)
		if(reading) then
			xmlpage = xmlpage .. reading
		end

	end
	if xmlpage == "" then search_button:set_text(old_button_name) return false end

	subtitles_result = ws.parsefunc(xmlpage)

	if subtitles_list == nil then
		subtitles_list = dlg:add_list(1, 4, 4, 1)
		load_button = dlg:add_button("Load selected subtitles",
click_load_from_search_button, 1, 5, 4, 1)
	end

	if not subtitles_result then
		subtitles_result = {}
		subtitles_result[1]= { url = "-1" }
		subtitles_list:add_value("Nothing found", 1)
		search_button:set_text(old_button_name)
		dlg:update()
		return false
	end

	for idx, res in ipairs(subtitles_result) do
		if(not res.language or lang.tag == "all" or lang.tag == res.language) then
			subtitles_list:add_value("["..res.language.."] "..res.name, idx)
		end

	end


	search_button:set_text(old_button_name)
	dlg:update()

	load_first_result()

	return true
end

function load_unknown_subtitles(url, language)
	vlc.msg.dbg("Loading "..language.." subtitle: "..url)
	vlc.input.add_subtitle(url)
end

function load_subtitles_in_the_archive(dataBuffer, language)
	local buffer_length = dataBuffer:len()
	local files_found_in_the_compressed_file = 0
	local subtitles_found_in_the_compressed_file = 0
	local endIdx = 1
	local srturl, extension

	-- Find subtitles
	while(endIdx < buffer_length) do
		_, endIdx, srturl, extension =
dataBuffer:find("<location>([^<]+)%.(%a%a%a?)</location>", endIdx)
		if(srturl == nil ) then break end

		--vlc.msg.dbg("File found in the archive: " .. srturl .. extension)
		files_found_in_the_compressed_file = files_found_in_the_compressed_file + 1
		srturl = string.gsub(srturl, "^(%a%a%a)://", "%1://http://")

		if(extension == "ass" or extension == "ssa" or extension == "srt" or
extension == "smi" or extension == "sub" or extension == "rt" or
extension == "txt" or extension == "mpl") then
			subtitles_found_in_the_compressed_file =
subtitles_found_in_the_compressed_file + 1
			vlc.msg.dbg("Loading "..language.." subtitle: "..srturl)
			vlc.input.add_subtitle(srturl.."."..extension)
		end

	end
	vlc.msg.info("Files found in the compressed file:
"..files_found_in_the_compressed_file)
	vlc.msg.info("Subtitles found in the compressed file:
"..subtitles_found_in_the_compressed_file)

	if(subtitles_found_in_the_compressed_file > 0) then return true end

	vlc.msg.warn("No subtitles found in the compressed file")
	return false
end

function parse_archive(url, language)
	if url == "-1" then vlc.msg.dbg("Dummy result") return true end

	local stream = vlc.stream(url)
	if stream == nil then vlc.msg.err("The site of subtitles isn't
reachable") return false end
	stream:addfilter("zip,stream_filter_rar")

	local data = stream:read(2048)
	if(data == nil or data:find("<?xml version", 1, true) ~= 1) then
		vlc.msg.info("Type: RAR or unknown file")
		load_unknown_subtitles(url, language)
	else

		vlc.msg.info("Type: ZIP file")
		local dataBuffer = ""
		while(data ~= nil and data ~= "") do
			vlc.msg.dbg("Buffering...")
			dataBuffer = dataBuffer..data
			data = stream:read(8192)
		end

		load_subtitles_in_the_archive(dataBuffer, language)
	end

	--vlc.msg.dbg("Subtitle data: "..dataBuffer)

	return true
end

function click_load_from_search_button()
	vlc.msg.dbg("Clicked load button from \"Download subtitles\" dialog")
	if(not vlc.input.is_playing()) then
		vlc.msg.warn("You cannot load subtitles if you aren't playing any file")
		return true
	end

	local old_button_name = load_button:get_text()
	load_button:set_text("Wait...")
	dlg:update()

	local selection = subtitles_list:get_selection()
	local index, name

	for index, name in pairs(selection) do
		vlc.msg.dbg("Selected the item "..index.." with the name: "..name)
		vlc.msg.dbg("URL: "..subtitles_result[index].url)

		parse_archive(subtitles_result[index].url,
subtitles_result[index].language) -- ZIP, RAR or unknown file
	end

	load_button:set_text(old_button_name)
	dlg:update()
	return true
end

function load_first_result()
	vlc.msg.dbg("Loading first result")
	if(not vlc.input.is_playing()) then
		vlc.msg.warn("You cannot load subtitles if you aren't playing any file")
		return true
	end

	local old_button_name = load_button:get_text()
	load_button:set_text("Wait...")
	dlg:update()

	parse_archive(subtitles_result[1].url, subtitles_result[1].language)

	load_button:set_text(old_button_name)
	dlg:update()
	return true
end

function click_load_from_url_button()
	vlc.msg.dbg("Clicked load button in \"Load subtitles from url...\" dialog")
	if(not vlc.input.is_playing()) then
		vlc.msg.warn("You cannot load subtitles if you aren't playing any file")
		return true
	end

	local old_button_name = load_button:get_text()
	load_button:set_text("Wait...")
	type_text_input:set_text("")
	dlg:update()

	local url_to_load = main_text_input:get_text()
	if(url_to_load == "") then return false end
	vlc.msg.dbg("URL: "..url_to_load)

	local _, ext_pos, extension = url_to_load:find("%.(%a%a%a?)", -4)

	if(ext_pos == url_to_load:len()) then
		type_text_input:set_text(extension)
		if(extension == "ass" or extension == "ssa" or extension == "srt" or
extension == "smi" or extension == "sub" or extension == "rt" or
extension == "txt" or extension == "mpl") then
			load_button:set_text(old_button_name)
			dlg:update()
			return vlc.input.add_subtitle(url_to_load)
		end

	end


	local result = parse_archive(url_to_load, "")
	if not result then
		vlc.msg.info("Waiting 5 seconds before retry...")
		result = parse_archive(url_to_load, "")
	end

	load_button:set_text(old_button_name)
	dlg:update()
	return result
end



-- XML Parsing
function parseargs(s)
	local arg = {}
	string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
		arg[w] = a
	end)
	return arg
end

function collect(s)
	local stack = {}
	local top = {}
	table.insert(stack, top)
	local ni,c,label,xarg, empty
	local i, j = 1, 1
	while true do
		ni,j,c,label,xarg, empty = string.find(s, "<(%/?)([%w:]+)(.-)(%/?)>", i)
		if not ni then break end
		local text = string.sub(s, i, ni-1)
		if not string.find(text, "^%s*$") then
			table.insert(top, text)
		end

		if empty == "/" then -- empty element tag
			table.insert(top, {label=label, xarg=parseargs(xarg), empty=1})
		elseif c == "" then -- start tag
			top = {label=label, xarg=parseargs(xarg)}
			table.insert(stack, top) -- new level
		else -- end tag
			local toclose = table.remove(stack) -- remove top
			top = stack[#stack]
			if #stack < 1 then
				error("nothing to close with "..label)
			end

			if toclose.label ~= label then
				error("trying to close "..toclose.label.." with "..label)
			end

			table.insert(top, toclose)
		end

		i = j+1
	end

	local text = string.sub(s, i)
	if not string.find(text, "^%s*$") then
		table.insert(stack[#stack], text)
	end

	if #stack > 1 then
		error("unclosed "..stack[stack.n].label)
	end

	return stack[1]
end

function urlOpenSub(search_term,lang)
	-- base = "http://api.opensubtitles.org/en/search/"
	search_term = string.gsub(search_term, "%%", "%%37")
	search_term = string.gsub(search_term, " ", "%%20")
	return "http://kafol.net/code/subtitles/search.php?s=" .. search_term
.. "&l=" .. lang
	-- return base .. "moviename-" .. search_term .. "/simplexml"
	-- http://api.opensubtitles.org/en/search/moviename- .. search_term
.. /simplexml
end

function parseOpenSub(xmltext)
	vlc.msg.dbg("Parsing XML data...")
	local xmltext = string.gsub(xmltext, "<%?xml version=\"1%.0\"
encoding=\"utf-8\"%?>", "")
	local xmldata = collect(xmltext)
	for a,b in pairs(xmldata) do
		if type(b) == "table" then
			if b.label == "search" then
				xmldata = b
				break

			end
		end
	end


	if xmldata == nil then return nil end

	-- Subtitles information data
	local subname = {}
	local sub_movie = {}
	local suburl = {}
	local sublang = {}
	local sub_language = {}
	local subformat = {}
	local subfilenum = {}
	local subnum = 1
	local baseurl = ""

	-- Let's browse iteratively the 'xmldata' tree
	-- OK, the variables' names aren't explicit enough, but just remember a couple
	-- a,b contains the index (a) and the data (b) of the table, which
might also be a table
	for a,b in pairs(xmldata) do
		if type(b) == "table" then
			if b.label == "results" then
				for c,d in pairs(b) do
					if type(d) == "table" then
						if d.label == "subtitle" then
							for e,f in pairs(d) do
								if type(f) == "table" then
									if f.label == "releasename" then
										if f[1] ~= nil then subname[subnum] = f[1]
										else subname[subnum] = "" end
									elseif f.label == "movie" then
										if f[1] ~= nil then sub_movie[subnum] = f[1]
										else sub_movie[subnum] = "" end
									elseif f.label == "download" then
										if f[1] ~= nil then suburl[subnum] = f[1]
										else suburl[subnum] = "" end
									elseif f.label == "iso639" then	-- two letter language code
										if f[1] ~= nil then sublang[subnum] = f[1]
										else sublang[subnum] = "" end
									elseif f.label == "language" then
										if f[1] ~= nil then sub_language[subnum] = f[1]
										else sub_language[subnum] = "" end
									elseif f.label == "format" then
										if f[1] ~= nil then subformat[subnum] = f[1]
										else subformat[subnum] = "" end
									end

								end
							end
							subnum = subnum + 1
						end

					end
				end
			elseif b.label == "base" then
				baseurl = b[1]
			end

		end
	end

	if subnum <= 1 then
		return nil
	end

	ret = {}

	for i = 1,(subnum - 1) do
		fullURL = suburl[i] -- baseurl .. "/" .. suburl[i]
		realName = string.gsub( subname[i], "<..CDATA.", "" )
		realName = string.gsub( realName, "..>", "" )
		if realName == "" then
			realName = string.gsub( sub_movie[i], "<..CDATA.", "" )
			realName = string.gsub( realName, "..>", "" )
		end

		ret[i] = { name = realName,
			   url = fullURL,
			   language = sublang[i],
			   extension = ".zip"
		}

		vlc.msg.dbg("Found subtitle " .. i .. ": ")
		vlc.msg.dbg(realName)
		vlc.msg.dbg(fullURL)
	end

	return ret
end

-- These tables must be after all function definitions
websites = {
	{ title = "Kafol.net",
	  urlfunc = urlOpenSub,
	  parsefunc = parseOpenSub } --[[;
	{ title = "Fake (OS)",
	  urlfunc = url2,
	  parsefunc = parse2 }]]
}

languages = {
	{ title = "English", tag = "en" },
	-- { title = "All", tag = "all" },
	{ title = "Slovenian", tag = "sl" },
	{ title = "French", tag = "fr" }
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20130503/f82f2e63/attachment.html>


More information about the vlc-devel mailing list