webif/webif/lib/epg.class

572 lines
12 KiB
Tcl

source /mod/webif/lib/setup
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
require settings.class progressbar rsv.class mwildcard svc.class
set ::epgpath /mnt/hd1/dvbepg/epg.dat
set ::epgdbpath /mnt/hd1/epg.db
set ::hdepgpath /media/drive1/epgsavedata
if {![file exists $::epgpath] && [file exists $::hdepgpath]} {
set ::epgpath $::hdepgpath
set ::epgdbpath /media/drive1/epg.db
}
set ::channeldb 0
set ::qepg 0
catch { set ::channeldb [sqlite3.open /var/lib/humaxtv/channel.db] }
if {[file exists $::epgdbpath]} {
$::channeldb query {attach database '%s' as epg} $::epgdbpath
set ::qepg 1
}
# Maps the top nibble of descriptor 84 (content_type) to a description and
# icon.
set ::epg::genrelist {
0 { Unclassified Unclassified }
1 { Film Movie }
2 { "News & Factual" News }
3 { Entertainment Show }
4 { Sport Sports }
5 { Children Children }
6 { Entertainment Music }
7 { Art Art }
8 { Society Society }
9 { Education Education }
10 { Lifestyle Leisure }
11 { Unknown Unclassified }
12 { Unknown Unclassified }
13 { Unknown Unclassified }
14 { Unknown Unclassified }
15 { Drama Show }
}
# * service_id, event_id, start, duration, encrypted, name, text
# * warning, content code, content type,
# * event CRID, series CRID, rec CRID, warning mode
class epg {
service_id 0
event_id 0
start 0
duration 0
encrypted 0
name ""
text ""
warning ""
warning_mode 0
content_code 0
content_type ""
event_crid ""
series_crid ""
rec_crid ""
channel 0
channel_num 0
channel_name ""
channel_crid ""
channel_hsvc 0
content_mgmt 0
sched_type -1
rsv 0
}
epg method _parse {line} {
lassign [split $line "\t"] \
service_id event_id start duration encrypted name text warning \
content_code content_type event_crid series_crid rec_crid \
warning_mode content_mgmt
}
epg method percent {} {
set now [clock seconds]
if {$start > $now} { return 0 }
if {$start + $duration < $now} { return 100 }
return [expr [expr $now - $start] * 100 / $duration]
}
epg method showing {} {
set now [clock seconds]
if {$start > $now} { return 0 }
if {$start + $duration < $now} { return 0 }
return 1
}
epg method ended {} {
if {$start + $duration < [clock seconds]} { return 1 }
return 0
}
epg method not_started {} {
if {$start > [clock seconds]} { return 1 }
return 0
}
epg method elapsed {} {
set percent [$self percent]
if {$percent == 0} { return 0 }
if {$percent == 100} { return $duration }
return [expr $duration * $percent / 100]
}
epg method remaining {} {
return [expr $duration - [$self elapsed]]
}
epg method end {} {
return $($start + $duration)
}
epg method type_icon {} {
set img ""
if {[dict exists $::epg::genrelist $content_code]} {
lassign $::epg::genrelist($content_code) x img
}
if {$img != "" && $img ne "Unclassified"} {
return "/images/173_3_00_G3_$img.png"
} else {
return ""
}
}
proc {epg channeliconpath} {name} {
return "/img/channels/out/$name.png"
}
proc {epg channelicon} {name {width 0} {style ""}} {
set str "<img src=\"/img/channels/out/$name.png\"";
if {$width > 0} { append str " width=$width" }
if {$style ne ""} { append str " style=\"$style\"" }
append str " alt=\"\">"
return $str
}
epg method channel_icon {{width 0} {style ""}} {
set str "<img src=\"/img/channels/out/$channel_name.png\"";
if {$width > 0} { append str " width=$width" }
if {$style ne ""} { append str " style=\"$style\"" }
append str " alt=\"\">"
return $str
}
epg method get_channel_info {} {
if {$channel_num > 0} return
set channel [svc load usSvcId $service_id]
if {$channel != 0} {
set channel_num [$channel get usLcn]
set channel_name [$channel get szSvcName]
set channel_crid [$channel get aucDefaultAuthority]
set channel_hsvc [$channel get hSvc]
}
}
epg method copy_channel_info {s} {
set channel [$s get channel]
set channel_num [$s get channel_num]
set channel_name [$s get channel_name]
set channel_crid [$s get channel_crid]
set channel_hsvc [$s get channel_hsvc]
}
epg method get_rsv {} {
$self get_channel_info
if {$channel == 0} return
if {$rsv == 0 && $event_crid ne ""} {
set rsv [rsv entry $event_crid $channel_hsvc]
}
if {$rsv == 0 && $series_crid ne ""} {
set rsv [rsv entry $series_crid $channel_hsvc]
}
}
epg method process_sched {{debug 0}} {
$self scheduled $debug
}
set rsvlookup ""
epg method scheduled {{debug 0}} {
global rsvlookup
if {$sched_type >= 0} { return $sched_type }
set sched_type 0
if {$rsvlookup eq ""} {
set st [clock milliseconds]
set rsvlookup [rsv lookuptab]
if {$debug} {
puts "mS $([clock milliseconds] - $st) --- $rsvlookup"
}
}
set p 0
foreach key [list \
"$service_id:$event_id" \
"$channel_hsvc:$event_id" \
[string tolower "$service_id:$channel_crid$series_crid"] \
[string tolower "$channel_crid$series_crid:$channel_crid$event_crid"] \
] {
if {$debug} { puts "Check key ($key)" }
if {[dict exists $rsvlookup $key]} {
set p $rsvlookup($key)
if {$debug} {puts "FOUND ($p)"}
break
}
}
switch $p {
S { set sched_type 2 }
E { set sched_type 1 }
R { set sched_type 3 }
X { set sched_type 4 }
default { set sched_type 0 }
}
if {$debug} { puts "SCHED_TYPE: ($sched_type)" }
return $sched_type
}
proc {epg update_lookup_tab} {svcid evtid {add true} {type "S"}} {
global rsvlookup
# Update the reservations look up table (if present) with single entry
if {$rsvlookup == ""} return
set key $svcid:$evtid
if {$add} {
# add new entry
dict set rsvlookup $key $type
} else {
# remove existing entry
if {[dict exists $rsvlookup $key]} {
dict unset rsvlookup $key
}
}
#puts "$svcid:$evtid $add $type == $rsvlookup"
}
epg method icon_set {{height 0}} {
if {$height > 0} { set height "height=$height" } else { set height "" }
set icon [$self type_icon]
set set ""
if {$icon != ""} {
lappend set "<img class=genre src=$icon $height
alt=\"$content_type\" title=\"$content_type\">"
}
if {$warning ne ""} {
if {$warning_mode} {
set icon "Guidance_red"
} else {
set icon "Guidance_blue"
}
lappend set "<img class=guidance src=/img/$icon.png $height
alt=Guidance title=Guidance>"
}
$self process_sched
if {$sched_type == 1} {
lappend set \
"<img src=/images/175_1_11_Reservation_Record.png $height>"
}
if {$sched_type == 2} {
lappend set \
"<img src=/images/175_1_11_Series_Record.png $height>"
} elseif {$series_crid ne ""} {
lappend set \
"<img src=/images/178_1_00_Icon_Serise.png $height>"
}
if {$rec_crid ne ""} {
lappend set \
"<img src=/images/178_1_26_Icon_Recommend.png $height>"
}
if {[string match {/*#*} $event_crid]} {
lappend set \
"<img src=/images/178_1_26_Icon_Split.png $height>"
}
if {$content_mgmt eq "1"} {
lappend set \
"<img class=epgenc src=/images/749_1_26_Video_Encryption.png $height>"
}
return $set
}
epg method cell {} {
set percent [$self percent]
puts "<td nowrap valign=top>"
puts [join [$self icon_set 14] ""]
if {$series_crid ne ""} {
set recopts 2
} else {
set recopts 1
}
puts "
<a class=event href=# xs=$service_id xe=$event_id
sch=$sched_type rec=$recopts>
$name</a>
"
puts "<br>"
puts "<font class=footnote>"
puts "[clock format $start -format %H:%M]"
puts " ([clock format $duration -format %T])"
if {$percent > 0 && $percent < 100} {
puts "<br>[progressbar $percent]"
puts "$percent% [clock format [$self elapsed] -format %T] /
[clock format [$self remaining] -format %T]"
}
puts "</font>"
puts "</td>"
}
epg method next {} {
set tm $($start + $duration + 60)
set nextlist [epg dbfetch dump -service $service_id -time $tm]
if {[llength nextlist] > 0} {
return [lindex $nextlist 0]
} else {
return ""
}
}
epg method previous {} {
set tm $($start - 60)
set prevlist [epg dbfetch dump -service $service_id -time $tm]
if {[llength prevlist] > 0} {
return [lindex $prevlist 0]
} else {
return ""
}
}
epg method recommended {} {
set rec ""
if {$rec_crid ne ""} {
catch { set rec [lindex [
epg dbfetch dump -crid $rec_crid] 0] }
}
return $rec
}
epg method othertimes {} {
if {$event_crid eq ""} { return "" }
set others ""
foreach other [epg dbfetch dump -crid $event_crid] {
if {[$other get service_id] == $service_id &&
[$other get event_id] == $event_id} { continue }
lappend others $other
}
return $others
}
proc {epg parse} {line} {
set e [epg new]
$e _parse $line
return $e
}
proc {epg cleanup} {} {
global channeldb
if {$channeldb != ""} { $channeldb close }
}
proc {epg exec} {mode args} {
set raw 0
set cmd [list /mod/bin/epg -f $::epgpath]
set extra ""
foreach arg $args {
if {[string first "-" $arg] == 0} {
switch -- $arg {
-raw { set raw 1 }
-crid { lappend cmd -C $args($arg) }
-scrid { lappend cmd -R $args($arg) }
-type { lappend cmd -T $args($arg) }
-service { lappend cmd -S $args($arg) }
-event { lappend cmd -E $args($arg) }
-time { lappend cmd -@ $args($arg) }
-trange { lappend cmd -= $args($arg) }
-day { lappend cmd -/ $args($arg) }
-extra { set extra $args($arg) }
default { error "Invalid option, $arg" }
}
}
}
if { $raw == 0 } { lappend cmd -p }
lappend cmd $mode
lappend cmd $extra
#puts "CMD -$cmd-"
return [exec {*}$cmd]
}
proc {epg dbfetch} {mode args} {
set records {}
set extra ""
set params {}
set debug 0
set select "
select distinct *,
usLcn as channel_num,
substr(szSvcName, 2) as channel_name,
aucDefaultAuthority as channel_crid,
hSvc as channel_hsvc
"
set from "
from epg.epg e join TBL_SVC c
on e.service_id = c.usSvcId
"
set q "where 1 "
set sort "order by channel_num, start"
foreach arg $args {
if {[string first "-" $arg] == 0} {
set v $args($arg)
switch -- $arg {
-debug { set debug $v }
-ljoin {
set from "
from TBL_SVC c left join epg.epg e
on e.service_id = c.usSvcId
"
}
-crid { append q \
"and e.event_crid = '$v' collate nocase " }
-scrid { append q \
"and e.series_crid = '$v' collate nocase " }
-type { append q \
"and e.content_code = $v " }
-service { append q \
"and e.service_id = $v " }
-event { append q \
"and e.event_id = $v " }
-time { append q \
"and e.start < $v and e.end > $v " }
-after { append q \
"and e.end >= $v " }
-before { append q \
"and e.start < $v " }
-sort {
if {$v eq ""} {
set sort ""
} else {
set sort "order by $v"
}
}
-trange {
lassign [split $v :] stt ett
append q "and (e.start is null or
(e.start > $stt and e.start < $ett) or
(e.end > $stt and e.end < $ett) or
(e.start <= $stt and e.end >= $ett)
) "
}
-fav {
set v $(1 << ($v - 1))
append from \
"join TBL_FAV f using(hSvc) "
append q "and f.eFavGroup = $v "
set sort "order by f.favIdx, start"
}
-term {
set v [mwildcard $v]
append q "and ("
append q "e.name like '%s' "
lappend params "%$v%"
if {$mode eq "searchall"} {
append q \
"or e.text like '%s' "
lappend params "%$v%"
}
append q ") "
}
-param { lappend params $v }
-nocase { append q "collate nocase " }
default { error "Invalid option, $arg" }
}
}
}
set query "$select $from $q $sort"
if {$debug} {
puts "QUERY -$query-"
puts "PARAMS -$params-"
}
set records {}
if {[catch {
foreach rec [$::channeldb query $query {*}$params] {
lappend records [epg new $rec]
}
} msg]} {
puts "No cached EPG data, try again later ($msg)."
}
return $records
}
# This function is deprecated in favour of {epg dbfetch} and should not be
# used.
proc {epg fetch} {mode args} {
set records ""
foreach line [split [epg exec $mode {*}$args] "\n"] {
lappend records [epg parse $line]
}
return $records
}
proc {epg favlist} {} {
global channeldb
set num $(1 << ([[settings] channel_group] - 1))
if {!$num} { return "" }
return [lmap i [$channeldb query "
select TBL_SVC.usSvcid
from TBL_SVC join TBL_FAV
using(hSvc)
where TBL_FAV.eFavGroup == $num
order by TBL_FAV.favIdx
"] { lindex $i end }]
}
proc {epg channellist} {{field usLcn}} {
global channeldb
set channels {}
lmap i [$channeldb query "
select $field, szSvcName
from TBL_SVC
order by 1
"] { lappend channels [list \
[string range [lindex $i 3] 1 end] [lindex $i 1] ] }
return $channels
}