Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
91684229
Commit
91684229
authored
Apr 23, 2013
by
Jean-Baptiste Kempf
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add VLSub to find subtitles
Ref #8131
parent
b97b7eef
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1383 additions
and
0 deletions
+1383
-0
share/lua/extensions/VLSub.lua
share/lua/extensions/VLSub.lua
+1383
-0
No files found.
share/lua/extensions/VLSub.lua
0 → 100644
View file @
91684229
--[[
VLSub Extension for VLC media player 1.1 and 2.0
Copyright 2010 - 2013 Guillaume Le Maout
Authors: Guillaume Le Maout
Contact: http://addons.videolan.org/messages/?action=newmessage&username=exebetche
Bug report: http://addons.videolan.org/content/show.php/?content=148752
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
=
"VLsub"
;
version
=
"0.8"
;
author
=
"exebetche"
;
url
=
'http://www.opensubtitles.org/'
;
shortdesc
=
"VLsub"
;
description
=
"<center><b>VLsub</b></center>"
..
"Download subtitles from OpenSubtitles.org"
;
capabilities
=
{
"input-listener"
,
"meta-listener"
}
}
end
-- Global variables
dlg
=
nil
-- Dialog
conflocation
=
'subdownloader.conf'
url
=
"http://api.opensubtitles.org/xml-rpc"
progressBarSize
=
40
interface_state
=
0
result_state
=
{}
default_language
=
"eng"
function
set_default_language
()
if
default_language
then
for
k
,
v
in
ipairs
(
languages
)
do
if
v
[
2
]
==
default_language
then
table.insert
(
languages
,
1
,
v
)
return
true
end
end
end
end
function
activate
()
vlc
.
msg
.
dbg
(
"[VLsub] Welcome"
)
set_default_language
()
create_dialog
()
openSub
.
getFileInfo
()
openSub
.
getMovieInfo
()
--~ openSub.request("LogIn")
end
function
deactivate
()
if
openSub
.
token
then
openSub
.
LogOut
()
end
vlc
.
msg
.
dbg
(
"[VLsub] Bye bye!"
)
end
function
close
()
vlc
.
deactivate
()
end
function
meta_changed
()
openSub
.
getFileInfo
()
openSub
.
getMovieInfo
()
if
tmp_method_id
==
"hash"
then
searchHash
()
elseif
tmp_method_id
==
"imdb"
then
widget
.
get
(
"title"
).
input
:
set_text
(
openSub
.
movie
.
name
)
widget
.
get
(
"season"
).
input
:
set_text
(
openSub
.
movie
.
seasonNumber
)
widget
.
get
(
"episode"
).
input
:
set_text
(
openSub
.
movie
.
episodeNumber
)
end
end
function
input_changed
()
return
false
end
openSub
=
{
itemStore
=
nil
,
actionLabel
=
""
,
conf
=
{
url
=
"http://api.opensubtitles.org/xml-rpc"
,
userAgentHTTP
=
"VLSub"
,
useragent
=
"VLSub 0.8"
,
username
=
""
,
password
=
""
,
language
=
""
,
downloadSub
=
true
,
removeTag
=
true
,
justgetlink
=
false
},
session
=
{
loginTime
=
0
,
token
=
""
},
file
=
{
uri
=
nil
,
ext
=
nil
,
name
=
nil
,
path
=
nil
,
dir
=
nil
,
hash
=
nil
,
bytesize
=
nil
,
fps
=
nil
,
timems
=
nil
,
frames
=
nil
},
movie
=
{
name
=
""
,
season
=
""
,
episode
=
""
,
imdbid
=
nil
,
imdbidShow
=
nil
,
imdbidEpisode
=
nil
,
imdbRequest
=
nil
,
year
=
nil
,
releasename
=
nil
,
aka
=
nil
},
sub
=
{
id
=
nil
,
authorcomment
=
nil
,
hash
=
nil
,
idfile
=
nil
,
filename
=
nil
,
content
=
nil
,
IDSubMovieFile
=
nil
,
score
=
nil
,
comment
=
nil
,
bad
=
nil
,
languageid
=
nil
},
request
=
function
(
methodName
)
local
params
=
openSub
.
methods
[
methodName
].
params
()
local
reqTable
=
openSub
.
getMethodBase
(
methodName
,
params
)
local
request
=
"<?xml version='1.0'?>"
..
dump_xml
(
reqTable
)
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"
,
"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
response
=
parse_xmlrpc
(
responseStr
)
if
(
response
and
response
.
status
==
"200 OK"
)
then
vlc
.
msg
.
dbg
(
responseStr
)
return
openSub
.
methods
[
methodName
].
callback
(
response
)
elseif
response
then
setError
(
"code "
..
response
.
status
..
"("
..
status
..
")"
)
return
false
else
setError
(
"Server not responding"
)
return
false
end
elseif
status
==
401
then
setError
(
"Request unauthorized"
)
response
=
parse_xmlrpc
(
responseStr
)
if
openSub
.
session
.
token
~=
response
.
token
then
setMessage
(
"Session expired, retrying"
)
openSub
.
session
.
token
=
response
.
token
openSub
.
request
(
methodName
)
end
return
false
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
=
{
LogIn
=
{
params
=
function
()
openSub
.
actionLabel
=
"Logging in"
return
{
{
value
=
{
string
=
openSub
.
conf
.
username
}
},
{
value
=
{
string
=
openSub
.
conf
.
password
}
},
{
value
=
{
string
=
openSub
.
conf
.
language
}
},
{
value
=
{
string
=
openSub
.
conf
.
useragent
}
}
}
end
,
callback
=
function
(
resp
)
openSub
.
session
.
token
=
resp
.
token
openSub
.
session
.
loginTime
=
os.time
()
return
true
end
},
LogOut
=
{
params
=
function
()
openSub
.
actionLabel
=
"Logging out"
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
}
}
end
,
callback
=
function
()
return
true
end
},
NoOperation
=
{
params
=
function
()
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
}
}
end
,
callback
=
function
()
return
true
end
},
SearchSubtitlesByHash
=
{
methodName
=
"SearchSubtitles"
,
params
=
function
()
openSub
.
actionLabel
=
"Searching subtitles"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
},
{
value
=
{
array
=
{
data
=
{
value
=
{
struct
=
{
member
=
{
{
name
=
"sublanguageid"
,
value
=
{
string
=
openSub
.
sub
.
languageid
}
},
{
name
=
"moviehash"
,
value
=
{
string
=
openSub
.
file
.
hash
}
},
{
name
=
"moviebytesize"
,
value
=
{
double
=
openSub
.
file
.
bytesize
}
}
}}}}}}}
}
end
,
callback
=
function
(
resp
)
openSub
.
itemStore
=
resp
.
data
if
openSub
.
itemStore
~=
"0"
then
return
true
else
openSub
.
itemStore
=
nil
return
false
end
end
},
SearchMoviesOnIMDB
=
{
params
=
function
()
openSub
.
actionLabel
=
"Searching movie on IMDB"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
},
{
value
=
{
string
=
openSub
.
movie
.
imdbRequest
}
}
}
end
,
callback
=
function
(
resp
)
openSub
.
itemStore
=
resp
.
data
if
openSub
.
itemStore
~=
"0"
then
return
true
else
openSub
.
itemStore
=
nil
return
false
end
end
},
SearchSubtitlesByIdIMDB
=
{
methodName
=
"SearchSubtitles"
,
params
=
function
()
openSub
.
actionLabel
=
"Searching subtitles"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
},
{
value
=
{
array
=
{
data
=
{
value
=
{
struct
=
{
member
=
{
{
name
=
"sublanguageid"
,
value
=
{
string
=
openSub
.
sub
.
languageid
}
},
{
name
=
"imdbid"
,
value
=
{
string
=
openSub
.
movie
.
imdbid
}
}
}}}}}}}
}
end
,
callback
=
function
(
resp
)
openSub
.
itemStore
=
resp
.
data
if
openSub
.
itemStore
~=
"0"
then
return
true
else
openSub
.
itemStore
=
nil
return
false
end
end
},
GetIMDBMovieDetails
=
{
params
=
function
()
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
},
{
value
=
{
string
=
openSub
.
movie
.
imdbid
}
}
}
end
,
callback
=
function
(
resp
)
print
(
dump_xml
(
resp
))
end
},
IsTVserie
=
{
methodName
=
"GetIMDBMovieDetails"
,
params
=
function
()
return
{
{
value
=
{
string
=
openSub
.
session
.
token
}
},
{
value
=
{
string
=
openSub
.
movie
.
imdbid
}
}
}
end
,
callback
=
function
(
resp
)
return
(
string.lower
(
resp
.
data
.
kind
)
==
"tv series"
)
end
}
},
getInputItem
=
function
()
return
vlc
.
item
or
vlc
.
input
.
item
()
end
,
getFileInfo
=
function
()
local
item
=
openSub
.
getInputItem
()
if
not
item
then
return
false
else
local
file
=
openSub
.
file
local
parsed_uri
=
vlc
.
net
.
url_parse
(
item
:
uri
())
file
.
uri
=
item
:
uri
()
file
.
protocol
=
parsed_uri
[
"protocol"
]
file
.
path
=
vlc
.
strings
.
decode_uri
(
parsed_uri
[
"path"
])
--correction needed for windows
local
windowPath
=
string.match
(
file
.
path
,
"^/(%a:/.+)$"
)
if
windowPath
then
file
.
path
=
windowPath
end
file
.
dir
,
file
.
completeName
=
string.match
(
file
.
path
,
"^([^\n]-/?)([^/]+)$"
)
file
.
name
,
file
.
ext
=
string.match
(
file
.
path
,
"([^/]-)%.?([^%.]*)$"
)
if
file
.
ext
==
"part"
then
file
.
name
,
file
.
ext
=
string.match
(
file
.
name
,
"^([^/]+)%.([^%.]+)$"
)
end
file
.
cleanName
=
string.gsub
(
file
.
name
,
"[%._]"
,
" "
)
end
end
,
getMovieInfo
=
function
()
if
not
openSub
.
file
.
name
then
return
false
end
local
showName
,
seasonNumber
,
episodeNumber
=
string.match
(
openSub
.
file
.
cleanName
,
"(.+)[sS](%d%d)[eE](%d%d).*"
)
if
not
showName
then
showName
,
seasonNumber
,
episodeNumber
=
string.match
(
openSub
.
file
.
cleanName
,
"(.+)(%d)[xX](%d%d).*"
)
end
if
showName
then
openSub
.
movie
.
name
=
showName
openSub
.
movie
.
seasonNumber
=
seasonNumber
openSub
.
movie
.
episodeNumber
=
episodeNumber
else
openSub
.
movie
.
name
=
openSub
.
file
.
cleanName
openSub
.
movie
.
seasonNumber
=
""
openSub
.
movie
.
episodeNumber
=
""
end
end
,
getMovieHash
=
function
()
openSub
.
actionLabel
=
"Calculating movie hash"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
local
item
=
openSub
.
getInputItem
()
if
not
item
then
setError
(
"Please use this method during playing"
)
return
false
end
openSub
.
getFileInfo
()
if
openSub
.
file
.
protocol
~=
"file"
then
setError
(
"This method works with local file only (for now)"
)
return
false
end
local
path
=
openSub
.
file
.
path
if
not
path
then
setError
(
"File not found"
)
return
false
end
local
file
=
assert
(
io.open
(
path
,
"rb"
))
if
not
file
then
setError
(
"File not found"
)
return
false
end
local
i
=
1
local
a
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}
local
hash
=
""
local
size
=
file
:
seek
(
"end"
)
file
:
seek
(
"set"
,
0
)
local
bytes
=
file
:
read
(
65536
)
file
:
seek
(
"set"
,
size
-
65536
)
bytes
=
bytes
..
file
:
read
(
"*all"
)
file
:
close
()
for
b
in
string
.
gfind
(
string.format
(
"%16X "
,
size
),
".."
)
do
d
=
tonumber
(
b
,
16
)
if
type
(
d
)
~=
"nil"
then
a
[
9
-
i
]
=
d
end
i
=
i
+
1
end
i
=
1
for
b
in
string
.
gfind
(
bytes
,
"."
)
do
a
[
i
]
=
a
[
i
]
+
string.byte
(
b
)
d
=
math.floor
(
a
[
i
]
/
255
)
if
d
>=
1
then
a
[
i
]
=
a
[
i
]
-
d
*
256
if
i
<
8
then
a
[
i
+
1
]
=
a
[
i
+
1
]
+
d
end
end
i
=
i
+
1
if
i
==
9
then
i
=
1
end
end
for
i
=
8
,
1
,
-
1
do
hash
=
hash
..
string.format
(
"%02x"
,
a
[
i
])
end
openSub
.
file
.
bytesize
=
size
openSub
.
file
.
hash
=
hash
return
true
end
,
getImdbEpisodeId
=
function
(
season
,
episode
)
openSub
.
actionLabel
=
"Searching episode id on IMDB"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
local
IMDBurl
=
"http://www.imdb.com/title/tt"
..
openSub
.
movie
.
imdbid
..
"/episodes/_ajax?season="
..
season
local
host
,
path
=
parse_url
(
IMDBurl
)
local
stream
=
vlc
.
stream
(
IMDBurl
)
local
data
=
""
while
data
do
data
=
stream
:
read
(
65536
)
local
id
=
string.match
(
data
,
'data%-const="tt(%d+)"[^>]+>\r?\n<img[^>]+>\r?\n<div> S'
..
season
..
', Ep'
..
episode
)
return
id
end
return
false
end
,
getImdbEpisodeIdYQL
=
function
(
season
,
episode
)
openSub
.
actionLabel
=
"Searching episode on IMDB"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
local
url
=
"http://pipes.yahoo.com/pipes/pipe.run?_id=5f525406f2b2b376eeb20b97a216bcb1&_render=json&imdbid="
..
openSub
.
movie
.
imdbid
..
"&season="
..
season
..
"&episode="
..
episode
local
host
,
path
=
parse_url
(
url
)
local
header
=
{
"GET "
..
path
..
" HTTP/1.1"
,
"Host: "
..
host
,
"User-Agent: "
..
openSub
.
conf
.
userAgentHTTP
,
""
,
""
}
local
request
=
table.concat
(
header
,
"
\r\n
"
)
local
fd
=
vlc
.
net
.
connect_tcp
(
host
,
80
)
local
data
=
""
if
fd
>=
0
then
local
pollfds
=
{}
pollfds
[
fd
]
=
vlc
.
net
.
POLLIN
vlc
.
net
.
send
(
fd
,
request
)
vlc
.
net
.
poll
(
pollfds
)
data
=
vlc
.
net
.
recv
(
fd
,
2048
)
print
(
data
)
end
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
100
))
local
id
=
string.match
(
data
,
'"content":"(%d+)"'
)
return
id
end
,
getImdbEpisodeIdGoogle
=
function
(
season
,
episode
,
title
)
openSub
.
actionLabel
=
"Searching episode on IMDB"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
local
query
=
'site:imdb.com tv episode "'
..
title
..
'" (#'
..
season
..
'.'
..
episode
..
')'
local
url
=
"https://www.google.com/uds/GwebSearch?hl=fr&source=gsc&gss=.com&gl=www.google.com&context=1&key=notsupplied&v=1.0&&q="
..
vlc
.
strings
.
encode_uri_component
(
query
)
local
host
,
path
=
parse_url
(
url
)
local
header
=
{
"GET "
..
path
..
" HTTP/1.1"
,
"Host: "
..
host
,
"User-Agent: "
..
openSub
.
conf
.
userAgentHTTP
,
""
,
""
}
local
request
=
table.concat
(
header
,
"
\r\n
"
)
local
fd
=
vlc
.
net
.
connect_tcp
(
host
,
80
)
local
data
=
""
if
fd
>=
0
then
local
pollfds
=
{}
pollfds
[
fd
]
=
vlc
.
net
.
POLLIN
vlc
.
net
.
send
(
fd
,
request
)
vlc
.
net
.
poll
(
pollfds
)
data
=
vlc
.
net
.
recv
(
fd
,
2048
)
--print(data)
end
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
100
))
local
id
=
string.match
(
data
,
'"url":"http://www.imdb.com/title/tt(%d+)/"'
)
return
id
end
,
loadSubtitles
=
function
(
url
,
fileDir
,
SubFileName
,
target
)
openSub
.
actionLabel
=
"Downloading subtitle"
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
0
))
local
resp
=
get
(
url
)
local
subfileURI
=
""
if
resp
then
local
tmpFileName
=
fileDir
..
SubFileName
..
".zip"
local
tmpFile
=
assert
(
io.open
(
tmpFileName
,
"wb"
))
tmpFile
:
write
(
resp
)
tmpFile
:
close
()
subfileURI
=
"zip://"
..
make_uri
(
tmpFileName
,
true
)
..
"!/"
..
SubFileName
if
target
then
local
stream
=
vlc
.
stream
(
subfileURI
)
local
data
=
""
local
subfile
=
assert
(
io.open
(
target
,
"w"
))
-- FIXME: check for file presence before overwrite (maybe ask what to do)
while
data
do
if
openSub
.
conf
.
removeTag
then
subfile
:
write
(
remove_tag
(
data
)
..
"
\n
"
)
else
subfile
:
write
(
data
..
"
\n
"
)
end
data
=
stream
:
readline
()
end
subfile
:
close
()
stream
=
nil
end
subfileURI
=
make_uri
(
target
,
true
)
collectgarbage
()
-- force gargabe collection in order to close the opened stream
os.remove
(
tmpFileName
)
end
local
item
=
vlc
.
item
or
vlc
.
input
.
item
()
if
item
then
vlc
.
input
.
add_subtitle
(
subfileURI
)
else
setError
(
"No current input, unable to add subtitles "
..
target
)
end
end
}
function
make_uri
(
str
,
encode
)
local
iswindowPath
=
string.match
(
str
,
"^%a:/.+$"
)
-- vlc.msg.dbg(iswindowPath)
if
encode
then
local
encodedPath
=
""
for
w
in
string.gmatch
(
str
,
"/([^/]+)"
)
do
vlc
.
msg
.
dbg
(
w
)
encodedPath
=
encodedPath
..
"/"
..
vlc
.
strings
.
encode_uri_component
(
w
)
end
str
=
encodedPath
end
if
iswindowPath
then
return
"file:///"
..
str
else
return
"file://"
..
str
end
end
function
searchHash
()
if
not
hasAssociatedResult
()
then
openSub
.
sub
.
languageid
=
languages
[
widget
.
getVal
(
"language"
)][
2
]
openSub
.
getMovieHash
()
associatedResult
()
if
openSub
.
file
.
hash
then
openSub
.
request
(
"SearchSubtitlesByHash"
)
display_subtitles
()
end
else
local
selection
=
widget
.
getVal
(
"hashmainlist"
)
if
#
selection
>
0
then
download_subtitles
(
selection
)
end
end
end
function
searchIMBD
()
local
title
=
trim
(
widget
.
getVal
(
"title"
))
local
old_title
=
trim
(
widget
.
get
(
"title"
).
value
)
local
season
=
tonumber
(
widget
.
getVal
(
"season"
))
local
old_season
=
tonumber
(
widget
.
get
(
"season"
).
value
)
local
episode
=
tonumber
(
widget
.
getVal
(
"episode"
))
local
old_episode
=
tonumber
(
widget
.
get
(
"episode"
).
value
)
local
language
=
languages
[
widget
.
getVal
(
"language"
)][
2
]
local
selection
=
widget
.
getVal
(
"imdbmainlist"
)
local
sel
=
(
#
selection
>
0
)
local
newTitle
=
(
title
~=
old_title
)
local
newEpisode
=
(
season
~=
old_season
or
episode
~=
old_episode
)
local
newLanguage
=
(
language
~=
openSub
.
sub
.
languageid
)
local
movie
=
openSub
.
movie
local
imdbResults
=
{}
widget
.
get
(
"title"
).
value
=
title
widget
.
get
(
"season"
).
value
=
season
widget
.
get
(
"episode"
).
value
=
episode
openSub
.
sub
.
languageid
=
language
if
newTitle
then
movie
.
imdbRequest
=
title
movie
.
imdbid
=
nil
movie
.
imdbidShow
=
nil
if
openSub
.
request
(
"SearchMoviesOnIMDB"
)
then
-- search exact match
local
lowerTitle
=
string.lower
(
title
)
local
itemTitle
=
""
for
i
,
item
in
ipairs
(
openSub
.
itemStore
)
do
-- itemTitle = string.match(item.title, "[%s\"]*([^%(\"]*)[%s\"']*%(?")
item
.
cleanTitle
=
string.match
(
item
.
title
,
"[%s\"
]
*
([
^%
(
\
"]*)[%s\"
']*%(?")
-- vlc.msg.dbg(itemTitle)
--[[if string.lower(itemTitle) == lowerTitle then
movie.imdbid = item.id
break
end]]
table.insert(imdbResults, item.title)
end
if not movie.imdbid then
widget.setVal("imdbmainlist")
widget.setVal("imdbmainlist", imdbResults)
end
end
end
if not movie.imdbid and sel then
local index = selection[1][1]
local item = openSub.itemStore[index]
movie.imdbid = item.id
movie.title = item.cleanTitle
movie.imdbidShow = movie.imdbid
newEpisode = true
end
if movie.imdbid then
if season and episode and (newTitle or newEpisode) then
if not newTitle then
movie.imdbid = movie.imdbidShow
end
movie.imdbidEpisode = openSub.getImdbEpisodeIdGoogle(season, episode, movie.title)
-- movie.imdbidEpisode = openSub.getImdbEpisodeId(season, episode)
if movie.imdbidEpisode then
vlc.msg.dbg("Episode imdbid: "..movie.imdbidEpisode)
movie.imdbidShow = movie.imdbid
movie.imdbid = movie.imdbidEpisode
elseif openSub.request("IsTVserie") then
movie.imdbidEpisode = openSub.getImdbEpisodeIdYQL(season, episode)
if movie.imdbidEpisode then
movie.imdbidShow = movie.imdbid
movie.imdbid = movie.imdbidEpisode
else
setError("Season/episode don'
t
match
for
this
title
")
end
else
setError("
Title
not
referenced
as
a
TV
serie
on
IMDB
")
--~ -- , choose an other one and/or empty episode/season field"
)
widget
.
setVal
(
"imdbmainlist"
,
imdbResults
)
end
end
if
newTitle
or
newEpisode
or
newLanguage
then
openSub
.
request
(
"SearchSubtitlesByIdIMDB"
)
display_subtitles
()
elseif
sel
and
openSub
.
itemStore
then
download_subtitles
(
selection
)
end
end
end
function
associatedResult
()
local
item
=
openSub
.
getInputItem
()
if
not
item
then
return
false
end
result_state
[
tmp_method_id
]
=
item
:
uri
()
end
function
hasAssociatedResult
()
local
item
=
openSub
.
getInputItem
()
if
not
item
then
return
false
end
return
(
result_state
[
tmp_method_id
]
==
item
:
uri
())
end
function
display_subtitles
()
local
list
=
tmp_method_id
..
"mainlist"
widget
.
setVal
(
list
)
if
openSub
.
itemStore
then
for
i
,
item
in
ipairs
(
openSub
.
itemStore
)
do
widget
.
setVal
(
list
,
item
.
SubFileName
..
" ["
..
item
.
SubLanguageID
..
"] ("
..
item
.
SubSumCD
..
" CD)"
)
end
else
widget
.
setVal
(
list
,
"No result"
)
end
end
function
download_subtitles
(
selection
)
local
list
=
tmp_method_id
..
"mainlist"
widget
.
resetSel
(
list
)
-- reset selection
local
index
=
selection
[
1
][
1
]
local
item
=
openSub
.
itemStore
[
index
]
local
subfileTarget
=
""
if
openSub
.
file
.
dir
and
openSub
.
file
.
name
then
subfileTarget
=
openSub
.
file
.
dir
..
openSub
.
file
.
name
..
"."
..
item
.
SubLanguageID
..
"."
..
item
.
SubFormat
else
subfileTarget
=
os.tmpname
()
--FIXME: ask the user where to put it instaed
end
if
openSub
.
conf
.
justgetlink
then
setMessage
(
"Link: <a href='"
..
item
.
ZipDownloadLink
..
"'>"
..
item
.
ZipDownloadLink
..
"</a>"
)
else
openSub
.
loadSubtitles
(
item
.
ZipDownloadLink
,
openSub
.
file
.
dir
,
item
.
SubFileName
,
subfileTarget
)
end
end
widget
=
{
stack
=
{},
meta
=
{},
registered_table
=
{},
main_table
=
{},
set_node
=
function
(
node
,
parent
)
local
left
=
parent
.
left
for
k
,
l
in
pairs
(
node
)
do
--parse items
local
tmpTop
=
parent
.
height
local
tmpLeft
=
left
local
ltmpLeft
=
l
.
left
local
ltmpTop
=
l
.
top
local
tmphidden
=
l
.
hidden
l
.
top
=
parent
.
height
+
parent
.
top
l
.
left
=
left
l
.
parent
=
parent
if
l
.
display
==
"none"
or
parent
.
hidden
then
l
.
hidden
=
true
else
l
.
hidden
=
false
end
if
l
.
type
==
"div"
then
--that's a container
l
.
display
=
(
l
.
display
or
"block"
)
l
.
height
=
1
for
_
,
newNode
in
ipairs
(
l
.
content
)
do
--parse lines
widget
.
set_node
(
newNode
,
l
)
l
.
height
=
l
.
height
+
1
end
l
.
height
=
l
.
height
-
1
left
=
left
-
1
else
--that's an item
l
.
display
=
(
l
.
display
or
"inline"
)
if
not
l
.
input
then
tmphidden
=
true
end
if
tmphidden
and
not
l
.
hidden
then
--~ create
widget
.
create
(
l
)
elseif
not
tmphidden
and
l
.
hidden
then
--~ destroy
widget
.
destroy
(
l
)
end
if
not
l
.
hidden
and
(
ltmpTop
~=
l
.
top
or
ltmpLeft
~=
l
.
left
)
then
if
l
.
input
then
--~ destroy
widget
.
destroy
(
l
)
end
--~ recreate
widget
.
create
(
l
)
end
end
--~ Store reference ID
if
l
.
id
and
not
widget
.
registered_table
[
l
.
id
]
then
widget
.
registered_table
[
l
.
id
]
=
l
end
if
l
.
display
==
"block"
then
parent
.
height
=
parent
.
height
+
(
l
.
height
or
1
)
left
=
parent
.
left
elseif
l
.
display
==
"none"
then
parent
.
height
=
(
tmpTop
or
parent
.
height
)
left
=
(
tmpLeft
or
left
)
elseif
l
.
display
==
"inline"
then
left
=
left
+
(
l
.
width
or
1
)
end
end
end
,
set_interface
=
function
(
intf_map
)
local
root
=
{
left
=
1
,
top
=
0
,
height
=
0
,
hidden
=
false
}
widget
.
set_node
(
intf_map
,
root
)
end
,
destroy
=
function
(
w
)
dlg
:
del_widget
(
w
.
input
)
--~ w.input = nil
--~ w.value = nil
if
widget
.
registered_table
[
w
.
id
]
then
widget
.
registered_table
[
w
.
id
]
=
nil
end
end
,
create
=
function
(
w
)
local
cur_widget
if
w
.
type
==
"button"
then
cur_widget
=
dlg
:
add_button
(
w
.
value
or
""
,
w
.
callback
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"label"
then
cur_widget
=
dlg
:
add_label
(
w
.
value
or
""
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"html"
then
cur_widget
=
dlg
:
add_html
(
w
.
value
or
""
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"text_input"
then
cur_widget
=
dlg
:
add_text_input
(
w
.
value
or
""
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"password"
then
cur_widget
=
dlg
:
add_password
(
w
.
value
or
""
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"check_box"
then
cur_widget
=
dlg
:
add_check_box
(
w
.
value
or
""
,
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"dropdown"
then
cur_widget
=
dlg
:
add_dropdown
(
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"list"
then
cur_widget
=
dlg
:
add_list
(
w
.
left
,
w
.
top
,
w
.
width
or
1
,
w
.
height
or
1
)
elseif
w
.
type
==
"image"
then
end
if
w
.
type
==
"dropdown"
or
w
.
type
==
"list"
then
if
type
(
w
.
value
)
==
"table"
then
for
k
,
l
in
ipairs
(
w
.
value
)
do
if
type
(
l
)
==
"table"
then
cur_widget
:
add_value
(
l
[
1
],
k
)
else
cur_widget
:
add_value
(
l
,
k
)
end
end
end
end
if
w
.
type
and
w
.
type
~=
"div"
then
w
.
input
=
cur_widget
end
end
,
get
=
function
(
h
)
return
widget
.
registered_table
[
h
]
end
,
setVal
=
function
(
h
,
val
,
index
)
widget
.
set_val
(
widget
.
registered_table
[
h
],
val
,
index
)
end
,
set_val
=
function
(
w
,
val
,
index
)
local
input
=
w
.
input
local
t
=
w
.
type
if
t
==
"button"
or
t
==
"label"
or
t
==
"html"
or
t
==
"text_input"
or
t
==
"password"
then
if
type
(
val
)
==
"string"
then
input
:
set_text
(
val
)
w
.
value
=
val
end
elseif
t
==
"check_box"
then
if
type
(
val
)
==
"bool"
then
input
:
set_checked
(
val
)
else
input
:
set_text
(
val
)
end
elseif
t
==
"dropdown"
or
t
==
"list"
then
if
val
and
index
then
input
:
add_value
(
val
,
index
)
w
.
value
[
index
]
=
val
elseif
val
and
not
index
then
if
type
(
val
)
==
"table"
then
for
k
,
l
in
ipairs
(
val
)
do
input
:
add_value
(
l
,
k
)
table.insert
(
w
.
value
,
l
)
end
else
input
:
add_value
(
val
,
#
w
.
value
+
1
)
table.insert
(
w
.
value
,
val
)
end
elseif
not
val
and
not
index
then
input
:
clear
()
w
.
value
=
nil
w
.
value
=
{}
end
end
end
,
getVal
=
function
(
h
,
typeval
)
if
not
widget
.
registered_table
[
h
]
then
print
(
h
)
return
false
end
return
widget
.
get_val
(
widget
.
registered_table
[
h
],
typeval
)
end
,
get_val
=
function
(
w
,
typeval
)
local
input
=
w
.
input
local
t
=
w
.
type
if
t
==
"button"
or
t
==
"label"
or
t
==
"html"
or
t
==
"text_input"
or
t
==
"password"
then
return
input
:
get_text
()
elseif
t
==
"check_box"
then
if
typeval
==
"checked"
then
return
input
:
get_checked
()
else
return
input
:
get_text
()
end
elseif
t
==
"dropdown"
then
return
input
:
get_value
()
elseif
t
==
"list"
then
local
selection
=
input
:
get_selection
()
local
output
=
{}
for
index
,
name
in
pairs
(
selection
)
do
table.insert
(
output
,
{
index
,
name
})
end
return
output
end
end
,
resetSel
=
function
(
h
,
typeval
)
local
w
=
widget
.
registered_table
[
h
]
local
val
=
w
.
value
widget
.
set_val
(
w
)
widget
.
set_val
(
w
,
val
)
end
}
function
create_dialog
()
dlg
=
vlc
.
dialog
(
"VLSub"
)
widget
.
set_interface
(
interface
)
end
function
set_interface
()
local
method_index
=
widget
.
getVal
(
"method"
)
local
method_id
=
methods
[
method_index
][
2
]
if
tmp_method_id
then
if
tmp_method_id
==
method_id
then
return
false
end
widget
.
get
(
tmp_method_id
).
display
=
"none"
else
openSub
.
request
(
"LogIn"
)
end
tmp_method_id
=
method_id
widget
.
get
(
method_id
).
display
=
"block"
widget
.
set_interface
(
interface
)
setMessage
(
""
)
if
method_id
==
"hash"
then
searchHash
()
elseif
method_id
==
"imdb"
then
if
openSub
.
file
.
name
and
not
hasAssociatedResult
()
then
associatedResult
()
widget
.
get
(
"title"
).
input
:
set_text
(
openSub
.
movie
.
name
)
widget
.
get
(
"season"
).
input
:
set_text
(
openSub
.
movie
.
seasonNumber
)
widget
.
get
(
"episode"
).
input
:
set_text
(
openSub
.
movie
.
episodeNumber
)
end
end
end
function
progressBarContent
(
pct
)
local
content
=
"<span style='color:#181'>"
local
accomplished
=
math.ceil
(
progressBarSize
*
pct
/
100
)
local
left
=
progressBarSize
-
accomplished
content
=
content
..
string.rep
(
"|"
,
accomplished
)
content
=
content
..
"</span>"
content
=
content
..
string.rep
(
"|"
,
left
)
return
content
end
function
setError
(
str
)
setMessage
(
"<span style='color:#B23'>Error: "
..
str
..
"</span>"
)
end
function
setMessage
(
str
)
if
widget
.
get
(
"message"
)
then
widget
.
setVal
(
"message"
,
str
)
dlg
:
update
()
end
end
function
get
(
url
)
local
host
,
path
=
parse_url
(
url
)
local
header
=
{
"GET "
..
path
..
" HTTP/1.1"
,
"Host: "
..
host
,
"User-Agent: "
..
openSub
.
conf
.
userAgentHTTP
,
--~ "TE: identity", -- useless, and that's a shame
""
,
""
}
local
request
=
table.concat
(
header
,
"
\r\n
"
)
local
response
local
status
,
response
=
http_req
(
host
,
80
,
request
)
if
status
==
200
then
return
response
else
return
false
end
end
function
http_req
(
host
,
port
,
request
)
local
fd
=
vlc
.
net
.
connect_tcp
(
host
,
port
)
if
fd
>=
0
then
local
pollfds
=
{}
pollfds
[
fd
]
=
vlc
.
net
.
POLLIN
vlc
.
net
.
send
(
fd
,
request
)
vlc
.
net
.
poll
(
pollfds
)
local
response
=
vlc
.
net
.
recv
(
fd
,
1024
)
local
headerStr
,
body
=
string.match
(
response
,
"(.-\r?\n)\r?\n(.*)"
)
local
header
=
parse_header
(
headerStr
)
local
contentLength
=
tonumber
(
header
[
"Content-Length"
])
local
TransferEncoding
=
header
[
"Transfer-Encoding"
]
local
status
=
tonumber
(
header
[
"statuscode"
])
local
bodyLenght
=
string.len
(
body
)
local
pct
=
0
if
status
~=
200
then
return
status
end
while
contentLength
and
bodyLenght
<
contentLength
do
vlc
.
net
.
poll
(
pollfds
)
response
=
vlc
.
net
.
recv
(
fd
,
1024
)
if
response
then
body
=
body
..
response
else
vlc
.
net
.
close
(
fd
)
return
false
end
bodyLenght
=
string.len
(
body
)
pct
=
bodyLenght
/
contentLength
*
100
setMessage
(
openSub
.
actionLabel
..
": "
..
progressBarContent
(
pct
))
end
vlc
.
net
.
close
(
fd
)
return
status
,
body
end
return
""
end
function
parse_header
(
data
)
local
header
=
{}
for
name
,
s
,
val
in
string
.
gfind
(
data
,
"([^%s:]+)(:?)%s([^\n]+)\r?\n"
)
do
if
s
==
""
then
header
[
'statuscode'
]
=
tonumber
(
string.sub
(
val
,
1
,
3
))
else
header
[
name
]
=
val
end
end
return
header
end
function
parse_url
(
url
)
local
url_parsed
=
vlc
.
net
.
url_parse
(
url
)
return
url_parsed
[
"host"
],
url_parsed
[
"path"
],
url_parsed
[
"option"
]
end
function
parse_xml
(
data
)
local
tree
=
{}
local
stack
=
{}
local
tmp
=
{}
local
level
=
0
table.insert
(
stack
,
tree
)
for
op
,
tag
,
p
,
empty
,
val
in
string.gmatch
(
data
,
"<(%/?)([%w:]+)(.-)(%/?)>[%s\r\n\t]*([^<]*)"
)
do
if
op
==
"/"
then
if
level
>
1
then
level
=
level
-
1
table.remove
(
stack
)
end
else
level
=
level
+
1
if
val
==
""
then
if
type
(
stack
[
level
][
tag
])
==
"nil"
then
stack
[
level
][
tag
]
=
{}
table.insert
(
stack
,
stack
[
level
][
tag
])
else
if
type
(
stack
[
level
][
tag
][
1
])
==
"nil"
then
tmp
=
nil
tmp
=
stack
[
level
][
tag
]
stack
[
level
][
tag
]
=
nil
stack
[
level
][
tag
]
=
{}
table.insert
(
stack
[
level
][
tag
],
tmp
)
end
tmp
=
nil
tmp
=
{}
table.insert
(
stack
[
level
][
tag
],
tmp
)
table.insert
(
stack
,
tmp
)
end
else
if
type
(
stack
[
level
][
tag
])
==
"nil"
then
stack
[
level
][
tag
]
=
{}
end
stack
[
level
][
tag
]
=
vlc
.
strings
.
resolve_xml_special_chars
(
val
)
table.insert
(
stack
,
{})
end
if
empty
~=
""
then
stack
[
level
][
tag
]
=
""
level
=
level
-
1
table.remove
(
stack
)
end
end
end
return
tree
end
function
parse_xmlrpc
(
data
)
local
tree
=
{}
local
stack
=
{}
local
tmp
=
{}
local
tmpTag
=
""
local
level
=
0
table.insert
(
stack
,
tree
)
for
op
,
tag
,
p
,
empty
,
val
in
string.gmatch
(
data
,
"<(%/?)([%w:]+)(.-)(%/?)>[%s\r\n\t]*([^<]*)"
)
do
if
op
==
"/"
then
if
tag
==
"member"
or
tag
==
"array"
then
if
level
>
0
then
level
=
level
-
1
table.remove
(
stack
)
end
end
elseif
tag
==
"name"
then
level
=
level
+
1
if
val
~=
""
then
tmpTag
=
vlc
.
strings
.
resolve_xml_special_chars
(
val
)
end
if
type
(
stack
[
level
][
tmpTag
])
==
"nil"
then
stack
[
level
][
tmpTag
]
=
{}
table.insert
(
stack
,
stack
[
level
][
tmpTag
])
else
tmp
=
nil
tmp
=
{}
table.insert
(
stack
[
level
-
1
],
tmp
)
stack
[
level
]
=
nil
stack
[
level
]
=
tmp
table.insert
(
stack
,
tmp
)
end
if
empty
~=
""
then
level
=
level
-
1
stack
[
level
][
tmpTag
]
=
""
table.remove
(
stack
)
end
elseif
tag
==
"array"
then
level
=
level
+
1
tmp
=
nil
tmp
=
{}
table.insert
(
stack
[
level
],
tmp
)
table.insert
(
stack
,
tmp
)
elseif
val
~=
""
then
stack
[
level
][
tmpTag
]
=
vlc
.
strings
.
resolve_xml_special_chars
(
val
)
end
end
return
tree
end
function
dump_xml
(
data
)
local
level
=
0
local
stack
=
{}
local
dump
=
""
local
function
parse
(
data
,
stack
)
for
k
,
v
in
pairs
(
data
)
do
if
type
(
k
)
==
"string"
then
--~ print(k)
dump
=
dump
..
"
\r\n
"
..
string.rep
(
" "
,
level
)
..
"<"
..
k
..
">"
table.insert
(
stack
,
k
)
level
=
level
+
1
elseif
type
(
k
)
==
"number"
and
k
~=
1
then
dump
=
dump
..
"
\r\n
"
..
string.rep
(
" "
,
level
-
1
)
..
"<"
..
stack
[
level
]
..
">"
end
if
type
(
v
)
==
"table"
then
parse
(
v
,
stack
)
elseif
type
(
v
)
==
"string"
then
dump
=
dump
..
vlc
.
strings
.
convert_xml_special_chars
(
v
)
elseif
type
(
v
)
==
"number"
then
dump
=
dump
..
v
end
if
type
(
k
)
==
"string"
then
if
type
(
v
)
==
"table"
then
dump
=
dump
..
"
\r\n
"
..
string.rep
(
" "
,
level
-
1
)
..
"</"
..
k
..
">"
else
dump
=
dump
..
"</"
..
k
..
">"
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
(
" "
,
level
-
1
)
..
"</"
..
stack
[
level
]
..
">"
else
dump
=
dump
..
"</"
..
stack
[
level
]
..
">"
end
end
end
end
parse
(
data
,
stack
)
return
dump
end
function
trim
(
str
)
if
not
str
then
return
""
end
return
string.gsub
(
str
,
"^%s*(.-)%s*$"
,
"%1"
)
end
function
remove_tag
(
str
)
return
string.gsub
(
str
,
"{[^}]+}"
,
""
)
end
languages
=
{
{
'All'
,
'all'
},
{
'Albanian'
,
'alb'
},
{
'Arabic'
,
'ara'
},
{
'Armenian'
,
'arm'
},
{
'Malay'
,
'may'
},
{
'Bosnian'
,
'bos'
},
{
'Bulgarian'
,
'bul'
},
{
'Catalan'
,
'cat'
},
{
'Basque'
,
'eus'
},
{
'Chinese (China)'
,
'chi'
},
{
'Croatian'
,
'hrv'
},
{
'Czech'
,
'cze'
},
{
'Danish'
,
'dan'
},
{
'Dutch'
,
'dut'
},
{
'English (US)'
,
'eng'
},
{
'English (UK)'
,
'bre'
},
{
'Esperanto'
,
'epo'
},
{
'Estonian'
,
'est'
},
{
'Finnish'
,
'fin'
},
{
'French'
,
'fre'
},
{
'Galician'
,
'glg'
},
{
'Georgian'
,
'geo'
},
{
'German'
,
'ger'
},
{
'Greek'
,
'ell'
},
{
'Hebrew'
,
'heb'
},
{
'Hungarian'
,
'hun'
},
{
'Indonesian'
,
'ind'
},
{
'Italian'
,
'ita'
},
{
'Japanese'
,
'jpn'
},
{
'Kazakh'
,
'kaz'
},
{
'Korean'
,
'kor'
},
{
'Latvian'
,
'lav'
},
{
'Lithuanian'
,
'lit'
},
{
'Luxembourgish'
,
'ltz'
},
{
'Macedonian'
,
'mac'
},
{
'Norwegian'
,
'nor'
},
{
'Persian'
,
'per'
},
{
'Polish'
,
'pol'
},
{
'Portuguese (Portugal)'
,
'por'
},
{
'Portuguese (Brazil)'
,
'pob'
},
{
'Romanian'
,
'rum'
},
{
'Russian'
,
'rus'
},
{
'Serbian'
,
'scc'
},
{
'Slovak'
,
'slo'
},
{
'Slovenian'
,
'slv'
},
{
'Spanish (Spain)'
,
'spa'
},
{
'Swedish'
,
'swe'
},
{
'Thai'
,
'tha'
},
{
'Turkish'
,
'tur'
},
{
'Ukrainian'
,
'ukr'
},
{
'Vietnamese'
,
'vie'
}
}
methods
=
{
{
"Video hash"
,
"hash"
},
{
"IMDB ID"
,
"imdb"
}
}
interface
=
{
{
id
=
"header"
,
type
=
"div"
,
content
=
{
{
{
type
=
"label"
,
value
=
"Search method:"
},
{
type
=
"dropdown"
,
value
=
methods
,
id
=
"method"
,
width
=
2
},
{
type
=
"button"
,
value
=
"Go"
,
callback
=
set_interface
}
},
{
{
type
=
"label"
,
value
=
"Language:"
},
{
type
=
"dropdown"
,
value
=
languages
,
id
=
"language"
,
width
=
2
}
}
}
},
{
id
=
"hash"
,
type
=
"div"
,
display
=
"none"
,
content
=
{
{
{
type
=
"list"
,
width
=
4
,
id
=
"hashmainlist"
}
},{
{
type
=
"span"
,
width
=
2
},
{
type
=
"button"
,
value
=
"Ok"
,
callback
=
searchHash
},
{
type
=
"button"
,
value
=
"Close"
,
callback
=
close
}
}
}
},
{
id
=
"imdb"
,
type
=
"div"
,
display
=
"none"
,
content
=
{
{
{
type
=
"label"
,
value
=
"Title:"
},
{
type
=
"text_input"
,
value
=
openSub
.
movie
.
name
or
""
,
id
=
"title"
}
},{
{
type
=
"label"
,
value
=
"Season (series):"
},
{
type
=
"text_input"
,
value
=
openSub
.
movie
.
seasonNumber
or
""
,
id
=
"season"
}
},{
{
type
=
"label"
,
value
=
"Episode (series):"
},
{
type
=
"text_input"
,
value
=
openSub
.
movie
.
episodeNumber
or
""
,
id
=
"episode"
},
{
type
=
"button"
,
value
=
"Ok"
,
callback
=
searchIMBD
},
{
type
=
"button"
,
value
=
"Close"
,
callback
=
close
}
},{
{
type
=
"list"
,
width
=
4
,
id
=
"imdbmainlist"
}
}
}
},
{
id
=
"progressBar"
,
type
=
"div"
,
content
=
{
{
{
type
=
"label"
,
width
=
4
,
value
=
"Powered by <a href='http://www.opensubtitles.org/'>opensubtitles.org</a>"
,
id
=
"message"
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment