Should fix `modinit.log` error report: ```in procedure 'rsv' called at file "/mod/sbin/autoschedule", line 22 at file "/mod/webif/lib/rsv.class", line 1374```
1726 lines
38 KiB
Tcl
1726 lines
38 KiB
Tcl
source /mod/webif/lib/setup
|
|
|
|
if {![exists -proc class]} { package require oo }
|
|
if {![exists -proc sqlite3.open]} { package require sqlite3 }
|
|
if {![exists -proc binary]} { package require binary }
|
|
require settings.class system.class plugin svc.class
|
|
|
|
set binaryfields aulEventToRecordInfo
|
|
|
|
class rsv {
|
|
ulslot -1
|
|
ersvtype 0
|
|
hsvc 0
|
|
nsttime 0
|
|
szsttime "00000000000000"
|
|
nduration 0
|
|
erepeat 0
|
|
usevtid 0
|
|
szevtname {}
|
|
ulPreOffset 0
|
|
ulPostOffset 0
|
|
ulProgramId 0
|
|
ulSeriesId 0
|
|
ucVolume 0
|
|
ucInputMode 0
|
|
usChNum 0
|
|
ucRecKind 0
|
|
ucCRIDType 0
|
|
szCRID {}
|
|
szFPBRecPath {}
|
|
szRecordedProgCrid {}
|
|
szEventToRecord {}
|
|
aulEventToRecordInfo {}
|
|
bRecomRsv 0
|
|
usLastRecordedEvtId 0
|
|
eReady 0
|
|
szSvcName {}
|
|
usLcn 0
|
|
sort 0
|
|
action 0
|
|
_table ""
|
|
_origstart 0
|
|
}
|
|
|
|
proc {rsv dbhandle} {args} {
|
|
|
|
if {"-close" in $args} {
|
|
if {[info exists ::rsv::db]} {
|
|
catch {$::rsv::db close}
|
|
unset ::rsv::db
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
if {[info exists ::rsv::db]} {
|
|
return $::rsv::db
|
|
}
|
|
|
|
set ::rsv::db [sqlite3.open /var/lib/humaxtv/rsv.db]
|
|
$::rsv::db query {attach database '/var/lib/humaxtv/channel.db' as channel}
|
|
|
|
if {![file exists /var/lib/humaxtv/rsvp.db]} {
|
|
file copy /var/lib/humaxtv/rsv.db /var/lib/humaxtv/rsvp.db
|
|
set tdb [sqlite3.open /var/lib/humaxtv/rsvp.db]
|
|
$tdb query {drop table TBL_VERSION}
|
|
$tdb query {alter table TBL_RESERVATION rename to pending}
|
|
$tdb query {alter table pending add column action int}
|
|
$tdb query {delete from pending}
|
|
$tdb close
|
|
}
|
|
$::rsv::db query {attach database '/var/lib/humaxtv/rsvp.db' as pending}
|
|
# These are required to upgrade old tables.
|
|
catch { $::rsv::db query { alter table pending add column action int} }
|
|
# Add the skip table if missing
|
|
catch { $::rsv::db query {
|
|
create table if not exists pending.skip
|
|
(
|
|
ulslot int,
|
|
state text,
|
|
service_id int,
|
|
event_id int,
|
|
hSvc int,
|
|
start int,
|
|
ucCRIDType int,
|
|
szCRID text,
|
|
szSkipCRID text
|
|
);
|
|
}}
|
|
catch { $::rsv::db query {
|
|
create unique index pending.skipidx
|
|
on skip(
|
|
ulslot, state, service_id, event_id,
|
|
ucCRIDType, szCRID, szSkipCRID
|
|
);
|
|
} }
|
|
|
|
return $::rsv::db
|
|
}
|
|
|
|
alias {rsv cleanup} rsv dbhandle -close
|
|
|
|
rsv method status {} {
|
|
switch -- [system nugget schedule.timers.status $ulslot] {
|
|
"0,0" { return "idle" }
|
|
"1,1" { return "ready" }
|
|
"2,1" { return "arwatch" }
|
|
"2,2" { return "recording" }
|
|
default { return "unknown" }
|
|
}
|
|
}
|
|
|
|
rsv method aul {{filter false}} {
|
|
set aul {}
|
|
set xaul {}
|
|
if {$filter} { set xaul [$self skiplist] }
|
|
for {set i 0} {$i < [string length $aulEventToRecordInfo]} {
|
|
incr i 16} {
|
|
binary scan [string range $aulEventToRecordInfo $i $($i + 15)]\
|
|
iiii service start end event_id
|
|
if {"$service:$event_id" ni $xaul} {
|
|
catch {lappend aul [list $service $start $end $event_id]}
|
|
}
|
|
}
|
|
return $aul
|
|
}
|
|
|
|
proc {rsv mkaul} {e} {
|
|
$e get_channel_info
|
|
return [binary format iiii \
|
|
[$e get channel_hsvc] \
|
|
[$e get start] \
|
|
[$e end] \
|
|
[$e get event_id] \
|
|
]
|
|
}
|
|
|
|
proc {rsv buildaul} {auls} {
|
|
set newaul {}
|
|
foreach aul $auls {
|
|
lassign $aul _hsvc _start _end _eid
|
|
|
|
append newaul [binary format iiii \
|
|
$_hsvc $_start $_end $_eid]
|
|
}
|
|
return $newaul
|
|
}
|
|
|
|
rsv method setaul {s} {
|
|
set aulEventToRecordInfo $s
|
|
}
|
|
|
|
rsv method clear_ulslot {} {
|
|
set ulslot -1
|
|
}
|
|
|
|
rsv method isseries {} {
|
|
if {$ucRecKind == 4} { return 1 } else { return 0 }
|
|
}
|
|
|
|
rsv method issplit {} {
|
|
if {$ucRecKind == 2} { return 1 } else { return 0 }
|
|
}
|
|
|
|
rsv method _strip {str} {
|
|
return [system strip $str]
|
|
}
|
|
|
|
rsv method folder {} {
|
|
return [$self _strip $szFPBRecPath]
|
|
}
|
|
|
|
rsv method name {} {
|
|
set name [$self _strip $szevtname]
|
|
if {$name == ""} {
|
|
switch $ersvtype {
|
|
1 { set name "--- Unnamed reminder ---" }
|
|
2 { set name "--- Unnamed manual reminder ---" }
|
|
3 { set name "--- Unnamed recording ---" }
|
|
4 { set name "--- Unnamed manual recording ---" }
|
|
5 { set name "--- Wake-up ---" }
|
|
6 { set name "--- Sleep ---" }
|
|
7 { set name "--- Auto Update ---" }
|
|
11 { set name "--- DSO Event ---" }
|
|
default { set name "--- Unknown event type $ersvtype ---" }
|
|
}
|
|
}
|
|
|
|
return $name
|
|
}
|
|
|
|
rsv method padded {{l 0}} {
|
|
if {$ulPreOffset > 0 || $ulPostOffset > 0} {
|
|
if {$l} {
|
|
return [list $ulPreOffset $ulPostOffset]
|
|
} else {
|
|
return 1
|
|
}
|
|
} else {
|
|
if {$l} {
|
|
return {0 0}
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
|
|
rsv method channel_name {} {
|
|
return [string range $szSvcName 1 end]
|
|
}
|
|
|
|
rsv method szsttime_stamp {} {
|
|
set spaced [regsub {^(....)(..)(..)(..)(..)(..).*} \
|
|
$szsttime {\1 \2 \3 \4 \5 \6}]
|
|
|
|
if {[catch {
|
|
set stamp [clock scan $spaced -format "%Y %m %d %H %M %S"]
|
|
}]} {
|
|
return 0
|
|
}
|
|
return $stamp
|
|
}
|
|
|
|
rsv method start {} {
|
|
if {[string range $szsttime 0 3] eq "0000"} { return $nsttime }
|
|
set tm [$self szsttime_stamp]
|
|
if {$tm > 0} { return $tm }
|
|
return $nsttime
|
|
}
|
|
|
|
rsv method end {} {
|
|
return $([$self start] + $nduration)
|
|
}
|
|
|
|
rsv method showing {} {
|
|
set now [clock seconds]
|
|
if {$nsttime - $ulPreOffset <= $now &&
|
|
$nsttime + $nduration + $ulPostOffset >= $now} {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
rsv method icon {} {
|
|
set rsvicon ""
|
|
switch $ersvtype {
|
|
1 -
|
|
2 { set rsvicon "175_1_00_Reservation_Watch.png" }
|
|
3 -
|
|
4 { set rsvicon "175_1_11_Reservation_Record.png" }
|
|
5 { set rsvicon "745_1_10_Video_2Live.png" }
|
|
6 { set rsvicon "745_1_11_Video_1REC.png" }
|
|
7 { set rsvicon "345_6_08_ST_Ad_Hoc.png" }
|
|
}
|
|
return $rsvicon
|
|
}
|
|
|
|
rsv method RKIcon {} {
|
|
switch $ucRecKind {
|
|
2 { set RKIcon "178_1_26_Icon_Split.png" }
|
|
4 { set RKIcon "175_1_11_Series_Record.png" }
|
|
default {
|
|
switch $erepeat {
|
|
1 {set RKIcon "521_1_00_RP_Daily_C.png"}
|
|
2 {set RKIcon "521_1_00_RP_Weekly_C.png"}
|
|
3 {set RKIcon "521_1_00_RP_Weekdays_C.png"}
|
|
4 {set RKIcon "521_1_00_RP_Weekend_C.png"}
|
|
default {set RKIcon ""}
|
|
}
|
|
}
|
|
}
|
|
return $RKIcon
|
|
}
|
|
|
|
rsv method pendingicon {{width 30}} {
|
|
switch $action {
|
|
0 { set icon "add" }
|
|
1 { set icon "close" }
|
|
2 { set icon "ar" }
|
|
3 { set icon "pad" }
|
|
4 { set icon "folder" }
|
|
5 { set icon "skip" }
|
|
6 { set icon "refresh" }
|
|
}
|
|
return "<img class=va width=$width src=/img/$icon.png>"
|
|
}
|
|
|
|
rsv method iconset {{height 20}} {
|
|
set iconlist {}
|
|
set icon [$self icon]
|
|
if {$icon ne ""} {
|
|
lappend iconlist "<img src='/images/$icon' height=$height>"
|
|
if {$ersvtype == 3} {
|
|
if {[$self padded]} {
|
|
set padding "<- [expr $ulPreOffset / 60], [expr $ulPostOffset / 60] ->"
|
|
lappend iconlist \
|
|
"<img src=/img/pad.png height=$height
|
|
title=\"$padding\" alt=\"$padding\">"
|
|
} elseif {[$self status] eq "arwatch"} {
|
|
lappend iconlist \
|
|
"<img src=/img/aractive.gif height=$height>"
|
|
} else {
|
|
lappend iconlist \
|
|
"<img src=/img/ar.png height=$height>"
|
|
}
|
|
}
|
|
}
|
|
set icon [$self RKIcon]
|
|
if {$icon ne ""} {
|
|
lappend iconlist "<img src='/images/$icon' height=$height>"
|
|
}
|
|
return $iconlist
|
|
}
|
|
|
|
rsv method set {ivName val} {
|
|
set $ivName $val
|
|
}
|
|
|
|
rsv method setorigstart {o} {
|
|
set _origstart $o
|
|
}
|
|
|
|
rsv method set_delete {} {
|
|
set action 1
|
|
}
|
|
|
|
rsv method set_unpad {} {
|
|
set action 2
|
|
}
|
|
|
|
rsv method set_folder {name} {
|
|
set action 4
|
|
set szFPBRecPath $name
|
|
}
|
|
|
|
rsv method set_pad {{pre 60} {post 60}} {
|
|
set action 3
|
|
set ulPreOffset $pre
|
|
set ulPostOffset $post
|
|
}
|
|
|
|
rsv method set_refresh {} {
|
|
set action 6
|
|
set aulEventToRecordInfo ""
|
|
}
|
|
|
|
rsv method update_aul {new_event old_aul} {
|
|
# Add new_event (optional) to aulEventToRecordInfo and szEventToRecord
|
|
# remove old_aul (optional) from " "
|
|
# Maintain list in time order
|
|
set curauls [$self aul]
|
|
set ecrids [split $szEventToRecord "|"]
|
|
set evtaul {}
|
|
set insert 1
|
|
set start 0
|
|
# Do we have new event to add?
|
|
if {$new_event != 0 && $new_event !={}} {
|
|
set service_id [$new_event get channel_hsvc]
|
|
set start [$new_event get start]
|
|
set end [$new_event end]
|
|
set evtid [$new_event get event_id]
|
|
set evtaul [list $service_id $start $end $evtid]
|
|
set evtcrid [string toupper
|
|
"1[$new_event get channel_crid][$new_event get event_crid]"]
|
|
set insert 0
|
|
}
|
|
# rebuild aul and events list with new event in correct order
|
|
lmap aul $curauls ecrid $ecrids {
|
|
#puts "$aul $ecrid"
|
|
if {$aul == $old_aul} {continue; #remove current entry}
|
|
if {$aul == ""} {continue; #null entry}
|
|
if {!$insert && $start <= [lindex $aul 1]} {
|
|
set insert 1
|
|
lappend newaul $evtaul
|
|
append newevnts "$evtcrid|"
|
|
}
|
|
lappend newaul $aul
|
|
append newevnts "$ecrid|"
|
|
}
|
|
# add to end if not inserted
|
|
if {!$insert} {
|
|
set insert 1
|
|
lappend newaul $evtaul
|
|
append newevnts "$evtcrid|"
|
|
}
|
|
set action 5
|
|
$self setaul [$self buildaul $newaul]
|
|
set szEventToRecord $newevnts
|
|
}
|
|
|
|
rsv method set_next_event {} {
|
|
# Update reservation next event info in ucVolume
|
|
if {[string length $aulEventToRecordInfo] >0} {
|
|
binary scan [string range $aulEventToRecordInfo 0 15] \
|
|
iiii service_id start end event_id
|
|
set dur $($end-$start)
|
|
if {$hsvc != $service_id ||
|
|
$nsttime != $start ||
|
|
$nduration != $dur ||
|
|
$usevtid != $event_id} {
|
|
set nduration $dur
|
|
set ucVolume "$service_id:$event_id:$start"
|
|
}
|
|
} else {
|
|
# The next event is not yet in the EPG
|
|
set time $([clock seconds] - 86400)
|
|
set ucVolume "$hsvc:$usLastRecordedEvtId:$time"
|
|
}
|
|
}
|
|
|
|
rsv method reset_next_event {} {
|
|
# Ensure our copy matches the updated reservation
|
|
if {$ucVolume != 0} {
|
|
lassign [split $ucVolume ":"] service_id event_id start
|
|
set hsvc $service_id
|
|
set nsttime $start
|
|
set usevtid $event_id
|
|
set ucVolume 0
|
|
}
|
|
}
|
|
|
|
rsv method set_skip {event} {
|
|
set action 5
|
|
|
|
$event get_channel_info
|
|
|
|
set event_hsvc [$event get channel_hsvc]
|
|
set service_id [$event get service_id]
|
|
set event_id [$event get event_id]
|
|
|
|
set crid [string toupper \
|
|
"[$event get channel_crid][$event get event_crid]"]
|
|
|
|
if {"1$crid" ni [split $szRecordedProgCrid "|"]} {
|
|
set szRecordedProgCrid "1$crid|$szRecordedProgCrid"
|
|
}
|
|
set szEventToRecord [string map "1$crid| {}" $szEventToRecord]
|
|
catch {
|
|
[rsv dbhandle] query {
|
|
insert or ignore into skip
|
|
(ulslot, state, ucCRIDType, szCRID, szSkipCRID,
|
|
service_id, event_id, start, hSvc)
|
|
values('%s', 'pending', '%s', '%s', '%s', %s, %s,
|
|
%s, %s)
|
|
} -1 $ucCRIDType $szCRID $crid $service_id $event_id [\
|
|
$event get start] $event_hsvc
|
|
}
|
|
|
|
set newaul ""
|
|
set next_event -1
|
|
foreach aul [$self aul] {
|
|
lassign $aul _hsvc _start _end _eid
|
|
|
|
if {$_hsvc == $event_hsvc && $_eid == $event_id} continue
|
|
|
|
# Track the next event which should be recorded.
|
|
if {$next_event == -1} {
|
|
set next_event $_eid
|
|
set next_hsvc $_hsvc
|
|
set next_time $_start
|
|
}
|
|
|
|
append newaul [binary format iiii \
|
|
$_hsvc $_start $_end $_eid]
|
|
}
|
|
set aulEventToRecordInfo $newaul
|
|
|
|
set nsttime [$event get start]
|
|
set nduration [$event get duration]
|
|
|
|
# Handle skipping the next up-coming instance.
|
|
if {$event_id eq $usevtid} {
|
|
# (mis)use some fields to hold the next event which
|
|
# should be recorded.
|
|
if {$next_event == -1} {
|
|
# The next event is not yet in the EPG
|
|
set time $([clock seconds] - 86400)
|
|
set ucVolume "$hsvc:$usLastRecordedEvtId:$time"
|
|
} else {
|
|
set ucVolume "$next_hsvc:$next_event:$next_time"
|
|
}
|
|
}
|
|
}
|
|
|
|
rsv method replace_skip {skiplist {debug false}} {
|
|
set action 5
|
|
|
|
set szRecordedProgCrid "1[join $skiplist |1]|"
|
|
|
|
# Remove episodes to be skipped from both szEventToRecord
|
|
# and aulEventToRecordInfo
|
|
|
|
set aul [$self aul]
|
|
if {![llength $aul]} return
|
|
set rec [lmap i \
|
|
[lrange [split $szEventToRecord |] 0 end-1] {
|
|
# Remove the initial CRID type
|
|
string range $i 1 end
|
|
}]
|
|
|
|
if {$debug} {
|
|
puts "_AUL: [llength $aul] $aul"
|
|
puts "_REC: [llength $rec] $rec"
|
|
}
|
|
|
|
# Should not happen but in this case the Humax software will
|
|
# sort it out in the background once it sees the new skiplist.
|
|
if {[llength $aul] != [llength $rec]} return
|
|
|
|
set skipnext 0
|
|
set i 0
|
|
foreach crid $rec {
|
|
if {$crid ni $skiplist} {
|
|
incr i
|
|
continue
|
|
}
|
|
if {$i == 0} { incr skipnext }
|
|
set aul [lreplace $aul $i $i]
|
|
set rec [lreplace $rec $i $i]
|
|
if {$debug} { puts " -- Removing $crid" }
|
|
incr i
|
|
}
|
|
|
|
if {$debug} {
|
|
puts " AUL: [llength $aul] $aul"
|
|
puts " REC: [llength $rec] $rec"
|
|
}
|
|
|
|
if {[llength $rec]} {
|
|
set szEventToRecord "1[join $rec |1]|"
|
|
set aulEventToRecordInfo [rsv buildaul $aul]
|
|
} else {
|
|
set szEventToRecord ""
|
|
set aulEventToRecordInfo ""
|
|
}
|
|
|
|
# Is the next scheduled recording to be skipped?
|
|
if {!$skipnext} return
|
|
|
|
if {$debug} { puts "Skip next event." }
|
|
|
|
if {[llength $aul]} {
|
|
lassign [lindex $aul 0] _hsvc _start _end _eid
|
|
set ucVolume "$_hsvc:$_eid:$_start"
|
|
} else {
|
|
# The next event is not yet in the EPG
|
|
set time $([clock seconds] - 86400)
|
|
set ucVolume "$hsvc:$usLastRecordedEvtId:$time"
|
|
}
|
|
}
|
|
|
|
rsv method apply_skip {service event} {
|
|
require epg.class
|
|
lassign [epg dbfetch dump -service $service -event $event] epg
|
|
|
|
if {$epg eq ""} {
|
|
error "Cannot find event in EPG."
|
|
}
|
|
$epg get_channel_info
|
|
|
|
# First check to see if there is already a pending skip for this
|
|
# event and, if so, update that one.
|
|
set crid [string toupper \
|
|
"[$epg get channel_crid][$epg get series_crid]"]
|
|
set table pending
|
|
set ev [rsv fetch $table $ersvtype $hsvc 0 $usevtid $crid]
|
|
if {$ev == 0} {
|
|
set table TBL_RESERVATION
|
|
set ev $self
|
|
$ev clear_ulslot
|
|
}
|
|
$ev set_skip $epg
|
|
if {[catch {$ev insert_deferred} msg]} {
|
|
error "Error during insert."
|
|
}
|
|
}
|
|
|
|
rsv method remove_pending {} {
|
|
[rsv dbhandle] query "delete from pending where ulslot = $ulslot"
|
|
}
|
|
|
|
rsv method fix_hsvc {} {
|
|
set c [svc channel $szSvcName]
|
|
if {$c == 0} { set c [svc load usLcn $usLcn] }
|
|
if {$c == 0} return
|
|
set hsvc [$c get hSvc]
|
|
}
|
|
|
|
proc {rsv find_hsvc} {lcn channel} {
|
|
set c [svc channel $szSvcName]
|
|
if {$c == 0} { set c [svc load usLcn $usLcn] }
|
|
if {$c == 0} { return 0 }
|
|
return [$c get hSvc]
|
|
}
|
|
|
|
rsv method cleanvars {} {
|
|
return [lsort [lmap i [$self vars] {
|
|
if {[string index $i 0] eq "_"} continue
|
|
function $i
|
|
}]]
|
|
}
|
|
|
|
rsv method insert {{table pending} {force 0} {defer 0}} {
|
|
set rsvdb [rsv dbhandle]
|
|
|
|
set now [clock seconds]
|
|
|
|
# In-progress check
|
|
if {!$force && $nsttime - $ulPreOffset <= $now} {
|
|
# Start time in the past
|
|
if {$nsttime + $nduration + $ulPostOffset >= $now} {
|
|
# Still showing
|
|
switch $action {
|
|
0 { # Add
|
|
# Ok if real-time scheduling in use.
|
|
if {![rsv rtsched]} {
|
|
throw 20 "Event already in progress."
|
|
return
|
|
}
|
|
}
|
|
default {
|
|
throw 20 "Event already in progress."
|
|
return
|
|
}
|
|
}
|
|
} elseif {$action == 0} {
|
|
throw 20 "Event has finished."
|
|
return
|
|
}
|
|
}
|
|
|
|
# Duplicate check - all tables
|
|
if {!$force && $action == 0 && $usevtid} {
|
|
foreach tab {pending TBL_RESERVATION} {
|
|
set rec [$rsvdb query "
|
|
select ulslot from $tab
|
|
where usevtid = '%s'
|
|
and hsvc = '%s'
|
|
" $usevtid $hsvc]
|
|
if {[llength $rec] > 0} {
|
|
throw 20 "Duplicate reservation."
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
# Find a spare slot.
|
|
if {$ulslot < 0} {
|
|
set slotlist [$rsvdb query "
|
|
select ulslot FROM $table
|
|
order by ulslot;
|
|
"]
|
|
if {[llength $slotlist] > 0} {
|
|
set slots [lmap i $slotlist {lindex $i 1}]
|
|
set max [lindex $i end]
|
|
for {set i 0} {$i < $max} {incr i} {
|
|
if {$i ni $slots} {
|
|
set ulslot $i
|
|
break
|
|
}
|
|
}
|
|
if {$ulslot < 0} { set ulslot $($max + 1) }
|
|
}
|
|
if {$ulslot < 0} { set ulslot 0 }
|
|
}
|
|
|
|
set fields [$self cleanvars]
|
|
|
|
foreach field {szSvcName usLcn sort} {
|
|
set df [lsearch $fields $field]
|
|
set fields [lreplace $fields $df $df]
|
|
}
|
|
|
|
if {$table ne "pending"} {
|
|
set df [lsearch $fields "action"]
|
|
set fields [lreplace $fields $df $df]
|
|
}
|
|
|
|
set vals {}
|
|
set bvals {}
|
|
foreach field $fields {
|
|
set f [$self get $field]
|
|
if {$field in $::binaryfields && [string bytelength $f] > 1} {
|
|
binary scan $f H* fx
|
|
lappend bvals $fx
|
|
lappend vals "X'%s'"
|
|
} else {
|
|
lappend bvals $f
|
|
lappend vals "'%s'"
|
|
}
|
|
}
|
|
|
|
set query "insert into ${table}("
|
|
append query [join $fields ","]
|
|
append query ") values("
|
|
append query [join $vals ","]
|
|
append query ");"
|
|
|
|
#puts $query
|
|
#puts $bvals
|
|
|
|
$rsvdb query "delete from ${table} where ulslot = $ulslot;"
|
|
$rsvdb query $query {*}$bvals
|
|
|
|
system plog activity "Scheduled [$self name] @ $nsttime"
|
|
|
|
if {$table eq "pending" && !$defer} { rsv commit }
|
|
}
|
|
|
|
rsv method insert_deferred {{table pending}} {
|
|
return [$self insert $table 0 1]
|
|
}
|
|
|
|
proc {rsv list} {{table tbl_reservation} {extra ""} {class rsv}} {
|
|
set qstring "
|
|
select $table.*,
|
|
channel.TBL_SVC.szSvcName, channel.TBL_SVC.usLcn,
|
|
case when ersvtype > 3 then 1 else 0 end as sort1,
|
|
case when nsttime + nduration < [clock seconds]
|
|
then 0 else 1 end as sort2
|
|
from $table
|
|
left join channel.TBL_SVC
|
|
on $table.hSvc = channel.TBL_SVC.hSvc
|
|
"
|
|
if {$extra ne ""} { append qstring $extra }
|
|
append qstring "
|
|
order by sort1, sort2 desc, nsttime
|
|
"
|
|
|
|
#puts "QSTRING: ($qstring)"
|
|
|
|
set res [[$class dbhandle] query $qstring]
|
|
set records {}
|
|
foreach rec $res {
|
|
lappend rec _table $table
|
|
lappend records [$class new $rec]
|
|
}
|
|
|
|
return $records
|
|
}
|
|
|
|
proc {rsv count} {{table tbl_reservation}} {
|
|
return [llength [rsv list $table]]
|
|
}
|
|
|
|
proc {rsv lookuptab} {} {
|
|
set records {}
|
|
foreach tab {tbl_reservation pending} {
|
|
set res [[rsv dbhandle] query "
|
|
select usSvcId, usevtid, ucCRIDType, szCRID,
|
|
ucRecKind, aulEventToRecordInfo,
|
|
szRecordedProgCrid
|
|
from $tab left join channel.TBL_SVC
|
|
on $tab.hSvc = channel.TBL_SVC.hSvc
|
|
where ersvtype <= 3
|
|
"]
|
|
|
|
foreach rec $res {
|
|
if {$rec(ucRecKind) == 4} {
|
|
set p "S"
|
|
} else {
|
|
set p "E"
|
|
}
|
|
set records([\
|
|
string tolower "$rec(usSvcId):$rec(usevtid)"]) $p
|
|
if {$rec(szCRID) eq ""} continue
|
|
if {$rec(ucCRIDType) == 49} {
|
|
set p "E"
|
|
} elseif {$rec(ucCRIDType) == 50} {
|
|
set p "S"
|
|
} else {
|
|
continue
|
|
}
|
|
|
|
foreach r [split $rec(szRecordedProgCrid) "|"] {
|
|
if {$r != {}} {
|
|
set records([string tolower "\
|
|
$rec(szCRID):\
|
|
[string range $r 1 end]"]) "R"
|
|
}
|
|
}
|
|
|
|
set aul $rec(aulEventToRecordInfo)
|
|
|
|
if {[string length $aul]} {
|
|
for {set i 0} {
|
|
$i < [string length $aul]} {incr i 16} {
|
|
binary scan [string range \
|
|
$aul $i $($i + 15)] \
|
|
iiii service start end event_id
|
|
set records([
|
|
string tolower \
|
|
"$service:$event_id"]) $p
|
|
}
|
|
} else {
|
|
set records([
|
|
string tolower \
|
|
"$rec(usSvcId):$rec(szCRID)"]) $p
|
|
}
|
|
}
|
|
}
|
|
|
|
# Add all skipped episodes for all series
|
|
set skiplist [rsv _skiplist]
|
|
foreach skip $skiplist {
|
|
set records($skip) "X"
|
|
}
|
|
|
|
return $records
|
|
}
|
|
|
|
proc {rsv xlookuptab} {} {
|
|
set records {}
|
|
foreach tab {tbl_reservation pending} {
|
|
set res [[rsv dbhandle] query "
|
|
select $tab.szCRID, channel.TBL_SVC.hSvc
|
|
from $tab left join channel.TBL_SVC
|
|
on $tab.hSvc = channel.TBL_SVC.hSvc
|
|
where ersvtype <= 3
|
|
"]
|
|
|
|
foreach rec $res {
|
|
lappend records "$rec(hSvc)/[file tail $rec(szCRID)]"
|
|
}
|
|
}
|
|
|
|
return $records
|
|
}
|
|
|
|
proc {rsv entry} {{table TBL_RESERVATION} crid svc} {
|
|
set res [[rsv dbhandle] query "
|
|
select $table.*,
|
|
channel.TBL_SVC.szSvcName, channel.TBL_SVC.usLcn
|
|
from $table
|
|
left join channel.TBL_SVC
|
|
on $table.hSvc = channel.TBL_SVC.hSvc
|
|
where szCRID like '%%%s' and $table.hsvc = '%s'
|
|
" $crid $svc]
|
|
|
|
if {[llength $res] > 0} {
|
|
return [rsv new [lindex $res 0]]
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc {rsv fetch} {table ersvtype hsvc nsttime usevtid {crid ""} {extra ""}} {
|
|
set q "
|
|
select $table.*,
|
|
channel.TBL_SVC.szSvcName, channel.TBL_SVC.usLcn
|
|
from $table
|
|
left join channel.TBL_SVC
|
|
on $table.hSvc = channel.TBL_SVC.hSvc
|
|
where $table.ersvtype = '%s'
|
|
and $table.hsvc = '%s'
|
|
and $table.usevtid = '%s'
|
|
"
|
|
set params "$ersvtype $hsvc $usevtid"
|
|
|
|
if {$nsttime > 0} {
|
|
append q " and $table.nsttime = '%s' "
|
|
lappend params $nsttime
|
|
}
|
|
if {$crid ne ""} {
|
|
append q " and szCRID = '%s' collate nocase "
|
|
lappend params $crid
|
|
}
|
|
if {$extra ne ""} {
|
|
append q " $extra "
|
|
}
|
|
|
|
set res [[rsv dbhandle] query $q {*}$params]
|
|
|
|
if {[llength $res] > 0} {
|
|
return [rsv new [lindex $res 0]]
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc {rsv slot} {{table TBL_RESERVATION} slot} {
|
|
set res [[rsv dbhandle] query "
|
|
select $table.*,
|
|
channel.TBL_SVC.szSvcName, channel.TBL_SVC.usLcn
|
|
from $table
|
|
left join channel.TBL_SVC
|
|
on $table.hSvc = channel.TBL_SVC.hSvc
|
|
where ulslot = %s" $slot]
|
|
|
|
if {[llength $res] > 0} {
|
|
return [rsv new [lindex $res 0]]
|
|
}
|
|
return 0
|
|
}
|
|
|
|
proc {rsv rtsched} {} {
|
|
if {![system nuggeted]} { return 0 }
|
|
if {![[settings] rtschedule]} { return 0 }
|
|
return 1
|
|
}
|
|
|
|
proc {rsv commit} {{plugins 1}} {
|
|
if {![rsv rtsched]} return
|
|
rsv dbhandle -close
|
|
if {[catch {
|
|
exec /mod/boot/rsvsync -realtime >> /mod/tmp/rsvsync.log} msg]} {
|
|
puts "Scheduling: $msg"
|
|
} else {
|
|
system restartpending 0
|
|
if {$plugins} {
|
|
eval_plugins rts
|
|
}
|
|
}
|
|
}
|
|
|
|
proc {rsv construct} {event type} {
|
|
global ccrid
|
|
|
|
$event get_channel_info
|
|
|
|
set args {}
|
|
|
|
set args(ersvtype) 3
|
|
set args(hsvc) [$event get channel_hsvc]
|
|
set args(nsttime) [$event get start]
|
|
set args(nduration) [$event get duration]
|
|
set args(usevtid) [$event get event_id]
|
|
set args(szevtname) "\025[xconv [$event get name]]"
|
|
set args(eReady) 30
|
|
lassign [system padding] args(ulPreOffset) args(ulPostOffset)
|
|
|
|
set ccrid [string toupper [$event get channel_crid]]
|
|
|
|
# Fallback from series to event if there is no series CRID.
|
|
if {$type == 2 && [$event get series_crid] eq ""} {
|
|
set type 1
|
|
}
|
|
|
|
if {$type == 1} {
|
|
# Event
|
|
set args(ucCRIDType) 49
|
|
set args(ucRecKind) 1
|
|
set ecrid [$event get event_crid]
|
|
if {$ecrid ne ""} {
|
|
set args(szCRID) "$ccrid$ecrid"
|
|
set args(szEventToRecord) "1$args(szCRID)|"
|
|
set args(aulEventToRecordInfo) [rsv mkaul $event]
|
|
# Handle split events
|
|
if {[string match {*#*} $args(szCRID)]} {
|
|
set args(ucRecKind) 2
|
|
lassign [split $args(szCRID) "#"] crid imi
|
|
set args(szCRID) $crid
|
|
# TODO - check to see how many parts there
|
|
# are...
|
|
append args(szEventToRecord) \
|
|
$args(szEventToRecord)
|
|
}
|
|
}
|
|
} elseif {$type == 3} {
|
|
# Reminder
|
|
set args(ersvtype) 2
|
|
set args(szsttime) [clock format $args(nsttime) \
|
|
-format {%Y%m%d%H%M%S}]
|
|
} else {
|
|
# Series
|
|
set args(ucCRIDType) 50
|
|
set args(ucRecKind) 4
|
|
set args(szCRID) "$ccrid[$event get series_crid]"
|
|
set args(szFPBRecPath) "$args(szevtname)"
|
|
set events {}
|
|
set seen {}
|
|
set progs [lmap i [\
|
|
epg dbfetch dump -scrid [$event get series_crid] \
|
|
-sort start] {
|
|
if {[set ecrid [$i get event_crid]] eq ""} continue
|
|
if {$ecrid in $seen} continue
|
|
lappend seen $ecrid
|
|
if {[$i get start] < [$event get start]} {
|
|
set args(usLastRecordedEvtId) [$i get event_id]
|
|
continue
|
|
}
|
|
lappend events [rsv mkaul $i]
|
|
list "1$::ccrid$ecrid"
|
|
}]
|
|
set args(szEventToRecord) "[join $progs "|"]|"
|
|
set args(aulEventToRecordInfo) [join $events ""]
|
|
}
|
|
|
|
return [rsv new $args]
|
|
}
|
|
|
|
proc {rsv manual} {start end lcn type repeat {title ""}} {
|
|
set args {}
|
|
|
|
set args(ersvtype) $type
|
|
set args(erepeat) $repeat
|
|
set args(nsttime) $start
|
|
set args(szsttime) [clock format $args(nsttime) \
|
|
-format {%Y%m%d%H%M%S}]
|
|
set args(nduration) $($end - $start)
|
|
|
|
set c [svc load usLcn $lcn]
|
|
set args(hsvc) [$c get hSvc]
|
|
|
|
if {$title eq ""} {
|
|
set title [$c get szSvcName]
|
|
}
|
|
|
|
set args(szevtname) $title
|
|
|
|
set args(ucRecKind) 0
|
|
set args(usevtid) 0
|
|
set args(eReady) 30
|
|
|
|
return [rsv new $args]
|
|
}
|
|
|
|
proc {rsv backup} {file} {
|
|
set rsvdb [rsv dbhandle]
|
|
|
|
require epg.class
|
|
|
|
if {[catch { set fd [open $file w] } msg]} {
|
|
error "Error creating backup file. - $msg"
|
|
}
|
|
|
|
puts "Backing up scheduled recordings and events..."
|
|
|
|
set events [rsv list]
|
|
|
|
set fields [[rsv] cleanvars]
|
|
|
|
puts $fd "# version 2"
|
|
|
|
puts $fd "#\n# Schedule\n# [join $fields "\t"]"
|
|
|
|
foreach event $events {
|
|
puts " Backing up scheduled event '[$event name]'"
|
|
puts -nonewline $fd "event\t"
|
|
|
|
foreach f $fields {
|
|
set ret [$event get $f]
|
|
if {$f in $::binaryfields} {
|
|
binary scan $ret H* ret
|
|
}
|
|
puts -nonewline $fd "$ret\t"
|
|
}
|
|
puts $fd ""
|
|
}
|
|
puts "Done."
|
|
|
|
puts "Backing up channel favourites..."
|
|
puts " Names:"
|
|
|
|
puts $fd "#\n# Favourites"
|
|
|
|
# Favourite names
|
|
set favnames {}
|
|
loop i 1 6 {
|
|
set favname [system strip \
|
|
[system param FAV_CUSTOM_STR0$i Text]]
|
|
set idx [expr 1 << ($i - 1)]
|
|
set favnames($idx) $favname
|
|
puts $fd "favname\t$i\t$idx\t$favname"
|
|
puts " $favname"
|
|
}
|
|
|
|
set grp 0
|
|
foreach res [$rsvdb query {
|
|
select eFavGroup,
|
|
TBL_FAV.eSvcType,
|
|
substr(szSvcName, 2) as szSvcName,
|
|
favIdx
|
|
from TBL_FAV join TBL_SVC using (hSvc)
|
|
order by eFavGroup, favIdx
|
|
}] {
|
|
if {$res(eFavGroup) != $grp} {
|
|
set grp $res(eFavGroup)
|
|
if {[dict exists $favnames $grp]} {
|
|
puts " Group $favnames($grp)"
|
|
} else {
|
|
puts " Group '$grp':"
|
|
}
|
|
}
|
|
puts " $res(szSvcName)"
|
|
puts $fd "fav\t$res(eFavGroup)\t$res(eSvcType)\t$res(szSvcName)\t$res(favIdx)"
|
|
}
|
|
puts "Done."
|
|
|
|
puts "Backing up skiplist..."
|
|
|
|
set skiplist [$rsvdb query {
|
|
select * from skip
|
|
order by ulslot, start
|
|
}]
|
|
if {[llength $skiplist]} {
|
|
# Add key line
|
|
set keys "#\n# Skiplist\n#"
|
|
foreach {k v} [lindex $skiplist 0] {
|
|
append keys " $k,"
|
|
}
|
|
puts $fd $keys
|
|
|
|
foreach skip $skiplist {
|
|
puts -nonewline $fd "skip\t"
|
|
foreach {k v} $skip {
|
|
puts -nonewline $fd "$v\t"
|
|
}
|
|
puts $fd ""
|
|
}
|
|
}
|
|
|
|
puts "Done."
|
|
|
|
puts "Backing up channel list..."
|
|
|
|
puts $fd "#\n# Channels by hSvc"
|
|
|
|
foreach channel [epg channellist hSvc] {
|
|
lassign $channel name hsvc
|
|
puts $fd "hsvc\t$hsvc\t$name"
|
|
}
|
|
|
|
puts $fd "#\n# Channels by LCN"
|
|
|
|
foreach channel [epg channellist usLcn] {
|
|
lassign $channel name uslcn
|
|
puts $fd "lcn\t$uslcn\t$name"
|
|
}
|
|
|
|
puts "Done."
|
|
|
|
close $fd
|
|
}
|
|
|
|
proc {rsv restore} {file} {
|
|
set rsvdb [rsv dbhandle]
|
|
|
|
if {![file exists $file]} {
|
|
error "Backup file <i>$file</i> does not exist."
|
|
}
|
|
|
|
if {[catch { set fd [open $file r] } msg]} {
|
|
error "Error opening <i>$file</i> - $msg"
|
|
}
|
|
|
|
set data [split [read $fd] "\n"]
|
|
|
|
set ver 1
|
|
|
|
set hsvcmap {}
|
|
set lcnmap {}
|
|
set favmap {}
|
|
|
|
# Check version, build maps for later.
|
|
foreach line $data {
|
|
if {[string match "# version *" $line]} {
|
|
set ver [lindex [split $line " "] 2]
|
|
puts "Backup version $ver"
|
|
}
|
|
lassign [split $line "\t"] tag f1 f2 f3 f4
|
|
switch -- $tag {
|
|
hsvc { set hsvcmap($f1) $f2 }
|
|
lcn { set lcnmap($f2) $f1 }
|
|
favname { set favmap($f2) $f3 }
|
|
}
|
|
}
|
|
|
|
set chanmap [lreverse $hsvcmap]
|
|
|
|
puts "Restoring scheduled events from <i>$file</i>..."
|
|
|
|
# Disable RTS until next restart.
|
|
system nugget quit
|
|
|
|
# Clear tables
|
|
foreach tab {TBL_RESERVATION pending skip} {
|
|
$rsvdb query {delete from %s;} $tab
|
|
}
|
|
|
|
set fields [[rsv] cleanvars]
|
|
|
|
######################################################################
|
|
# Restore events
|
|
|
|
foreach line $data {
|
|
set vals [split $line "\t"]
|
|
if {[lindex $vals 0] ne "event"} continue
|
|
set vars {}
|
|
set i 0
|
|
foreach f $fields {
|
|
if {$ver < 2 && $f eq "aulEventToRecordInfo"} {
|
|
continue
|
|
}
|
|
incr i
|
|
set val [lindex $vals $i]
|
|
if {$f in $::binaryfields} {
|
|
set val [binary format H* $val]
|
|
}
|
|
lappend vars $f $val
|
|
}
|
|
|
|
# Don't restore DSO events.
|
|
if {$vars(ersvtype) == 11} continue
|
|
|
|
set rsv [rsv new $vars]
|
|
|
|
# Need to fix up channel and CRID mappings in case something
|
|
# has changed during a channel scan.
|
|
|
|
puts " Restoring [$rsv name] ([$rsv get szSvcName])"
|
|
|
|
set bad 0
|
|
# First, the service number
|
|
set ohsvc [$rsv get hsvc]
|
|
if {$ohsvc > 0} {
|
|
set hsvc [$rsv fix_hsvc]
|
|
if {$hsvc == 0} {
|
|
puts " Cannot find channel, restore failed."
|
|
set bad 1
|
|
} elseif {$hsvc != $ohsvc} {
|
|
puts -nonewline " Service number has "
|
|
puts "changed $ohsvc -> $hsvc, fixing."
|
|
} else {
|
|
puts " No change in channel service."
|
|
}
|
|
}
|
|
|
|
if {!$bad} {
|
|
# Need to fix up the AUL table service IDs too.
|
|
set newaul ""
|
|
foreach aul [$rsv aul] {
|
|
# {service start end event_id}
|
|
lassign $aul ohsvc start end eid
|
|
if {![dict exists $hsvcmap $ohsvc]} {
|
|
# Should not happen
|
|
puts " Losing AUL entry ($ohsvc)."
|
|
continue
|
|
}
|
|
set lcn 0
|
|
set channame $hsvcmap($ohsvc)
|
|
if {[dict exists $lcnmap $channame]} {
|
|
set lcn $lcnmap($channame)
|
|
}
|
|
# Find the new hsvc if possible.
|
|
set _hsvc [rsv find_hsvc $lcn $channame]
|
|
if {$_hsvc eq ""} continue
|
|
puts -nonewline " AUL $channame ($ohsvc"
|
|
if {$ohsvc != $_hsvc} {
|
|
puts -nonewline " -> $_hsvc"
|
|
}
|
|
puts ")"
|
|
append newaul [binary format iiii \
|
|
$_hsvc $start $end $eid]
|
|
}
|
|
$rsv setaul $newaul
|
|
}
|
|
|
|
if {!$bad} {
|
|
if {[catch {$rsv insert pending 1 1} msg]} {
|
|
puts " Error inserting event, $msg"
|
|
}
|
|
}
|
|
puts ""
|
|
}
|
|
|
|
######################################################################
|
|
# Restore skiplist
|
|
puts "Restoring skiplist..."
|
|
|
|
set fields "ulslot state service_id event_id hSvc start
|
|
ucCRIDType szCRID szSkipCRID"
|
|
|
|
foreach line $data {
|
|
set vals [lrange [lassign [split $line "\t"] key] 0 end-1]
|
|
if {$key ne "skip"} continue
|
|
|
|
lassign $vals {*}$fields
|
|
|
|
# Map old hSvc to new
|
|
if {![dict exists $hsvcmap $hSvc]} {
|
|
# Should not happen
|
|
puts " Losing skip entry ($hSvc)"
|
|
continue
|
|
}
|
|
set chan $hsvcmap($hSvc)
|
|
puts " Restoring skip for $chan - $szSkipCRID"
|
|
|
|
# Fetch new hSvc and service_id
|
|
set c [svc channel $chan]
|
|
if {$c == 0} {
|
|
puts " Cannot find channel"
|
|
continue
|
|
}
|
|
set _hsvc [$c get hSvc]
|
|
set _service_id [$c get usSvcId]
|
|
if {$_hsvc eq "" || $_service_id eq ""} {
|
|
puts " Cannot map channel name to service."
|
|
continue
|
|
}
|
|
if {$hSvc != $_hsvc || $service_id != $_service_id} {
|
|
puts -nonewline " Service number has changed "
|
|
puts "$hSvc -> $_hsvc, fixing."
|
|
lset vals [lsearch $fields hSvc] $_hsvc
|
|
lset vals [lsearch $fields service_id] $_service_id
|
|
}
|
|
catch {$rsvdb query "
|
|
insert into skip([join $fields ,]) values (
|
|
[join [lrepeat [llength $fields] "'%s'"] ,]
|
|
);
|
|
" {*}$vals}
|
|
}
|
|
|
|
######################################################################
|
|
# Restore favourites
|
|
puts "Restoring favourite channels..."
|
|
$rsvdb query {delete from channel.TBL_FAV}
|
|
|
|
$rsvdb query {drop table if exists pending.fav}
|
|
$rsvdb query {create table pending.fav (
|
|
favIdx integer primary key unique,
|
|
hSvc integer(4),
|
|
eFavGroup integer(4),
|
|
[eSvcType] integer(4)
|
|
)}
|
|
$rsvdb query {drop table if exists pending.favnames}
|
|
$rsvdb query {create table pending.favnames (
|
|
idx integer primary key unique,
|
|
name string
|
|
)}
|
|
|
|
set grp 0
|
|
set inc 0
|
|
set lastidx 1
|
|
foreach line $data {
|
|
set vals [split $line "\t"]
|
|
|
|
if {[lindex $vals 0] eq "favname"} {
|
|
lassign $vals x num x name
|
|
$rsvdb query {
|
|
insert into
|
|
pending.favnames(idx, name)
|
|
values(%s, '%s')
|
|
} $num $name
|
|
continue
|
|
}
|
|
|
|
if {[lindex $vals 0] ne "fav"} { continue }
|
|
|
|
lassign $vals x group type chan idx
|
|
|
|
if {$idx eq ""} {
|
|
# This is to support old format backup files where
|
|
# the favourite index is not present.
|
|
set idx 0
|
|
} else {
|
|
if {$idx eq "-"} {
|
|
set idx $lastidx
|
|
incr inc
|
|
}
|
|
set lastidx $idx
|
|
incr idx $inc
|
|
}
|
|
|
|
if {$grp != $group} {
|
|
set grp $group
|
|
if {[dict exists $favmap $grp]} {
|
|
puts " Group $favmap($grp)"
|
|
} else {
|
|
puts " Group $grp"
|
|
}
|
|
}
|
|
|
|
puts " $chan"
|
|
|
|
set c [svc channel $chan]
|
|
if {$c == 0} {
|
|
puts " Cannot map channel name to service."
|
|
continue
|
|
}
|
|
set hsvc [$c get hSvc]
|
|
if {$hsvc eq ""} {
|
|
puts " Cannot map channel name to service."
|
|
continue
|
|
}
|
|
|
|
$rsvdb query {
|
|
insert into
|
|
pending.fav(favIdx, hSvc, eFavGroup, eSvcType)
|
|
values(%s, %s, %s, %s);
|
|
} $idx $hsvc $group $type
|
|
}
|
|
|
|
system restartpending
|
|
|
|
close $fd
|
|
}
|
|
|
|
# Returns an array of expanded events from the schedule.
|
|
# Array keys:
|
|
# 0: start
|
|
# 1: end
|
|
# 2: hSvc
|
|
# 3: event_id
|
|
# 4: Schedule ID (sid)
|
|
# 5: ucRecKind
|
|
# 6: class (live, pending)
|
|
|
|
proc {rsv allevents} {{xota 0}} {
|
|
set events [rsv list]
|
|
set pending [rsv list pending]
|
|
if {[llength $pending]} {
|
|
lappend events {*}$pending
|
|
}
|
|
|
|
set today [midnight]
|
|
|
|
set xevents {}
|
|
|
|
foreach e $events {
|
|
set seen 0
|
|
|
|
if {[$e get ersvtype] > 4} continue
|
|
if {[$e get action] ne "0"} continue
|
|
if {[$e start] < $today} continue
|
|
|
|
if {$xota && [$e get szevtname] eq "Disable OTA"} continue
|
|
|
|
set trailer [list \
|
|
[$e get ulslot] \
|
|
[$e get ucRecKind] \
|
|
[$e get _table] \
|
|
]
|
|
|
|
# Expand the events encoded in the AUL data.
|
|
foreach a [$e aul] {
|
|
lassign $a service start end event_id
|
|
if {$start == [$e start] && \
|
|
$end == [$e end]} {
|
|
incr seen
|
|
}
|
|
lappend xevents [list $start $end $service $event_id \
|
|
{*}$trailer]
|
|
}
|
|
|
|
if {$seen} continue
|
|
|
|
set start [$e start]
|
|
set end [$e end]
|
|
|
|
lappend xevents [list $start $end \
|
|
[$e get hsvc] [$e get usevtid] {*}$trailer]
|
|
|
|
set repeat [$e get erepeat]
|
|
switch $repeat {
|
|
1 -
|
|
3 -
|
|
4 {
|
|
# 1 Daily
|
|
# 3 Weekends
|
|
# 4 Weekdays
|
|
|
|
for {set i 0} {$i < 8} {incr i} {
|
|
|
|
incr start 86400
|
|
incr end 86400
|
|
|
|
# Sun == 0
|
|
set day [clock format $start -format "%w"]
|
|
|
|
# Weekdays Only
|
|
if {$repeat == 3 && ($day == 0 || $day == 6)} {
|
|
continue
|
|
}
|
|
|
|
# Weekends Only
|
|
if {$repeat == 4 && $day != 0 && $day != 6} {
|
|
continue
|
|
}
|
|
|
|
lappend xevents [list \
|
|
$start $end \
|
|
[$e get hsvc] [$e get usevtid] \
|
|
{*}$trailer]
|
|
}
|
|
}
|
|
2 {
|
|
# Weekly
|
|
lappend xevents [list \
|
|
$($start + 7 * 86400) \
|
|
$($end + 7 * 86400) \
|
|
[$e get hsvc] [$e get usevtid] \
|
|
{*}$trailer]
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return $xevents
|
|
}
|
|
|
|
proc {rsv evaluate_conflicts} {events type thresh {debug 0}} {
|
|
set conflicts {}
|
|
set slots {0 0}
|
|
foreach ev $events {
|
|
lassign $ev start end hsvc eid sid
|
|
|
|
if {$debug} {
|
|
puts "\nSLOTS: $slots"
|
|
puts $ev
|
|
}
|
|
|
|
# Close off any open slots that have now finished.
|
|
for {set i 0} {$i < 2} {incr i} {
|
|
set v [lindex $slots $i]
|
|
if {$v eq "0"} {
|
|
if {$debug} { puts "\[$i] empty." }
|
|
continue
|
|
}
|
|
|
|
lassign $v xsid xend
|
|
|
|
if {$start >= $xend} {
|
|
lset slots $i 0
|
|
if {$debug} { puts "\[$i] finished $xend." }
|
|
} else {
|
|
if {$debug} { puts "\[$i] running $xend." }
|
|
}
|
|
}
|
|
|
|
# Find slot for recording
|
|
if {[lindex $slots 0] eq "0"} {
|
|
set uslot 0
|
|
} elseif {$thresh > 1 && [lindex $slots 1] eq "0"} {
|
|
set uslot 1
|
|
} else {
|
|
# Conflict detected
|
|
if {$debug} { puts " Conflict." }
|
|
if {$type eq "xlist"} {
|
|
set c "$sid$end"
|
|
for {set i 0} {$i < 2} {incr i} {
|
|
set v [lindex $slots $i]
|
|
if {$v eq "0"} continue
|
|
|
|
lassign $v xsid xend
|
|
|
|
lappend c "$xsid$xend"
|
|
}
|
|
} else {
|
|
set c "$sid"
|
|
for {set i 0} {$i < 2} {incr i} {
|
|
set v [lindex $slots $i]
|
|
if {$v eq "0"} continue
|
|
|
|
lassign $v xsid xend
|
|
|
|
lappend c "$xsid"
|
|
}
|
|
}
|
|
foreach x $c {
|
|
if {![dict exists $conflicts $x]} {
|
|
set conflicts($x) $c
|
|
}
|
|
}
|
|
|
|
# If this events ends later than the
|
|
# existing one in slot 0, then replace that
|
|
# with this one.
|
|
|
|
lassign [lindex $slots 0] xsid xend
|
|
if {$xend >= $end} continue
|
|
if {$debug} { puts " Replacing slot 0.\n" }
|
|
set uslot 0
|
|
}
|
|
|
|
if {$debug} {
|
|
puts " -> into slot $uslot"
|
|
}
|
|
# Insert event into slot
|
|
lset slots $uslot [list $sid $end]
|
|
}
|
|
return $conflicts
|
|
}
|
|
|
|
proc {rsv newconflicts} {{thresh 1} {type "list"} {debug 0}} {
|
|
set events [lsort -index 0 -integer [rsv allevents]]
|
|
set conflicts [rsv evaluate_conflicts $events $type $thresh $debug]
|
|
|
|
if {$type eq "map"} { return $conflicts }
|
|
return [dict keys $conflicts]
|
|
}
|
|
|
|
proc {rsv checkconflict} {s d thresh {debug 0}} {
|
|
set events [rsv allevents]
|
|
lappend events [list $s $($s + $d) 0 0 0]
|
|
set events [lsort -index 0 -integer $events]
|
|
set conflicts [rsv evaluate_conflicts $events 'list' $thresh $debug]
|
|
|
|
set ret {}
|
|
|
|
if {![dict exists $conflicts "0"]} { return $ret }
|
|
|
|
foreach c [dict get $conflicts 0] {
|
|
if {$c eq "0"} continue
|
|
set s [rsv slot $c]
|
|
set s [$s name]
|
|
lappend ret $s
|
|
}
|
|
|
|
return $ret
|
|
}
|
|
|
|
proc {rsv clearskip} {slot {start 0}} {
|
|
set q "delete from skip where ulslot = $slot "
|
|
if {$start} {
|
|
append q "and start = $start"
|
|
}
|
|
catch { [rsv dbhandle] query $q }
|
|
}
|
|
|
|
proc {rsv _skiplist} {{ulslot -1}} {
|
|
set dbh [rsv dbhandle]
|
|
|
|
set q "select group_concat(hSvc || ':' || event_id, ' ')
|
|
as list from skip where state = 'live'"
|
|
if {$ulslot >= 0} {
|
|
append q " and ulslot = $ulslot"
|
|
}
|
|
lassign [$dbh query $q] ret
|
|
return $ret(list)
|
|
}
|
|
|
|
rsv method skiplist {} {
|
|
return [rsv _skiplist $ulslot]
|
|
}
|
|
|
|
proc {rsv reassert_skips} {{debug false}} {
|
|
set rsvdb [rsv dbhandle]
|
|
set changes 0
|
|
|
|
# Remove any expired skips
|
|
$rsvdb query "delete from skip where start < [clock seconds]"
|
|
|
|
foreach s [$rsvdb query {
|
|
select ulslot, szCRID, group_concat(szSkipCRID) as skiplist
|
|
from skip
|
|
where state = 'live' and ulslot >= 0
|
|
group by 1, 2
|
|
order by ulslot, start
|
|
}] {
|
|
if {$debug} { puts "\n--> SKIP: $s" }
|
|
if {![dict exists $s ulslot]} continue
|
|
if {[catch { set r [rsv slot $s(ulslot)] }]} continue
|
|
if {$r eq "0"} {
|
|
if {$debug} { puts "Slot no longer in schedule." }
|
|
rsv clearskip $s(ulslot)
|
|
continue
|
|
}
|
|
if {[$r get szCRID] ne $s(szCRID)} {
|
|
if {$debug} { puts "Slot now for different series." }
|
|
rsv clearskip $s(ulslot)
|
|
continue
|
|
}
|
|
|
|
#if {$debug} { require classdump; classdump $r }
|
|
|
|
set toskip [split $s(skiplist) ,]
|
|
set rsvskip [lmap i \
|
|
[lrange [split [$r get szRecordedProgCrid] |] 0 end-1] {
|
|
# Remove the initial CRID type
|
|
string range $i 1 end
|
|
}]
|
|
|
|
# Build list of events in rsvskip which are not in toskip.
|
|
# These are entries which have been added as episodes have
|
|
# recorded.
|
|
set recskip [lmap i $rsvskip {
|
|
if {$i in $toskip} continue
|
|
function $i
|
|
}]
|
|
|
|
# Build a new skip list consisting of:
|
|
# Upcoming skipped events (in start order)
|
|
# Other events from existing list (recorded events)
|
|
# Always allow space for two of the "other events" if they
|
|
# are present.
|
|
|
|
set others [llength $recskip]
|
|
if {$others > 2} { set others 2 }
|
|
set skiplist [lrange $toskip 0 $(5 - $others - 1)]
|
|
lappend skiplist {*}$recskip
|
|
# Truncate to 5 entries
|
|
set skiplist [lrange $skiplist 0 4]
|
|
|
|
if {$debug} {
|
|
puts "TOSKIP: $toskip"
|
|
puts "RSVSKIP: $rsvskip"
|
|
puts "RECSKIP: $recskip"
|
|
puts "SKIPLIST: $skiplist"
|
|
}
|
|
|
|
if {$skiplist eq $rsvskip} {
|
|
puts "Skip list already correct, nothing to do."
|
|
continue
|
|
}
|
|
|
|
set ev [rsv fetch pending [$r get ersvtype] \
|
|
[$r get hsvc] 0 [$r get usevtid] $s(szCRID)]
|
|
if {$ev ne "0"} {
|
|
if {$debug} { puts "Found pending entry, skipping." }
|
|
continue
|
|
}
|
|
|
|
# Apply the new skiplist.
|
|
$r clear_ulslot
|
|
$r replace_skip $skiplist
|
|
#if {$debug} { require classdump; classdump $r }
|
|
$r insert_deferred
|
|
puts "Applied new skip list."
|
|
incr changes
|
|
}
|
|
if {$changes} {
|
|
if {$debug} { puts "Committing changes..." }
|
|
rsv commit
|
|
}
|
|
}
|
|
|