427 lines
9.4 KiB
Tcl
427 lines
9.4 KiB
Tcl
source /mod/webif/lib/setup
|
|
|
|
package require cgi
|
|
if {![exists -command class]} { package require oo }
|
|
if {![exists -command sqlite3.open]} { package require sqlite3 }
|
|
require system.class xml.class
|
|
|
|
set ::tvdb::apikey 1764335F804A5A91
|
|
set ::tvdb::mirror "thetvdb.com"
|
|
set ::tvdb::artwork "artworks.thetvdb.com"
|
|
set ::tvdb::cache "/mod/var/tvdb"
|
|
set ::tvdb::icache "/mod/webif/cache/tvdb/img"
|
|
set ::tvdb::cacheage 86400
|
|
set ::tvdb::debug 0
|
|
|
|
if {![file isdirectory $::tvdb::cache]} {
|
|
file mkdir $::tvdb::cache
|
|
}
|
|
|
|
if {![file isdirectory $::tvdb::icache]} {
|
|
system mkdir_p $::tvdb::icache
|
|
}
|
|
|
|
set ::tvdb::indexdb [sqlite3.open "$::tvdb::cache/series.db"]
|
|
|
|
$::tvdb::indexdb query {
|
|
create table if not exists nseries(
|
|
[name] text primary key
|
|
)
|
|
}
|
|
|
|
class tvdb {
|
|
seriesid 0
|
|
imdb_id ""
|
|
name ""
|
|
overview ""
|
|
dat ""
|
|
banner ""
|
|
|
|
_matches {}
|
|
_smatches {}
|
|
_phrases {}
|
|
}
|
|
|
|
proc ::tvdb::dlog {msg} {
|
|
if {$::tvdb::debug} {
|
|
puts $msg
|
|
}
|
|
}
|
|
|
|
tvdb method setseries {sid} {
|
|
set seriesid $sid
|
|
}
|
|
|
|
#tvdb method _fetch {url} {
|
|
# set f [socket stream "${::tvdb::mirror}:443"]
|
|
# $f ssl
|
|
# $f puts -nonewline "GET $url HTTP/1.1\r\n"
|
|
# $f puts -nonewline "Host: $::tvdb::mirror\r\n"
|
|
# $f puts -nonewline "Connection: close\r\n"
|
|
# $f puts -nonewline "\r\n"
|
|
#
|
|
# set line [string trim [$f gets]]
|
|
# while {[string length $line]} {
|
|
# #puts "Web Header: $line"
|
|
# set line [string trim [$f gets]]
|
|
# }
|
|
#
|
|
# # Save the body
|
|
# set ret [$f read]
|
|
# $f close
|
|
# return $ret
|
|
#}
|
|
|
|
proc {tvdb fetchfile} {url} {
|
|
set cmd {wget -q -4 -O-}
|
|
lappend cmd $url
|
|
::tvdb::dlog "Executing $cmd"
|
|
return [exec {*}$cmd]
|
|
}
|
|
|
|
tvdb method _fetch {path} {
|
|
return [tvdb fetchfile "https://$::tvdb::mirror$path"]
|
|
}
|
|
|
|
tvdb method _parse {xml vars {end "XX"}} {
|
|
set x [xml init $xml]
|
|
set cattr 0
|
|
while {1} {
|
|
lassign [$x next] type val attr etype
|
|
if {$type == "EOF"} break
|
|
switch $etype {
|
|
START { set cattr $val }
|
|
END {
|
|
if {$val == $end} break
|
|
set cattr 0
|
|
}
|
|
default {
|
|
if {$type == "TXT"} {
|
|
if {$cattr in $vars} {
|
|
set $cattr $val
|
|
}
|
|
::tvdb::dlog "$cattr - $val"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#<Series>
|
|
#<seriesid>261451</seriesid>
|
|
#<language>en</language>
|
|
#<SeriesName>Teenage Mutant Ninja Turtles (2012)</SeriesName>
|
|
#<banner>graphical/261451-g2.jpg</banner>
|
|
#<Overview>Four ninja turtles, mutated by a mysterious alien substance, must rise up out of the sewers and defend their city against evil forces from both the past and present.</Overview>
|
|
#<FirstAired>2012-09-29</FirstAired>
|
|
#<Network>Nickelodeon</Network>
|
|
#<id>261451</id>
|
|
#</Series>
|
|
|
|
tvdb method _extract {xml end vars} {
|
|
set x [xml init $xml]
|
|
set cattr 0
|
|
set ret {}
|
|
set attrs {}
|
|
while {1} {
|
|
lassign [$x next] type val attr etype
|
|
if {$type == "EOF"} break
|
|
switch $etype {
|
|
START {
|
|
set cattr $val
|
|
}
|
|
END {
|
|
if {$val == $end} {
|
|
lappend ret $attrs
|
|
set attrs {}
|
|
}
|
|
set cattr 0
|
|
}
|
|
default {
|
|
if {$type == "TXT"} {
|
|
if {$cattr in $vars} {
|
|
set attrs([\
|
|
string tolower $cattr]) $val
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $ret
|
|
}
|
|
|
|
tvdb method fetchseries {} {
|
|
if {!$seriesid} return
|
|
set base "$::tvdb::cache/$seriesid"
|
|
# Expire old files
|
|
if {[file exists "$base.xml"]} {
|
|
set age $([clock seconds] - [file mtime "$base.xml"])
|
|
::tvdb::dlog "$base.xml age $age"
|
|
if {$age > $::tvdb::cacheage} {
|
|
file delete "$base.xml"
|
|
::tvdb::dlog "Expiring $base.xml"
|
|
}
|
|
}
|
|
|
|
if {![file exists "$base.xml"]} {
|
|
::tvdb::dlog "Downloading"
|
|
# Download the series info
|
|
set f [open "$base.zip" w]
|
|
puts $f [$self _fetch \
|
|
"/api/$::tvdb::apikey/series/$seriesid/all/en.zip"]
|
|
$f close
|
|
catch {exec /mod/bin/unzip -o -q "$base.zip" en.xml -d $::tvdb::cache}
|
|
if {[file exists "$::tvdb::cache/en.xml"]} {
|
|
file rename "$::tvdb::cache/en.xml" $base.xml
|
|
# Extract episode info
|
|
puts [exec /mod/webif/lib/bin/tvdb "$base.xml"]
|
|
}
|
|
}
|
|
}
|
|
|
|
tvdb method loadseries {} {
|
|
if {!$seriesid} return
|
|
set ret [$::tvdb::indexdb query {
|
|
select * from series where series_id = %s} $seriesid]
|
|
if {[llength $ret] == 1} {
|
|
foreach {k v} [lindex $ret 0] {
|
|
set $k $v
|
|
}
|
|
}
|
|
}
|
|
|
|
tvdb method searchseries {series} {
|
|
::tvdb::dlog "Searching TVDB for $series"
|
|
set seriesxml [$self _fetch \
|
|
"/api/GetSeries.php?seriesname=[cgi_quote_url $series]"]
|
|
return [$self _extract $seriesxml Series \
|
|
{seriesid SeriesName banner Overview}]
|
|
}
|
|
|
|
tvdb method findseries {series} {
|
|
set ret ""
|
|
catch {
|
|
set ret [$::tvdb::indexdb query {
|
|
select series_id from series where name = '%s'
|
|
} $series]
|
|
}
|
|
if {[llength $ret]} {
|
|
lassign [lindex $ret 0] x seriesid
|
|
::tvdb::dlog "Cached ID for '$series' = $seriesid"
|
|
}
|
|
if {!$seriesid} {
|
|
# Attempt to determine series ID
|
|
|
|
::tvdb::dlog "Trying to find series in TVDB"
|
|
set seriesxml [$self _fetch \
|
|
"/api/GetSeries.php?seriesname=[cgi_quote_url $series]"]
|
|
$self _parse $seriesxml {seriesid} Series
|
|
}
|
|
|
|
if {!$seriesid} {
|
|
# Negative caching
|
|
$::tvdb::indexdb query {
|
|
replace into nseries values('%s')
|
|
} $series
|
|
}
|
|
}
|
|
|
|
tvdb method dbhandle {} {
|
|
if {![file exists "$::tvdb::cache/$seriesid.db"]} { return {} }
|
|
set db [sqlite3.open "$::tvdb::cache/$seriesid.db"]
|
|
return $db
|
|
}
|
|
|
|
proc {tvdb tolike} {str {extra ""}} {
|
|
set map {" and " "%" " the " "%"}
|
|
if {[llength $extra]} { lappend map {*}$extra }
|
|
return "%[string map $map $str]%"
|
|
}
|
|
|
|
tvdb method episodebynum {series episode} {
|
|
if {![llength [set db [$self dbhandle]]]} return {}
|
|
set ret [$db query {
|
|
select * from episode where series = %s and episode = %s
|
|
} $series $episode]
|
|
if {[llength $ret]} { return [lindex $ret 0] }
|
|
return {}
|
|
}
|
|
|
|
tvdb method episodebyname {str {series 0} {episode 0}} {
|
|
if {![llength [set db [$self dbhandle]]]} return {}
|
|
|
|
set q "select * from episode where name like '%s'"
|
|
if {$series} { append q " and series = $series" }
|
|
if {$episode} { append q " and episode = $episode" }
|
|
append q " order by length(name) desc"
|
|
set ret [$db query $q [tvdb tolike $str]]
|
|
if {[llength $ret]} { return [lindex $ret 0] }
|
|
|
|
# Try a match with all spaces removed
|
|
set q "select * from episode where replace(name, ' ', '') like '%s'"
|
|
if {$series} { append q " and series = $series" }
|
|
if {$episode} { append q " and episode = $episode" }
|
|
append q " order by length(name) desc"
|
|
set ret [$db query $q [tvdb tolike $str {" " ""}]]
|
|
if {[llength $ret]} { return [lindex $ret 0] }
|
|
|
|
return {}
|
|
}
|
|
|
|
tvdb method wordcount {db words extra} {
|
|
set _matches {}
|
|
|
|
loop i 5 1 -1 {
|
|
#puts "Trying phrases of length $i<br>"
|
|
set wlen $([llength $words] - $i - 1)
|
|
for {set a 0} {$a < $wlen} {incr a} {
|
|
set w [lrange $words $a $($a + $i - 1)]
|
|
#puts "Phrase: $w<br>"
|
|
|
|
set ret [$db query {
|
|
select episode_id,
|
|
case
|
|
when name like '%%%s%%' then 1
|
|
else 0
|
|
end as inname
|
|
from episode
|
|
where overview like '%%%s%%'
|
|
or name like '%%%s%%'
|
|
%s
|
|
} $w $w $w $extra]
|
|
foreach row $ret {
|
|
#puts " > FOUND: ($w)<br>"
|
|
ladd _phrases $w
|
|
lassign $row x id x inname
|
|
if {$inname eq "1"} {
|
|
# If found in name then score is 10x
|
|
# phrase length
|
|
incr _matches($id) $($i * 10)
|
|
} else {
|
|
# Score is twice phrase length
|
|
incr _matches($id) $($i * 2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tvdb method seek {synopsis {extra ""}} {
|
|
if {![llength [set db [$self dbhandle]]]} return {}
|
|
|
|
set words [split $synopsis " "]
|
|
|
|
# Count phrase occurence
|
|
$self wordcount $db $words $extra
|
|
|
|
if {![llength $_matches]} {
|
|
return {}
|
|
}
|
|
|
|
# Find best match
|
|
set _smatches [lsort -integer -decreasing -index end [\
|
|
lmap {k v} $_matches {
|
|
list $k $v
|
|
}]]
|
|
|
|
set eid [lindex [lindex $_smatches 0] 0]
|
|
|
|
set ret [$db query {
|
|
select * from episode where episode_id = %s
|
|
} $eid]
|
|
if {[llength $ret]} { return [lindex $ret 0] }
|
|
|
|
return {}
|
|
}
|
|
|
|
tvdb method episodebyid {episode_id} {
|
|
if {![llength [set db [$self dbhandle]]]} return {}
|
|
set ret [$db query {
|
|
select * from episode where episode_id = %s
|
|
} $episode_id]
|
|
if {[llength $ret]} { return [lindex $ret 0] }
|
|
return {}
|
|
}
|
|
|
|
tvdb method episodebyepnum {episode synopsis} {
|
|
return [$self seek $synopsis "and episode = $episode"]
|
|
}
|
|
|
|
tvdb method episodebyseries {series synopsis} {
|
|
return [$self seek $synopsis "and series = $series"]
|
|
}
|
|
|
|
tvdb method episodebysynopsis {synopsis} {
|
|
return [$self seek $synopsis]
|
|
}
|
|
|
|
tvdb method episodesearch {search} {
|
|
if {![llength [set db [$self dbhandle]]]} return {}
|
|
set ret [$db query {
|
|
select episode_id,
|
|
case
|
|
when name like '%%%s%%' then 1
|
|
else 0
|
|
end as inname
|
|
from episode
|
|
where overview like '%%%s%%'
|
|
or name like '%%%s%%'
|
|
} $search $search $search]
|
|
return $ret
|
|
}
|
|
|
|
tvdb method series_count {} {
|
|
if {![llength [set db [$self dbhandle]]]} { return 0 }
|
|
|
|
set ret [$db query {
|
|
select max(series) from episode
|
|
}]
|
|
set num 0
|
|
if {[llength $ret]} {
|
|
lassign [lindex $ret 0] x num
|
|
}
|
|
return $num
|
|
}
|
|
|
|
proc {tvdb series} {series {sid 0}} {
|
|
set t [tvdb]
|
|
|
|
if {$sid} {
|
|
$t setseries $sid
|
|
} else {
|
|
$t findseries $series
|
|
}
|
|
if {[$t get seriesid] ne "0"} {
|
|
$t fetchseries
|
|
$t loadseries
|
|
if {[$t get name] eq ""} {
|
|
$t setseries 0
|
|
}
|
|
}
|
|
return $t
|
|
}
|
|
|
|
proc {tvdb cachebanner} {banner} {
|
|
if {![string match {/banners/*} $banner]} {
|
|
set _banner "/banners/$banner"
|
|
} else {
|
|
set _banner $banner
|
|
}
|
|
if {![file exists "$::tvdb::icache/$banner"]} {
|
|
set ret [tvdb fetchfile "https://$::tvdb::artwork$_banner"]
|
|
if {[string length $ret] > 50} {
|
|
system mkdir_p "$::tvdb::icache/[file dirname $banner]"
|
|
file write "$::tvdb::icache/$banner" $ret
|
|
}
|
|
}
|
|
}
|
|
|
|
proc {tvdb bannerurl} {banner} {
|
|
return "/cgi-bin/tvdbimg.jim?file=[cgi_quote_url $banner]"
|
|
}
|
|
|
|
proc {tvdb seriesurl} {seriesid} {
|
|
return "https://$::tvdb::mirror/?tab=series&id=$seriesid"
|
|
}
|
|
|