diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..667ae92
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+lunit 0.5-1
diff --git a/tests/vlsub_core.lua b/tests/vlsub_core.lua
new file mode 100644
index 0000000..5a5d837
--- /dev/null
+++ b/tests/vlsub_core.lua
@@ -0,0 +1,108 @@
+require "lunit"
+package.path = package.path .. ";../vlsub.lua"
+local vlsub = require("vlsub")
+
+module( "vlsub_core", lunit.testcase, package.seeall)
+
+function test_last_subtitle_time_text_shouldReturnQuestionMark_WhenNoDuration()
+ -- Given
+ lang_mock = {int_last_sub="last sub at"}
+ subtitle_mock = {SubLastTS=nil}
+ -- When
+ local result = vlsub.last_subtitle_time_text(subtitle_mock, lang_mock)
+ -- Then
+ assert_equal("[last sub at ?]", result)
+end
+
+function test_last_subtitle_time_text_shouldReturnQuestionMark_WhenDurationFormatIsWrong()
+ -- Given
+ lang_mock = {int_last_sub="last sub at"}
+ subtitle_mock = {SubLastTS="123456"}
+ -- When
+ local result = vlsub.last_subtitle_time_text(subtitle_mock, lang_mock)
+ -- Then
+ assert_equal("[last sub at ?]", result)
+end
+
+function test_last_subtitle_time_text_shouldReturnDuration_WhenDurationFormatIsRight()
+ -- Given
+ lang_mock = {int_last_sub="last sub at"}
+ subtitle_mock = {SubLastTS="12:34:56"}
+ -- When
+ local result = vlsub.last_subtitle_time_text(subtitle_mock, lang_mock)
+ -- Then
+ assert_equal("[last sub at 12:34:56]", result)
+end
+
+function test_date_string_to_time_shouldReturnTime_FromStringFormatedWithHoursMinutesSeconds()
+ -- When
+ local result = vlsub.date_string_to_time("01:02:03")
+
+ -- Then
+ assert_equal(3723, result)
+end
+
+function test_date_string_to_time_shouldReturnZero_WhenGivenMalformatedString()
+ -- When
+ local result = vlsub.date_string_to_time("01.23azerty")
+
+ -- Then
+ assert_equal(0, result)
+end
+
+function test_order_subs_shouldOrderUnorderedSubs_ByDistanceBetweenLastSpokenLineAndMovieDuration()
+ -- Given
+ local movie_duration = 60
+ local unordered_table = {}
+ local incorrect = {SubLastTS="xxxxx"}
+ local greater = {SubLastTS="00:01:10"}
+ local equals = {SubLastTS="00:01:00"}
+ local lesser = {SubLastTS="00:00:10"}
+ table.insert(unordered_table, greater)
+ table.insert(unordered_table, incorrect)
+ table.insert(unordered_table, equals)
+ table.insert(unordered_table, lesser)
+
+ -- When
+ local result = vlsub.order_by_ascending_distance_between_last_sub_time_and_movie_duration(unordered_table, movie_duration)
+
+ -- Then
+ assert_equal(table_tostring({equals, greater, lesser, incorrect}), table_tostring(result))
+end
+
+-- test-utils
+function table_val_to_str ( v )
+ if "string" == type( v ) then
+ v = string.gsub( v, "\n", "\\n" )
+ if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
+ return "'" .. v .. "'"
+ end
+ return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
+ else
+ return "table" == type( v ) and table_tostring( v ) or
+ tostring( v )
+ end
+end
+
+function table_key_to_str ( k )
+ if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
+ return k
+ else
+ return "[" .. table_val_to_str( k ) .. "]"
+ end
+end
+
+function table_tostring( tbl )
+ local result, done = {}, {}
+ for k, v in ipairs( tbl ) do
+ table.insert( result, table_val_to_str( v ) )
+ done[ k ] = true
+ end
+ for k, v in pairs( tbl ) do
+ if not done[ k ] then
+ table.insert( result,
+ table_key_to_str( k ) .. "=" .. table_val_to_str( v ) )
+ end
+ end
+ return "{" .. table.concat( result, "," ) .. "}"
+end
\ No newline at end of file
diff --git a/tests/vlsub_interface_data.lua b/tests/vlsub_interface_data.lua
new file mode 100644
index 0000000..0faf91b
--- /dev/null
+++ b/tests/vlsub_interface_data.lua
@@ -0,0 +1,44 @@
+require "lunit"
+package.path = package.path .. ";../vlsub.lua"
+local vlsub = require("vlsub")
+
+module( "vlsub_interface_data", lunit.testcase, package.seeall)
+
+function test_movie_length_text_shouldReturnNone_WhenNoMovie()
+ -- Given
+ function item_mock(string)
+ return nil
+ end
+ vlc_mock = {input={item=item_mock}}
+ lang_mock = {int_movie_duration="movie duration"}
+ -- When
+ local result = vlsub.movie_duration_text(vlc_mock, lang_mock)
+ -- Then
+ assert_equal(result, "movie duration : ?")
+end
+
+function test_movie_length_text_shouldReturnNone_WhenMovieHasNone()
+ -- Given
+ function item_mock(string)
+ return {duration=function() return -1 end}
+ end
+ vlc_mock = {input={item=item_mock}}
+ lang_mock = {int_movie_duration="movie duration"}
+ -- When
+ local result = vlsub.movie_duration_text(vlc_mock, lang_mock)
+ -- Then
+ assert_equal(result, "movie duration : ?")
+end
+
+function test_movie_length_text_shouldReturnLength_WhenMovieHasOne()
+ -- Given
+ function item_mock(string)
+ return {duration=function() return 70 end}
+ end
+ vlc_mock = {input={item=item_mock}}
+ lang_mock = {int_movie_duration="movie duration"}
+ -- When
+ local result = vlsub.movie_duration_text(vlc_mock, lang_mock)
+ -- Then
+ assert_equal(result, "movie duration : 00:01:10")
+end
diff --git a/vlsub.lua b/vlsub.lua
index a4c2a84..c41f9a6 100644
--- a/vlsub.lua
+++ b/vlsub.lua
@@ -3,7 +3,7 @@ VLSub Extension for VLC media player 1.1 and 2.0
Copyright 2013 Guillaume Le Maout
Authors: Guillaume Le Maout
-Contact:
+Contact:
http://addons.videolan.org/messages/?action=newmessage&username=exebetche
Bug report: http://addons.videolan.org/content/show.php/?content=148752
@@ -23,15 +23,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
--]]
- --[[ Global var ]]--
+ --[[ Global var ]]--
-- You can set here your default language by replacing nil with
--- your language code (see below).Example:
--- language = "fre",
--- language = "ger",
+-- your language code (see below).Example:
+-- language = "fre",
+-- language = "ger",
-- language = "eng",
-- ...
+local export = {}
local options = {
language = nil,
downloadBehaviour = 'save',
@@ -42,8 +43,8 @@ local options = {
intLang = 'eng',
translations_avail = {
eng = 'English',
- cze = 'Czech',
- dan = 'Danish',
+ cze = 'Czech',
+ dan = 'Danish',
dut = 'Nederlands',
fre = 'Français',
ell = 'Greek',
@@ -92,70 +93,71 @@ local options = {
int_os_username = 'Username',
int_os_password = 'Password',
int_help_mess =[[
- Download subtitles from
+ Download subtitles from
opensubtitles.org
and display them while watching a video.
Usage:
- Start your video. If you use Vlsub witout playing a video
- you will get a link to download the subtitles in your browser
+ Start your video. If you use Vlsub witout playing a video
+ you will get a link to download the subtitles in your browser
but the subtitles won't be saved and loaded automatically.
- Choose the language for your subtitles and click on the
- button corresponding to one of the two research methods
+ Choose the language for your subtitles and click on the
+ button corresponding to one of the two research methods
provided by VLSub:
Method 1: Search by hash
- It is recommended to try this method first, because it
- performs a research based on the video file print, so you
+ It is recommended to try this method first, because it
+ performs a research based on the video file print, so you
can find subtitles synchronized with your video.
Method 2: Search by name
- If you have no luck with the first method, just check the
- title is correct before clicking. If you search subtitles
- for a series, you can also provide a season and episode
+ If you have no luck with the first method, just check the
+ title is correct before clicking. If you search subtitles
+ for a series, you can also provide a season and episode
number.
Downloading Subtitles
Select one subtitle in the list and click on 'Download'.
- It will be put in the same directory that your video, with
+ It will be put in the same directory that your video, with
the same name (different extension)
- so VLC will load them automatically the next time you'll
+ so VLC will load them automatically the next time you'll
start the video.
- /!\\ Beware : Existing subtitles are overwritten
- without asking confirmation, so put them elsewhere if
+ /!\\ Beware : Existing subtitles are overwritten
+ without asking confirmation, so put them elsewhere if
they're important.
- Find more VLC extensions at
+ Find more VLC extensions at
addons.videolan.org.
]],
int_no_support_mess = [[
- VLSub is not working with Vlc 2.1.x on
+ VLSub is not working with Vlc 2.1.x on
any platform
- because the lua "net" module needed to interact
- with opensubtitles has been
+ because the lua "net" module needed to interact
+ with opensubtitles has been
removed in this release for the extensions.
Works with Vlc 2.2 on mac and linux.
- On windows you have to install an older version
+ On windows you have to install an older version
of Vlc (2.0.8 for example)
to use Vlsub:
-
http://download.videolan.org/pub/videolan/vlc/2.0.8/
]],
-
+ int_movie_duration = 'Movie duration',
+ int_last_sub = 'Last sub at',
action_login = 'Logging in',
action_logout = 'Logging out',
action_noop = 'Checking session',
action_search = 'Searching subtitles',
action_hash = 'Calculating movie hash',
-
+
mess_success = 'Success',
mess_error = 'Error',
mess_no_response = 'Server not responding',
@@ -321,12 +323,12 @@ local lang_os_to_iso = {
local dlg = nil
local input_table = {} -- General widget id reference
-local select_conf = {} -- Drop down widget / option table association
+local select_conf = {} -- Drop down widget / option table association
--[[ VLC extension stuff ]]--
function descriptor()
- return {
+ return {
title = "VLsub 0.9.13",
version = "0.9.13",
author = "exebetche",
@@ -339,17 +341,17 @@ end
function activate()
vlc.msg.dbg("[VLsub] Welcome")
-
- if not check_config() then
+
+ if not check_config() then
vlc.msg.err("[VLsub] Unsupported VLC version")
- return false
+ return false
end
-
+
if vlc.input.item() then
openSub.getFileInfo()
openSub.getMovieInfo()
end
-
+
show_main()
end
@@ -360,18 +362,18 @@ end
function deactivate()
vlc.msg.dbg("[VLsub] Bye bye!")
if dlg then
- dlg:hide()
+ dlg:hide()
end
-
+
if openSub.session.token and openSub.session.token ~= "" then
openSub.request("LogOut")
end
end
function menu()
- return {
- lang.int_research,
- lang.int_config,
+ return {
+ lang.int_research,
+ lang.int_config,
lang.int_help
}
end
@@ -388,52 +390,65 @@ end
--[[ Interface data ]]--
+function movie_duration_text(vlc_global, lang_global)
+ lang_global = lang_global or lang
+ vlc_global = vlc_global or vlc
+ local movie = vlc_global.input.item()
+ local duration = "?"
+ if movie and movie:duration() >= 0 then
+ duration = os.date("!%X",movie:duration())
+ end
+ return string.format("%s : %s", lang_global["int_movie_duration"], duration)
+end
+export.movie_duration_text = movie_duration_text
+
function interface_main()
dlg:add_label(lang["int_default_lang"]..':', 1, 1, 1, 1)
input_table['language'] = dlg:add_dropdown(2, 1, 2, 1)
- dlg:add_button(lang["int_search_hash"],
+ dlg:add_button(lang["int_search_hash"],
searchHash, 4, 1, 1, 1)
-
- dlg:add_label(lang["int_title"]..':', 1, 2, 1, 1)
+
+ dlg:add_label(lang["int_title"]..':', 1, 2, 1, 1)
input_table['title'] = dlg:add_text_input(
- openSub.movie.title or "", 2, 2, 2, 1)
- dlg:add_button(lang["int_search_name"],
- searchIMBD, 4, 2, 1, 1)
- dlg:add_label(lang["int_season"]..':', 1, 3, 1, 1)
+ openSub.movie.title or "", 2, 2, 2, 1)
+ dlg:add_button(lang["int_search_name"],
+ searchIMBD, 4, 2, 1, 1)
+ dlg:add_label(lang["int_season"]..':', 1, 3, 1, 1)
input_table['seasonNumber'] = dlg:add_text_input(
- openSub.movie.seasonNumber or "", 2, 3, 2, 1)
+ openSub.movie.seasonNumber or "", 2, 3, 2, 1)
dlg:add_label(lang["int_episode"]..':', 1, 4, 1, 1)
input_table['episodeNumber'] = dlg:add_text_input(
- openSub.movie.episodeNumber or "", 2, 4, 2, 1)
- input_table['mainlist'] = dlg:add_list(1, 5, 4, 1)
+ openSub.movie.episodeNumber or "", 2, 4, 2, 1)
+ input_table['movieDuration'] = dlg:add_label(movie_duration_text())
+ input_table['mainlist'] = dlg:add_list( 1, 6, 4, 1)
input_table['message'] = nil
- input_table['message'] = dlg:add_label(' ', 1, 6, 4, 1)
+ input_table['message'] = dlg:add_label(' ', 1, 7, 4, 1)
dlg:add_button(
- lang["int_show_help"], show_help, 1, 7, 1, 1)
+ lang["int_show_help"], show_help, 1, 8, 1, 1)
dlg:add_button(
- ' '..lang["int_show_conf"]..' ', show_conf, 2, 7, 1, 1)
+ ' '..lang["int_show_conf"]..' ', show_conf, 2, 8, 1, 1)
dlg:add_button(
- lang["int_dowload_sel"], download_subtitles, 3, 7, 1, 1)
+ lang["int_dowload_sel"], download_subtitles, 3, 8, 1, 1)
dlg:add_button(
- lang["int_close"], close, 4, 7, 1, 1)
-
+ lang["int_close"], deactivate, 4, 8, 1, 1)
+
assoc_select_conf(
'language',
'language',
- openSub.conf.languages,
- 2,
+ openSub.conf.languages,
+ 2,
lang["int_all"])
-
+
display_subtitles()
end
function set_interface_main()
-- Update movie title and co. if video input change
if not type(input_table['title']) == 'userdata' then return false end
-
+
openSub.getFileInfo()
openSub.getMovieInfo()
-
+
input_table['title']:set_text(
openSub.movie.title or "")
input_table['episodeNumber']:set_text(
@@ -448,10 +463,10 @@ function interface_config()
input_table['intLangBut'] = dlg:add_button(
lang["int_search_transl"],
get_available_translations, 2, 1, 1, 1)
- input_table['intLang'] = dlg:add_dropdown(3, 1, 1, 1)
+ input_table['intLang'] = dlg:add_dropdown(3, 1, 1, 1)
dlg:add_label(
lang["int_default_lang"]..':', 1, 2, 2, 1)
- input_table['default_language'] = dlg:add_dropdown(3, 2, 1, 1)
+ input_table['default_language'] = dlg:add_dropdown(3, 2, 1, 1)
dlg:add_label(
lang["int_dowload_behav"]..':', 1, 3, 2, 1)
input_table['downloadBehaviour'] = dlg:add_dropdown(3, 3, 1, 1)
@@ -461,7 +476,7 @@ function interface_config()
dlg:add_label(
lang["int_remove_tag"]..':', 1, 5, 0, 1)
input_table['removeTag'] = dlg:add_dropdown(3, 5, 1, 1)
-
+
if openSub.conf.dirPath then
if openSub.conf.os == "win" then
dlg:add_label(
@@ -476,31 +491,31 @@ function interface_config()
dlg :add_label(
lang["int_vlsub_work_dir"], 1, 6, 2, 1)
end
-
+
input_table['dir_path'] = dlg:add_text_input(
openSub.conf.dirPath, 2, 6, 2, 1)
-
+
dlg:add_label(
lang["int_os_username"]..':', 1, 7, 0, 1)
input_table['os_username'] = dlg:add_text_input(
- type(openSub.option.os_username) == "string"
+ type(openSub.option.os_username) == "string"
and openSub.option.os_username or "", 2, 7, 2, 1)
dlg:add_label(
lang["int_os_password"]..':', 1, 8, 0, 1)
input_table['os_password'] = dlg:add_text_input(
- type(openSub.option.os_password) == "string"
+ type(openSub.option.os_password) == "string"
and openSub.option.os_password or "", 2, 8, 2, 1)
-
+
input_table['message'] = nil
input_table['message'] = dlg:add_label(' ', 1, 9, 3, 1)
-
+
dlg:add_button(
lang["int_cancel"],
show_main, 2, 10, 1, 1)
dlg:add_button(
lang["int_save"],
apply_config, 3, 10, 1, 1)
-
+
input_table['langExt']:add_value(
lang["int_bool_"..tostring(openSub.option.langExt)], 1)
input_table['langExt']:add_value(
@@ -509,7 +524,7 @@ function interface_config()
lang["int_bool_"..tostring(openSub.option.removeTag)], 1)
input_table['removeTag']:add_value(
lang["int_bool_"..tostring(not openSub.option.removeTag)], 2)
-
+
assoc_select_conf(
'intLang',
'intLang',
@@ -530,7 +545,7 @@ end
function interface_help()
local help_html = lang["int_help_mess"]
-
+
input_table['help'] = dlg:add_html(
help_html, 1, 1, 4, 1)
dlg:add_label(
@@ -541,7 +556,7 @@ end
function interface_no_support()
local no_support_html = lang["int_no_support_mess"]
-
+
input_table['no_support'] = dlg:add_html(
no_support_html, 1, 1, 4, 1)
dlg:add_label(
@@ -565,8 +580,8 @@ function trigger_menu(dlg_id)
openSub.conf.useragent..': '..lang["int_help"])
interface_help()
end
- collectgarbage() --~ !important
-end
+ collectgarbage() --~ !important
+end
function show_main()
trigger_menu(1)
@@ -583,15 +598,15 @@ end
function close_dlg()
vlc.msg.dbg("[VLSub] Closing dialog")
- if dlg ~= nil then
+ if dlg ~= nil then
--~ dlg:delete() -- Throw an error
- dlg:hide()
+ dlg:hide()
end
-
+
dlg = nil
input_table = nil
input_table = {}
- collectgarbage() --~ !important
+ collectgarbage() --~ !important
end
--[[ Drop down / config association]]--
@@ -609,18 +624,18 @@ function assoc_select_conf(select_id, option, conf, ind, default)
end
function set_default_option(select_id)
--- Put the selected option of a list in first place of the associated table
+-- Put the selected option of a list in first place of the associated table
local opt = select_conf[select_id].opt
local cfg = select_conf[select_id].cf
local ind = select_conf[select_id].ind
if openSub.option[opt] then
- table.sort(cfg, function(a, b)
+ table.sort(cfg, function(a, b)
if a[1] == openSub.option[opt] then
return true
elseif b[1] == openSub.option[opt] then
return false
else
- return a[ind] < b[ind]
+ return a[ind] < b[ind]
end
end)
end
@@ -633,11 +648,11 @@ function display_select(select_id)
local option = openSub.option[opt]
local default = select_conf[select_id].dflt
local default_isset = false
-
- if not default then
+
+ if not default then
default_isset = true
end
-
+
for k, l in ipairs(conf) do
if default_isset then
input_table[select_id]:add_value(l[2], k)
@@ -657,19 +672,19 @@ end
--[[ Config & interface localization]]--
function check_config()
- -- Make a copy of english translation to use it as default
+ -- Make a copy of english translation to use it as default
-- in case some element aren't translated in other translations
eng_translation = {}
for k, v in pairs(openSub.option.translation) do
eng_translation[k] = v
end
-
+
-- Get available translation full name from code
trsl_names = {}
for i, lg in ipairs(languages) do
trsl_names[lg[1]] = lg[2]
end
-
+
if is_window_path(vlc.config.datadir()) then
openSub.conf.os = "win"
slash = "\\"
@@ -677,17 +692,17 @@ function check_config()
openSub.conf.os = "lin"
slash = "/"
end
-
+
local path_generic = {"lua", "extensions", "userdata", "vlsub"}
local dirPath = slash..table.concat(path_generic, slash)
local filePath = slash.."vlsub_conf.xml"
local config_saved = false
sub_dir = slash.."vlsub_subtitles"
-
+
-- Check if config file path is stored in vlc config
local other_dirs = {}
-
- for path in
+
+ for path in
vlc.config.get("sub-autodetect-path"):gmatch("[^,]+") do
if path:match(".*"..sub_dir.."$") then
openSub.conf.dirPath = path:gsub(
@@ -696,10 +711,10 @@ function check_config()
end
table.insert(other_dirs, path)
end
-
+
-- if not stored in vlc config
- -- try to find a suitable config file path
-
+ -- try to find a suitable config file path
+
if openSub.conf.dirPath then
if not is_dir(openSub.conf.dirPath) and
(openSub.conf.os == "lin" or
@@ -709,7 +724,7 @@ function check_config()
else
local userdatadir = vlc.config.userdatadir()
local datadir = vlc.config.datadir()
-
+
-- check if the config already exist
if file_exist(userdatadir..dirPath..filePath) then
-- in vlc.config.userdatadir()
@@ -723,15 +738,15 @@ function check_config()
-- if not found determine an accessible path
local extension_path = slash..path_generic[1]
..slash..path_generic[2]
-
+
-- use the same folder as the extension if accessible
- if is_dir(userdatadir..extension_path)
+ if is_dir(userdatadir..extension_path)
and file_touch(userdatadir..dirPath..filePath) then
openSub.conf.dirPath = userdatadir..dirPath
elseif file_touch(datadir..dirPath..filePath) then
openSub.conf.dirPath = datadir..dirPath
end
-
+
-- try to create working dir in user folder
if not openSub.conf.dirPath
and is_dir(userdatadir) then
@@ -743,8 +758,8 @@ function check_config()
openSub.conf.dirPath = userdatadir..dirPath
end
end
-
- -- try to create working dir in vlc folder
+
+ -- try to create working dir in vlc folder
if not openSub.conf.dirPath and
is_dir(datadir) then
if not is_dir(datadir..dirPath) then
@@ -756,15 +771,15 @@ function check_config()
end
end
end
-
+
if openSub.conf.dirPath then
vlc.msg.dbg("[VLSub] Working directory: " ..
(openSub.conf.dirPath or "not found"))
-
- openSub.conf.filePath = openSub.conf.dirPath..filePath
+
+ openSub.conf.filePath = openSub.conf.dirPath..filePath
openSub.conf.localePath = openSub.conf.dirPath..slash.."locale"
-
- if config_saved
+
+ if config_saved
and file_exist(openSub.conf.filePath) then
vlc.msg.dbg(
"[VLSub] Loading config file: "..openSub.conf.filePath)
@@ -777,20 +792,20 @@ function check_config()
vlc.msg.dbg("[VLSub] Unable to save config")
end
end
-
- -- Check presence of a translation file
+
+ -- Check presence of a translation file
-- in "%vlsub_directory%/locale"
-- Add translation files to available translation list
local file_list = list_dir(openSub.conf.localePath)
local translations_avail = openSub.conf.translations_avail
-
+
if file_list then
for i, file_name in ipairs(file_list) do
local lg = string.gsub(
file_name,
"^(%w%w%w).xml$",
"%1")
- if lg
+ if lg
and not openSub.option.translations_avail[lg] then
table.insert(translations_avail, {
lg,
@@ -799,9 +814,9 @@ function check_config()
end
end
end
-
+
-- Load selected translation from file
- if openSub.option.intLang ~= "eng"
+ if openSub.option.intLang ~= "eng"
and not openSub.conf.translated
then
local transl_file_path = openSub.conf.localePath..
@@ -817,10 +832,10 @@ function check_config()
vlc.msg.dbg("[VLSub] Unable to find a suitable path"..
"to save config, please set it manually")
end
-
+
lang = nil
lang = options.translation -- just a short cut
-
+
if not vlc.net or not vlc.net.poll then
dlg = vlc.dialog(
openSub.conf.useragent..': '..lang["mess_error"])
@@ -828,16 +843,16 @@ function check_config()
dlg:show()
return false
end
-
+
SetDownloadBehaviours()
if not openSub.conf.dirPath then
setError(lang["mess_err_conf_access"])
end
-
- -- Set table list of available translations from assoc. array
+
+ -- Set table list of available translations from assoc. array
-- so it is sortable
-
- for k, l in pairs(openSub.option.translations_avail) do
+
+ for k, l in pairs(openSub.option.translations_avail) do
if k == openSub.option.int_research then
table.insert(openSub.conf.translations_avail, 1, {k, l})
else
@@ -856,7 +871,7 @@ function load_config()
tmpFile:flush()
tmpFile:close()
local option = parse_xml(resp)
-
+
for key, value in pairs(option) do
if type(value) == "table" then
if key == "translation" then
@@ -887,8 +902,8 @@ function load_transl(path)
tmpFile:flush()
tmpFile:close()
openSub.option.translation = nil
-
- openSub.option.translation = parse_xml(resp)
+
+ openSub.option.translation = parse_xml(resp)
collectgarbage()
end
@@ -902,9 +917,9 @@ function apply_translation()
end
function getenv_lang()
--- Retrieve the user OS language
+-- Retrieve the user OS language
local os_lang = os.getenv("LANG")
-
+
if os_lang then -- unix, mac
os_lang = string.sub(os_lang, 0, 2)
if type(lang_os_to_iso[os_lang]) then
@@ -918,7 +933,7 @@ function getenv_lang()
if v[2] == lang_w then
openSub.option.language = v[1]
end
- end
+ end
end
end
@@ -928,8 +943,8 @@ function apply_config()
local sel_val
local opt
local sel_cf
-
- if lg_sel and lg_sel ~= 1
+
+ if lg_sel and lg_sel ~= 1
and openSub.conf.translations_avail[lg_sel] then
local lg = openSub.conf.translations_avail[lg_sel][1]
if not set_translation(lg) then
@@ -938,48 +953,48 @@ function apply_config()
end
SetDownloadBehaviours()
end
-
+
for select_id, v in pairs(select_conf) do
- if input_table[select_id]
+ if input_table[select_id]
and select_conf[select_id] then
sel_val = input_table[select_id]:get_value()
sel_cf = select_conf[select_id]
opt = sel_cf.opt
-
+
if sel_val == 0 then
openSub.option[opt] = nil
else
openSub.option[opt] = sel_cf.cf[sel_val][1]
end
-
+
set_default_option(select_id)
end
end
-
-
+
+
openSub.option.os_username = input_table['os_username']:get_text()
openSub.option.os_password = input_table['os_password']:get_text()
-
+
if input_table["langExt"]:get_value() == 2 then
openSub.option.langExt = not openSub.option.langExt
end
-
+
if input_table["removeTag"]:get_value() == 2 then
openSub.option.removeTag = not openSub.option.removeTag
end
-
+
-- Set a custom working directory
local dir_path = input_table['dir_path']:get_text()
local dir_path_err = false
if trim(dir_path) == "" then dir_path = nil end
-
+
if dir_path ~= openSub.conf.dirPath then
- if openSub.conf.os == "lin"
- or is_win_safe(dir_path)
+ if openSub.conf.os == "lin"
+ or is_win_safe(dir_path)
or not dir_path then
local other_dirs = {}
-
- for path in
+
+ for path in
vlc.config.get(
"sub-autodetect-path"):gmatch("[^,]+"
) do
@@ -990,13 +1005,13 @@ function apply_config()
end
openSub.conf.dirPath = dir_path
if dir_path then
- table.insert(other_dirs,
+ table.insert(other_dirs,
string.gsub(dir_path, "^(.-)[\\/]?$", "%1")..sub_dir)
-
+
if not is_dir(dir_path) then
mkdir_p(dir_path)
end
-
+
openSub.conf.filePath = openSub.conf.dirPath..
slash.."vlsub_conf.xml"
openSub.conf.localePath = openSub.conf.dirPath..
@@ -1020,7 +1035,7 @@ function apply_config()
"")
end
end
-
+
if openSub.conf.dirPath and
not dir_path_err then
local config_saved = save_config()
@@ -1034,13 +1049,13 @@ function apply_config()
end
function save_config()
--- Dump local config into config file
+-- Dump local config into config file
if openSub.conf.dirPath
and openSub.conf.filePath then
vlc.msg.dbg(
"[VLSub] Saving config file: "..
openSub.conf.filePath)
-
+
if file_touch(openSub.conf.filePath) then
local tmpFile = assert(
io.open(openSub.conf.filePath, "wb"))
@@ -1063,8 +1078,8 @@ function save_config()
end
function SetDownloadBehaviours()
- openSub.conf.downloadBehaviours = nil
- openSub.conf.downloadBehaviours = {
+ openSub.conf.downloadBehaviours = nil
+ openSub.conf.downloadBehaviours = {
{'save', lang["int_dowload_save"]},
{'manual', lang["int_dowload_manual"]}
}
@@ -1072,17 +1087,17 @@ end
function get_available_translations()
-- Get all available translation files from the internet
--- (drop previous direct download from github repo
+-- (drop previous direct download from github repo
-- causing error with github https CA certficate on OS X an XP)
-- https://github.com/exebetche/vlsub/tree/master/locale
-
+
local translations_url = "http://addons.videolan.org/CONTENT/"..
"content-files/148752-vlsub_translations.xml"
-
- if input_table['intLangBut']:get_text() == lang["int_search_transl"]
+
+ if input_table['intLangBut']:get_text() == lang["int_search_transl"]
then
openSub.actionLabel = lang["int_searching_transl"]
-
+
local translations_content = get(translations_url)
if not translations_content then
collectgarbage()
@@ -1091,9 +1106,9 @@ function get_available_translations()
local translations_avail = openSub.option.translations_avail
all_trsl = parse_xml(translations_content)
local lg, trsl
-
+
for lg, trsl in pairs(all_trsl) do
- if lg ~= options.intLang[1]
+ if lg ~= options.intLang[1]
and not translations_avail[lg] then
translations_avail[lg] = trsl_names[lg] or ""
table.insert(openSub.conf.translations_avail, {
@@ -1105,7 +1120,7 @@ function get_available_translations()
#openSub.conf.translations_avail)
end
end
-
+
setMessage(success_tag(lang["mess_complete"]))
collectgarbage()
end
@@ -1115,14 +1130,14 @@ end
function set_translation(lg)
openSub.option.translation = nil
openSub.option.translation = {}
-
+
if lg == 'eng' then
for k, v in pairs(eng_translation) do
openSub.option.translation[k] = v
end
else
-- If translation file exists in /locale directory load it
- if openSub.conf.localePath
+ if openSub.conf.localePath
and file_exist(openSub.conf.localePath..
slash..lg..".xml") then
local transl_file_path = openSub.conf.localePath..
@@ -1147,12 +1162,12 @@ function set_translation(lg)
all_trsl = nil
end
end
-
+
lang = nil
lang = openSub.option.translation
collectgarbage()
return true
-end
+end
--[[ Core ]]--
@@ -1198,24 +1213,24 @@ openSub = {
local params = openSub.methods[methodName].params()
local reqTable = openSub.getMethodBase(methodName, params)
local request = ""..dump_xml(reqTable)
- local host, path = parse_url(openSub.conf.url)
+ local host, path = parse_url(openSub.conf.url)
local header = {
- "POST "..path.." HTTP/1.1",
- "Host: "..host,
- "User-Agent: "..openSub.conf.userAgentHTTP,
- "Content-Type: text/xml",
+ "POST "..path.." HTTP/1.1",
+ "Host: "..host,
+ "User-Agent: "..openSub.conf.userAgentHTTP,
+ "Content-Type: text/xml",
"Content-Length: "..string.len(request),
"",
""
}
request = table.concat(header, "\r\n")..request
-
+
local response
local status, responseStr = http_req(host, 80, request)
-
- if status == 200 then
+
+ if status == 200 then
response = parse_xmlrpc(responseStr)
-
+
if response then
if response.status == "200 OK" then
return openSub.methods[methodName]
@@ -1241,22 +1256,22 @@ openSub = {
openSub.request(methodName)
end
return false
- elseif status == 503 then
+ elseif status == 503 then
setError("Server overloaded, please retry later")
return false
end
-
+
end,
getMethodBase = function(methodName, param)
if openSub.methods[methodName].methodName then
methodName = openSub.methods[methodName].methodName
end
-
+
local request = {
methodCall={
methodName=methodName,
params={ param=param }}}
-
+
return request
end,
methods = {
@@ -1267,7 +1282,7 @@ openSub = {
{ value={ string=openSub.option.os_username } },
{ value={ string=openSub.option.os_password } },
{ value={ string=openSub.movie.sublanguageid } },
- { value={ string=openSub.conf.useragent } }
+ { value={ string=openSub.conf.useragent } }
}
end,
callback = function(resp)
@@ -1280,7 +1295,7 @@ openSub = {
params = function()
openSub.actionLabel = lang["action_logout"]
return {
- { value={ string=openSub.session.token } }
+ { value={ string=openSub.session.token } }
}
end,
callback = function()
@@ -1291,7 +1306,7 @@ openSub = {
params = function()
openSub.actionLabel = lang["action_noop"]
return {
- { value={ string=openSub.session.token } }
+ { value={ string=openSub.session.token } }
}
end,
callback = function(resp)
@@ -1304,7 +1319,7 @@ openSub = {
openSub.actionLabel = lang["action_search"]
setMessage(openSub.actionLabel..": "..
progressBarContent(0))
-
+
return {
{ value={ string=openSub.session.token } },
{ value={
@@ -1313,13 +1328,13 @@ openSub = {
value={
struct={
member={
- { name="sublanguageid", value={
- string=openSub.movie.sublanguageid }
+ { name="sublanguageid", value={
+ string=openSub.movie.sublanguageid }
},
- { name="moviehash", value={
+ { name="moviehash", value={
string=openSub.file.hash } },
- { name="moviebytesize", value={
- double=openSub.file.bytesize } }
+ { name="moviebytesize", value={
+ double=openSub.file.bytesize } }
}}}}}}}
}
end,
@@ -1333,24 +1348,24 @@ openSub = {
openSub.actionLabel = lang["action_search"]
setMessage(openSub.actionLabel..": "..
progressBarContent(0))
-
+
local member = {
- { name="sublanguageid", value={
+ { name="sublanguageid", value={
string=openSub.movie.sublanguageid } },
- { name="query", value={
+ { name="query", value={
string=openSub.movie.title } } }
-
-
+
+
if openSub.movie.seasonNumber ~= nil then
- table.insert(member, { name="season", value={
+ table.insert(member, { name="season", value={
string=openSub.movie.seasonNumber } })
- end
-
+ end
+
if openSub.movie.episodeNumber ~= nil then
- table.insert(member, { name="episode", value={
+ table.insert(member, { name="episode", value={
string=openSub.movie.episodeNumber } })
- end
-
+ end
+
return {
{ value={ string=openSub.session.token } },
{ value={
@@ -1372,13 +1387,13 @@ openSub = {
openSub.actionLabel = lang["action_search"]
setMessage(openSub.actionLabel..": "..
progressBarContent(0))
-
+
local member = {
- { name="sublanguageid", value={
+ { name="sublanguageid", value={
string=openSub.movie.sublanguageid } },
- { name="tag", value={
+ { name="tag", value={
string=openSub.file.completeName } } }
-
+
return {
{ value={ string=openSub.session.token } },
{ value={
@@ -1415,12 +1430,12 @@ openSub = {
file.uri = item:uri()
file.protocol = parsed_uri["protocol"]
file.path = parsed_uri["path"]
-
+
-- Corrections
-
+
-- For windows
file.path = string.match(file.path, "^/(%a:/.+)$") or file.path
-
+
-- For file in archive
local archive_path, name_in_archive = string.match(
file.path, '^([^!]+)!/([^!/]*)$')
@@ -1442,26 +1457,26 @@ openSub = {
file.dir, file.completeName = string.match(
file.path,
'^(.+/)([^/]*)$')
-
+
local file_stat = vlc.net.stat(file.path)
- if file_stat
+ if file_stat
then
file.stat = file_stat
end
-
+
file.is_archive = false
end
-
+
file.name, file.ext = string.match(
file.completeName,
'^([^/]-)%.?([^%.]*)$')
-
+
if file.ext == "part" then
file.name, file.ext = string.match(
file.name,
'^([^/]+)%.([^%.]+)$')
end
-
+
file.hasInput = true;
file.cleanName = string.gsub(
file.name,
@@ -1476,9 +1491,9 @@ openSub = {
openSub.movie.title = ""
openSub.movie.seasonNumber = ""
openSub.movie.episodeNumber = ""
- return false
+ return false
end
-
+
local showName, seasonNumber, episodeNumber = string.match(
openSub.file.cleanName,
"(.+)[sS](%d?%d)[eE](%d%d).*")
@@ -1488,7 +1503,7 @@ openSub = {
openSub.file.cleanName,
"(.-)(%d?%d)[xX](%d%d).*")
end
-
+
if showName then
openSub.movie.title = showName
openSub.movie.seasonNumber = seasonNumber
@@ -1505,37 +1520,37 @@ openSub = {
openSub.actionLabel = lang["action_hash"]
setMessage(openSub.actionLabel..": "..
progressBarContent(0))
-
+
local item = openSub.getInputItem()
-
+
if not item then
setError(lang["mess_no_input"])
return false
end
-
+
openSub.getFileInfo()
-
+
if not openSub.file.path then
setError(lang["mess_not_found"])
return false
end
-
+
local data_start = ""
local data_end = ""
local size
local chunk_size = 65536
-
+
-- Get data for hash calculation
if openSub.file.is_archive then
vlc.msg.dbg("[VLSub] Read hash data from stream")
-
+
local file = vlc.stream(openSub.file.uri)
local dataTmp1 = ""
local dataTmp2 = ""
size = chunk_size
-
+
data_start = file:read(chunk_size)
-
+
while data_end do
size = size + string.len(data_end)
dataTmp1 = dataTmp2
@@ -1544,31 +1559,31 @@ openSub = {
collectgarbage()
end
data_end = string.sub((dataTmp1..dataTmp2), -chunk_size)
- elseif not file_exist(openSub.file.path)
+ elseif not file_exist(openSub.file.path)
and openSub.file.stat then
vlc.msg.dbg("[VLSub] Read hash data from stream")
-
+
local file = vlc.stream(openSub.file.uri)
-
+
if not file then
vlc.msg.dbg("[VLSub] No stream")
return false
end
-
+
size = openSub.file.stat.size
local decal = size%chunk_size
-
+
data_start = file:read(chunk_size)
-
- -- "Seek" to the end
+
+ -- "Seek" to the end
file:read(decal)
-
+
for i = 1, math.floor(((size-decal)/chunk_size))-2 do
file:read(chunk_size)
end
-
+
data_end = file:read(chunk_size)
-
+
file = nil
else
vlc.msg.dbg("[VLSub] Read hash data from file")
@@ -1577,13 +1592,13 @@ openSub = {
vlc.msg.dbg("[VLSub] No stream")
return false
end
-
+
data_start = file:read(chunk_size)
size = file:seek("end", -chunk_size) + chunk_size
data_end = file:read(chunk_size)
file = nil
end
-
+
-- Hash calculation
local lo = size
local hi = 0
@@ -1591,24 +1606,24 @@ openSub = {
local hash_data = data_start..data_end
local max_size = 4294967296
local overflow
-
+
for i = 1, #hash_data, 8 do
a,b,c,d,e,f,g,h = hash_data:byte(i,i+7)
lo = lo + a + b*256 + c*65536 + d*16777216
hi = hi + e + f*256 + g*65536 + h*16777216
-
+
if lo > max_size then
overflow = math.floor(lo/max_size)
lo = lo-(overflow*max_size)
hi = hi+overflow
end
-
+
if hi > max_size then
overflow = math.floor(hi/max_size)
hi = hi-(overflow*max_size)
end
end
-
+
openSub.file.bytesize = size
openSub.file.hash = string.format("%08x%08x", hi,lo)
vlc.msg.dbg("[VLSub] Video hash: "..openSub.file.hash)
@@ -1617,7 +1632,7 @@ openSub = {
return true
end,
checkSession = function()
-
+
if openSub.session.token == "" then
openSub.request("LogIn")
else
@@ -1633,9 +1648,9 @@ function searchHash()
else
openSub.movie.sublanguageid = openSub.conf.languages[sel][1]
end
-
+
openSub.getMovieHash()
-
+
if openSub.file.hash then
openSub.checkSession()
openSub.request("SearchSubtitlesByHash")
@@ -1656,7 +1671,7 @@ function searchIMBD()
else
openSub.movie.sublanguageid = openSub.conf.languages[sel][1]
end
-
+
if openSub.movie.title ~= "" then
openSub.checkSession()
openSub.request("SearchSubtitles")
@@ -1664,20 +1679,58 @@ function searchIMBD()
end
end
+function last_subtitle_time_text(subtitle, lang_global)
+ lang_global = lang_global or lang
+ local last_subtitle_time = "?"
+ if subtitle.SubLastTS
+ and string.find(subtitle.SubLastTS, ":") then
+ last_subtitle_time = subtitle.SubLastTS
+ end
+ return string.format("[%s %s]", lang_global["int_last_sub"], last_subtitle_time)
+end
+export.last_subtitle_time_text = last_subtitle_time_text
+
+function rank_subtitles(unordered_subs, movie_duration)
+ marked_subs = {}
+ for _, item in ipairs(unordered_subs) do
+ local last_subtitle_time = date_string_to_time(item.SubLastTS)
+ local distance = -1
+ if last_subtitle_time ~= 0 then
+ distance = math.abs(movie_duration - last_subtitle_time)
+ end
+ table.insert(marked_subs, {rank=distance, sub=item})
+ end
+ return marked_subs
+end
+
+function order_by_ascending_distance_between_last_sub_time_and_movie_duration(unordered_subs, movie_duration)
+ marked_subs = rank_subtitles(unordered_subs, movie_duration)
+ table.sort(marked_subs, function(a, b) return b.rank == -1 or a.rank < b.rank and a.rank ~= -1 end)
+ ordered_subs = {}
+ for _, marked_sub in ipairs(marked_subs) do
+ table.insert(ordered_subs, marked_sub.sub)
+ end
+ return ordered_subs
+end
+export.order_by_ascending_distance_between_last_sub_time_and_movie_duration = order_by_ascending_distance_between_last_sub_time_and_movie_duration
+
function display_subtitles()
+ input_table['movieDuration']:set_text(movie_duration_text())
local mainlist = input_table["mainlist"]
mainlist:clear()
-
- if openSub.itemStore == "0" then
+
+ if openSub.itemStore == "0" then
mainlist:add_value(lang["mess_no_res"], 1)
setMessage(""..lang["mess_complete"]..": "..
lang["mess_no_res"])
- elseif openSub.itemStore then
- for i, item in ipairs(openSub.itemStore) do
+ elseif openSub.itemStore then
+ local ordered_subs = order_by_ascending_distance_between_last_sub_time_and_movie_duration(openSub.itemStore, vlc.input.item():duration())
+ for i, item in ipairs(ordered_subs) do
mainlist:add_value(
- (item.SubFileName or "???")..
- " ["..(item.SubLanguageID or "?").."]"..
- " ("..(item.SubSumCD or "?").." CD)", i)
+ last_subtitle_time_text(item)..
+ "["..(item.SubLanguageID or "?").."]"..
+ "("..(item.SubSumCD or "?").." CD)"..
+ " "..(item.SubFileName or "???"), i)
end
setMessage(""..lang["mess_complete"]..": "..
#(openSub.itemStore).." "..lang["mess_res"])
@@ -1686,7 +1739,7 @@ end
function get_first_sel(list)
local selection = list:get_selection()
- for index, name in pairs(selection) do
+ for index, name in pairs(selection) do
return index
end
return 0
@@ -1694,17 +1747,17 @@ end
function download_subtitles()
local index = get_first_sel(input_table["mainlist"])
-
+
if index == 0 then
setMessage(lang["mess_no_selection"])
return false
end
-
- openSub.actionLabel = lang["mess_downloading"]
-
+
+ openSub.actionLabel = lang["mess_downloading"]
+
local item = openSub.itemStore[index]
-
- if openSub.option.downloadBehaviour == 'manual'
+
+ if openSub.option.downloadBehaviour == 'manual'
or not openSub.file.hasInput then
local link = ""
link = link..""..lang["mess_dowload_link"]..":"
@@ -1712,27 +1765,27 @@ function download_subtitles()
link = link.." "
link = link..item.MovieReleaseName..""
-
+
setMessage(link)
return false
end
-
+
local message = ""
local subfileName = openSub.file.name or ""
-
+
if openSub.option.langExt then
subfileName = subfileName.."."..item.SubLanguageID
end
-
+
subfileName = subfileName.."."..item.SubFormat
local tmp_dir
local file_target_access = true
-
+
if is_dir(openSub.file.dir) then
tmp_dir = openSub.file.dir
elseif openSub.conf.dirPath then
tmp_dir = openSub.conf.dirPath
-
+
message = "
"..error_tag(lang["mess_save_fail"].." "..
""..
lang["mess_click_link"].."")
@@ -1742,18 +1795,18 @@ function download_subtitles()
lang["mess_click_link"].."")
return false
end
-
+
local tmpFileURI, tmpFileName = dump_zip(
- item.ZipDownloadLink,
- tmp_dir,
+ item.ZipDownloadLink,
+ tmp_dir,
item.SubFileName)
-
+
vlc.msg.dbg("[VLsub] tmpFileName: "..tmpFileName)
-
+
-- Determine if the path to the video file is accessible for writing
-
+
local target = openSub.file.dir..subfileName
-
+
if not file_touch(target) then
if openSub.conf.dirPath then
target = openSub.conf.dirPath..slash..subfileName
@@ -1769,37 +1822,37 @@ function download_subtitles()
return false
end
end
-
+
vlc.msg.dbg("[VLsub] Subtitles files: "..target)
-
- -- Unzipped data into file target
-
+
+ -- Unzipped data into file target
+
local stream = vlc.stream(tmpFileURI)
local data = ""
local subfile = io.open(target, "wb")
-
+
while data do
subfile:write(data)
data = stream:read(65536)
end
-
+
subfile:flush()
subfile:close()
-
+
stream = nil
collectgarbage()
-
+
if not os.remove(tmpFileName) then
vlc.msg.err("[VLsub] Unable to remove temp: "..tmpFileName)
end
-
+
-- load subtitles
- if add_sub(target) then
+ if add_sub(target) then
message = success_tag(lang["mess_loaded"]) .. message
else
message = error_tag(lang["mess_not_load"]) .. message
end
-
+
setMessage(message)
end
@@ -1807,18 +1860,18 @@ function dump_zip(url, dir, subfileName)
-- Dump zipped data in a temporary file
setMessage(openSub.actionLabel..": "..progressBarContent(0))
local resp = get(url)
-
- if not resp then
+
+ if not resp then
setError(lang["mess_no_response"])
- return false
+ return false
end
-
+
local tmpFileName = dir..subfileName..".gz"
if not file_touch(tmpFileName) then
return false
end
local tmpFile = assert(io.open(tmpFileName, "wb"))
-
+
tmpFile:write(resp)
tmpFile:flush()
tmpFile:close()
@@ -1877,8 +1930,8 @@ end
function get(url)
local host, path = parse_url(url)
local header = {
- "GET "..path.." HTTP/1.1",
- "Host: "..host,
+ "GET "..path.." HTTP/1.1",
+ "Host: "..host,
"User-Agent: "..openSub.conf.userAgentHTTP,
"",
""
@@ -1886,8 +1939,8 @@ function get(url)
local request = table.concat(header, "\r\n")
local status, response = http_req(host, 80, request)
-
- if status == 200 then
+
+ if status == 200 then
return response
else
vlc.msg.err("[VLSub] HTTP "..tostring(status).." : "..response)
@@ -1899,19 +1952,19 @@ function http_req(host, port, request)
local fd = vlc.net.connect_tcp(host, port)
if not fd then return false end
local pollfds = {}
-
+
pollfds[fd] = vlc.net.POLLIN
vlc.net.send(fd, request)
vlc.net.poll(pollfds)
-
+
local chunk = vlc.net.recv(fd, 2048)
local response = ""
local headerStr, header, body
local contentLength, status
local pct = 0
-
+
--~ vlc.msg.err(headerStr)
-
+
while chunk do
response = response..chunk
--~ vlc.msg.err("response", response)
@@ -1940,14 +1993,14 @@ function http_req(host, port, request)
end
vlc.net.close(fd)
-
- if status == 301
+
+ if status == 301
and header["Location"] then
local host, path = parse_url(trim(header["Location"]))
request = request
:gsub("^([^%s]+ )([^%s]+)", "%1"..path)
:gsub("(Host: )([^\n]*)", "%1"..host)
-
+
return http_req(host, port, request)
end
@@ -1956,23 +2009,23 @@ end
function parse_header(data)
local header = {}
-
+
for name, s, val in string.gmatch(
data,
"([^%s:]+)(:?)%s([^\n]+)\r?\n")
do
- if s == "" then
+ if s == "" then
header['statuscode'] = tonumber(string.sub(val, 1 , 3))
- else
+ else
header[name] = val
end
end
return header
-end
+end
function parse_url(url)
local url_parsed = vlc.net.url_parse(url)
- return url_parsed["host"],
+ return url_parsed["host"],
url_parsed["path"],
url_parsed["option"]
end
@@ -1989,7 +2042,7 @@ function parse_xml(data)
local resolve_xml = vlc.strings.resolve_xml_special_chars
for op, tag, p, empty, val in string.gmatch(
- data,
+ data,
"[%s\r\n\t]*<(%/?)([%w:_]+)(.-)(%/?)>"..
"[%s\r\n\t]*([^<]*)[%s\r\n\t]*"
) do
@@ -2031,7 +2084,7 @@ function parse_xml(data)
end
end
end
-
+
collectgarbage()
return tree
end
@@ -2042,7 +2095,7 @@ function parse_xmlrpc(xmlText)
local tmp, name = nil, nil
table.insert(stack, tree)
local FromXmlString = vlc.strings.resolve_xml_special_chars
-
+
local data_handle = {
int = function(v) return tonumber(v) end,
i4 = function(v) return tonumber(v) end,
@@ -2051,11 +2104,11 @@ function parse_xmlrpc(xmlText)
base64 = function(v) return tostring(v) end, -- FIXME
["string"] = function(v) return FromXmlString(v) end
}
-
- for c, label, empty, value
+
+ for c, label, empty, value
in xmlText:gmatch("<(%/?)([%w_:]+)(%/?)>([^<]*)") do
-
- if c == ""
+
+ if c == ""
then -- start tag
if label == "struct"
or label == "array" then
@@ -2074,27 +2127,27 @@ function parse_xmlrpc(xmlText)
if name then
stack[#stack][name] = data_handle[label](value)
else
- table.insert(stack[#stack],
+ table.insert(stack[#stack],
data_handle[label](value))
end
name = nil
end
if empty == "/" -- empty tag
- and #stack>0
+ and #stack>0
and (label == "struct"
or label == "array")
then
table.remove(stack)
end
else -- end tag
- if #stack>0
+ if #stack>0
and (label == "struct"
or label == "array")then
table.remove(stack)
end
end
end
-
+
return tree[1]
end
@@ -2103,21 +2156,21 @@ function dump_xml(data)
local stack = {}
local dump = ""
local convert_xml = vlc.strings.convert_xml_special_chars
-
+
local function parse(data, stack)
local data_index = {}
local k
local v
local i
local tb
-
+
for k,v in pairs(data) do
table.insert(data_index, {k, v})
table.sort(data_index, function(a, b)
- return a[1] < b[1]
+ return a[1] < b[1]
end)
end
-
+
for i,tb in pairs(data_index) do
k = tb[1]
v = tb[2]
@@ -2125,7 +2178,7 @@ function dump_xml(data)
dump = dump.."\r\n"..string.rep(
" ",
level)..
- "<"..k..">"
+ "<"..k..">"
table.insert(stack, k)
level = level + 1
elseif type(k)=="number" and k ~= 1 then
@@ -2134,7 +2187,7 @@ function dump_xml(data)
level-1)..
"<"..stack[level]..">"
end
-
+
if type(v)=="table" then
parse(v, stack)
elseif type(v)=="string" then
@@ -2144,7 +2197,7 @@ function dump_xml(data)
else
dump = dump..tostring(v)
end
-
+
if type(k)=="string" then
if type(v)=="table" then
dump = dump.."\r\n"..string.rep(
@@ -2156,7 +2209,7 @@ function dump_xml(data)
end
table.remove(stack)
level = level - 1
-
+
elseif type(k)=="number" and k ~= #data then
if type(v)=="table" then
dump = dump.."\r\n"..string.rep(
@@ -2182,9 +2235,9 @@ function make_uri(str)
local encode_uri = vlc.strings.encode_uri_component
local encodedPath = ""
for w in string.gmatch(str, "/([^/]+)") do
- encodedPath = encodedPath.."/"..encode_uri(w)
+ encodedPath = encodedPath.."/"..encode_uri(w)
end
-
+
if windowdrive then
return "file:///"..windowdrive..encodedPath
else
@@ -2193,38 +2246,38 @@ function make_uri(str)
end
function file_touch(name) -- test write ability
- if not name or trim(name) == ""
+ if not name or trim(name) == ""
then return false end
-
+
local f=io.open(name ,"w")
- if f~=nil then
- io.close(f)
- return true
- else
- return false
+ if f~=nil then
+ io.close(f)
+ return true
+ else
+ return false
end
end
function file_exist(name) -- test readability
- if not name or trim(name) == ""
+ if not name or trim(name) == ""
then return false end
local f=io.open(name ,"r")
- if f~=nil then
- io.close(f)
- return true
- else
- return false
+ if f~=nil then
+ io.close(f)
+ return true
+ else
+ return false
end
end
function is_dir(path)
- if not path or trim(path) == ""
+ if not path or trim(path) == ""
then return false end
-- Remove slash at the end or it won't work on Windows
path = string.gsub(path, "^(.-)[\\/]?$", "%1")
local f, _, code = io.open(path, "rb")
-
- if f then
+
+ if f then
_, _, code = f:read("*a")
f:close()
if code == 21 then
@@ -2233,23 +2286,23 @@ function is_dir(path)
elseif code == 13 then
return true
end
-
+
return false
end
function list_dir(path)
- if not path or trim(path) == ""
+ if not path or trim(path) == ""
then return false end
- local dir_list_cmd
+ local dir_list_cmd
local list = {}
if not is_dir(path) then return false end
-
+
if openSub.conf.os == "win" then
dir_list_cmd = io.popen('dir /b "'..path..'"')
elseif openSub.conf.os == "lin" then
dir_list_cmd = io.popen('ls -1 "'..path..'"')
end
-
+
if dir_list_cmd then
for filename in dir_list_cmd:lines() do
if string.match(filename, "^[^%s]+.+$") then
@@ -2263,7 +2316,7 @@ function list_dir(path)
end
function mkdir_p(path)
- if not path or trim(path) == ""
+ if not path or trim(path) == ""
then return false end
if openSub.conf.os == "win" then
os.execute('mkdir "' .. path..'"')
@@ -2281,12 +2334,12 @@ function is_window_path(path)
end
function is_win_safe(path)
- if not path or trim(path) == ""
+ if not path or trim(path) == ""
or not is_window_path(path)
then return false end
return string.match(path, "^%a?%:?[\\%w%p%s§¤]+$")
end
-
+
function trim(str)
if not str then return "" end
return string.gsub(str, "^[\r\n%s]*(.-)[\r\n%s]*$", "%1")
@@ -2295,3 +2348,18 @@ end
function remove_tag(str)
return string.gsub(str, "{[^}]+}", "")
end
+
+function date_string_to_time(date_string)
+ if not date_string
+ or not string.find(date_string, ":") then
+ return 0
+ end
+ local results = {}
+ for str in string.gmatch(date_string, "[^:]+") do
+ table.insert(results, tonumber(str) or 0)
+ end
+ return results[1]*60*60 + results[2]*60 + results[3]
+end
+export.date_string_to_time = date_string_to_time
+
+return export