#!/mod/bin/jimsh # "schedchk = Check for recording schedule issues and attempt to fix them" # author MymsMan based on webif functions by af123 source /mod/webif/lib/setup require rsv.class epg.class system.class ts.class proc log {msg {level 1}} { if {$level > $::loglevel} return puts $::logfd "[\ clock format [clock seconds] -format "%d/%m/%Y %H:%M:%S"\ ] - SC $msg" flush $::logfd # Generate webif alerts for changes/errors if {!$::opts(noalert) && $level == 0} { system notify "SchedChk: $msg" } } ## let's mess with the internals - needs to be moved to rsv.class #rsv method set {ivName val} { # set $ivName $val #} # #rsv method issplit {} { # if {$ucRecKind == 2} { return 1 } else { return 0 } #} # Parse command options and apply defaults proc checkopts {argv} { global optarray set settings [settings] set parmerror 0 set ::autologlevel [$settings _nval_setting "autolog"] set ::loglevel $::autologlevel if {[info exists ::auto::logfd]} { set logfd ::auto::logfd } # Read List of options with default values source "/mod/webif/plugin/schedchk/optlist.jim" # Override default from settings DB foreach optl $optarray { lassign $optl desc key defval helptxt set key [string tolower $key] if {$defval eq "n"} {set defval 0} if {$defval eq "y"} {set defval 1} set ::opts($key) [$settings _nval_setting "schedchk_$key"] if {$::opts($key)==0} {set ::opts($key) $defval} } # Handle text setting for oher options set otheropts [$settings _tval_setting "schedchk_otheropts"] if {$otheropts == 0} {set otheropts ""} # Parse argument lists foreach argl [list $otheropts $argv] { set ::optlist "" log "arg list $argl" 2 for {set ix 0} {$ix < [llength $argl]} {incr ix} { set arg [lindex $argl $ix] #check if option in optarray list if {[string range $arg 0 0] == "-"} { set argx [string tolower [string range $arg 1 end]] if {[dict exists $::opts $argx]} { incr ix set val [lindex $argl $ix] set nval $val if {$val eq "y"} {set nval 1} if {$val eq "n"} {set nval 0} if {![string is double -strict $nval]} { if {[string length $nval] == 0 || [string range $nval 0 0] == "-"} { # Value omitted assume true set nval 1 set val "y" incr ix -1 } else { log "Option $arg value ($val) is not y, n or numeric" 0 incr ix -1 set parmerror 1 continue } } lappend ::optlist $arg lappend ::optlist $val set ::opts($argx) $nval continue } } # check other options switch -- $arg { -rsv - --help - -h { set ::opt $arg } -hmt { set ::opt $arg incr ix set file [lindex $argl $ix] set ::file $file if {[file isfile $file]} { set ::ts [ts fetch $file] if {$::ts == 0} { "Cannot process ($file) file is not valid recording" 0 set parmerror 1 continue } } else { log "Cannot process ($file) file does not exist" 0 set parmerror 1 continue } } default { log "Unrecognized option: $arg" 0 set parmerror 1 continue } } } } if {$::opts(d)} { set ll $::loglevel if {$::opts(d) > $ll} {set ll $::opts(d)} set ::debug 1 set ::loglevel $ll set ::auto::loglevel $ll } if {$parmerror} { log "Parameter errors found" exit } log "Current options" 1 foreach optl $optarray { lassign $optl desc key default helptxt log "[format "-%-11s %-4s" $key $::opts([string tolower $key])]" 1 } } proc svcmap {} { # establish rsv <-> epg service_id mapping global svcmap svcdef set svcmap {} set svcdef {} set svcdef(0) 0 lmap i \ [$::channeldb query {select hSvc, usSvcid, eVideoType from TBL_SVC}] \ { set svcmap([lindex $i 1]) [lindex $i 3] set svcdef([lindex $i 1]) [lindex $i 5] } set svckeys [array names svcmap] } proc conflict-list {} { global conflicts if {$::opts(noconflict)} { log "-noconflict Bypassing automatic conflict resolution" 2 set conflicts {} return } set conflicts [rsv newconflicts [system tuners] "xlist"] if {[llength $conflicts] > 1} { log "++++ [llength $conflicts] Conflicts exist +++" 1 log "$conflicts" 3 } } proc rsvscan {} { global svcmap conflicts svcdef now thresh slot name def svcmap conflict-list set sttimer [clock seconds] set resvs [rsv list] # for each reservation # foreach resv $resvs { # Ignore manual recordings & reminders if {[$resv get ersvtype] != 3} { continue} set name [$resv name] set def $svcdef([$resv get hsvc]) set s [$resv start] set ds "[clock format $s -format {%d/%m/%y %H:%M}]" set d [$resv get nduration] set e $($s + $d) set slot [$resv get ulslot] set lasttime $now set dresv "$ds [clock format $d -format {%H:%M}] === slot $slot === $name === [$resv channel_name]" lassign [$resv padded 1] sp ep set rstatus [$resv status] # Has event passed if {$now > $e + $ep && $rstatus == "unknown" } { set ended 1 incr num_ended } else { set ended 0 } if {!$ended} { log "Reservation - $dresv" 2 # Check whether active recording really is recording if {$s - $sp < $now} { chkActive $resv $dresv $rstatus # don't check active recordings further continue } # If split recording check for repeats if {[$resv issplit]} { if {[chkSplit $resv $dresv]} {continue} } # add any missing episodes if {[$resv isseries]} { miss_epsd $resv $dresv set s [$resv start] set d [$resv get nduration] set e $($s + $d) } if {$s > $thresh} { log "Start > Threshold - $dresv" 2 # check for new series in same time slot if {[$resv isseries]} { scrid_chg $resv $dresv $lasttime } continue } set elist [$resv aul] set enum -1 set ecrids [split [string toupper [$resv get szEventToRecord]] "|"] set ecrid [string toupper [$resv get szCRID]] set ps $s foreach epsd $elist { lassign $epsd service_id start end event_id if {$start < $ps} { log "AUL not in time order - $dresv" 0 } set ps $start } if {[llength $elist] > 0} { lassign [lindex $elist 0] service_id start end event_id # Check 1st aul entry matchs current resv details, should always match? if {$service_id != [$resv get hsvc]} { log "Service id Mismatch $service_id != [$resv get hsvc] = $dresv" 1 # what to do? } if {$start != $s} { log "Start time id Mismatch $start != $s = $dresv" 1 # what to do? } if {$end != $e} { log "End time Mismatch $end != $e = $dresv" 1 # what to do? } if {$event_id != [$resv get usevtid]} { log "Event_id Mismatch $event_id != [$resv get usevtid] = $dresv" 1 # what to do? } # # check each episode scheduled # foreach epsd $elist { lassign $epsd service_id start end event_id incr enum set ecrid [lindex $ecrids $enum] set epgcrid [string range $ecrid [string first "/" $ecrid] end] # set ecrid [string range $ecrid 1 end] set dur $($end-$start) set lasttime $end set deps "[clock format $start -format {%d/%m/%y %H:%M}] [clock format $dur -format {%H:%M}] === slot $slot === $name === [$resv channel_name]" if {$start > $thresh} { log "Start > Threshold - $deps" 2 break } chkEpisode $resv $epsd $ecrid } } else { log "+++ No episodes scheduled in aulEventToRecordInfo +++ $dresv" 1 # use the event info in the main part of the reservation if {![$resv isseries]} { chkEpisode $resv [list [$resv get hsvc] $s $e [$resv get usevtid]] [$resv get szCRID] } } } else { log "Completed - $dresv" 2 } # check for new series in same time slot if {[$resv isseries]} { scrid_chg $resv $dresv $lasttime } } if {[llength $conflicts] > 1} { log "++++ [llength $conflicts] Unresolved conflicts remain +++" 1 } epg cleanup set endtimer [clock seconds] log "=== All done - run time [clock format $($endtimer - $sttimer) -format {%H:%M:%S}] ===" 1 } # # Should be recording now, check if it is # proc chkActive {resv dresv rstatus} { global now svcmap svcdef log "Already started? Status = $rstatus - $dresv" 1 if {$::opts(nonotrec)} { log "-noNotRec - Not checking for failed recording" 2 return } if {$::opts(recwait)+[$resv start] > $now} { log "-recWait - Still within wait interval" 2 return } set svc $svcmap([$resv get hsvc]) set event_id [$resv get usevtid] # Retrieve epg record for the episode set record [lindex [\ epg dbfetch dump -service $svc -event $event_id -sort ""] 0] set epgname [$record get name] set ok true set file [find_file $resv $epgname] # need to check whether it has actually started and schedule alternate if not recording if {$file !=0} { set ifsz [file size "$file.ts"] set cfsz $ifsz for {set i 0} {$i < 5} {incr i} { sleep 1 set cfsz [file size "$file.ts"] if {$cfsz > $ifsz} {break} } if {!($cfsz > $ifsz)} { log "$file.ts size size $cfsz not growing - $dresv" 1 set ok false } else { log "Recording OK - $dresv" 1 return } } set rstatus [$resv status] switch -exact -- $rstatus { "recording" { set ok false log "*** Status recording but Not recording *** - $dresv" 0 } "ready" - "unknown" - "arwatch" { set ok false log "*** Recording not started *** - $dresv" 0 } default { log "*** Status $rstatus Unexpected *** - $dresv" 1 return } } #Find Alternate set epgcrid [$record get event_crid] set def $svcdef([$record get channel_hsvc]) set start [$record get start] set others [epg dbfetch dump -crid $epgcrid -sort "start" ] set other [findAlternate $resv $others $start $def 1] if {$other != ""} { set ostart [$other get start] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" # attempt to schedule the alternate (always 1-off) schedule $other $dother "Alternate for non-recording" conflict-list return } else { log "Unable to schedule alternate for non-recording programme -$dresv " 0 } } # Find file name matching recordings # {There must be a better way of doing it than name matching) proc find_file {resv name} { set files [split [system nugget recordings] "\n"] set nl [split $name {}] foreach file $files { set fl [split [file tail $file] {}] lmap n $nl f $fl { if {$n==$f} {continue} if {$n == {}} { #names matchs check channel and start times match set ts [ts fetch "$file.ts"] if {[$ts get channel_num] != [$resv get usLcn] } {break} if {[$ts get schedstart] != [$resv start] } {break} #puts "$name - $file match" return $file } if {![string is alnum $n]} {continue} break } } return 0 } # # Split recording, check for repeats incorrectly scheduled # proc chkSplit {resv dresv} { global svcmap conflicts svcdef now thresh slot name def log "Split recording - $dresv" 2 if {$::opts(nosplit} { log "-noSplit - Not checking for split recordings" 2 return 0 } # need to check whether any portion is greater than 3hrs after previous set elist [$resv aul] set problems false if {[llength $elist] <= 2} {return 0} set enum -1 set pend [$resv end] set pstart [$resv start] set 3hrs $(3*60*60) set epg {} set first 0 set last 0 set ok true foreach epsd $elist { lassign $epsd service_id start end event_id #puts "$start $end $pend $3hrs" incr enum if {$start > $pend+$3hrs } { log "Split recording >3hrs gap - $dresv" 0 set problems true if {$ok} { break } # try the next repeat showing set ok true set first $enum } set last $enum set pend $end set svc $svcmap($service_id) # Check if segment conflicts if {"$slot$end" in $conflicts} { set ok 0 } # Retrieve epg record for the episode set epg($enum) [lindex [\ epg dbfetch dump -service $svc -event $event_id -sort ""] 0] if {$epg($enum) ==0} { set ok 0 } } if {$problems} { set crid "1[$resv get szCRID]#|" set aul {} set torec {} if {$::opts(noinplace)} { cancel $resv $dresv "Replace Split recording" } loop enum $first $($last+1) { lappend aul [lindex $elist $enum] set torec "$torec$crid" if {$::opts(noinplace)} { # Mark as Unscheduled epg update_lookup_tab $service_id $event_id 0 # Reschedule as 1-off event schedule $epg($enum) $dresv "Replace Split recording" } } if {!$::opts(noinplace)} { $resv set szEventToRecord $torec $resv setaul [$resv buildaul $aul] log "$aul $torec" 2 update_event $resv {} {} $dresv "Replace Split recording" } conflict-list } return $problems } # # check each episode for changes and conflicts # proc chkEpisode {resv epsd ecrid} { global svcmap conflicts svcdef now thresh slot name def lassign $epsd service_id start end event_id set epgcrid [string range $ecrid [string first "/" $ecrid] end] set ecrid [string range $ecrid 1 end] set dur $($end-$start) set deps "[clock format $start -format {%d/%m/%y %H:%M}] [clock format $dur -format {%H:%M}] === slot $slot === $name === [$resv channel_name]" set svc $svcmap($service_id) # Retrieve epg record for the episode set record [lindex [\ epg dbfetch dump -service $svc -event $event_id -sort ""] 0] log "$service_id $start $end $svc $event_id $record $ecrid $epgcrid" 3 if {$record==""} { # # No epg rcord found for the episode - find alternate showing # log "+++ No matching epg entry ++++ $deps" 1 if {$::opts(nomissepg)} { log "-noMissEPG - Not checking for alternate" 2 return } # look for an alternate showing set others [epg dbfetch dump -crid $epgcrid -sort "start" ] # Check what is currently scheduled for that time # If nothing, hole in epg data, dont look to reschedule set showingnow [epg dbfetch dump -service $svc -time "$(($start+$end)/2)" -sort "start" -debug 0 ] if {$showingnow == {}} { log "+++ Nothing in epg forhis time +++ $deps" 1 } else { foreach snow $showingnow { set sname [$snow get name] log "Now scheduled: $sname " 1 if {[string first [strip_new $name] $sname] >= 0 && ![$snow scheduled]} { ladd others $snow } } #puts $others set other [findAlternate $resv $others $start $def 1] if {$other != ""} { set ostart [$other get start] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" # attempt to schedule the alternate (inplace) if {!$::opts(noinplace)} { if {[$other scheduled]} { log "Alternate already scheduled "$deps--->$dother" 1 set other {} } update_event $resv $other $epsd "$deps--->$dother" "Event Changed" conflict-list return } # attempt to schedule the alternate (new event+skip) if {[schedule $other $dother "Event Changed"]} { if {![$resv isseries]} { # delete single recording cancel $resv $deps "Event Changed" } else { # move crid from scheduled to recorded replaceskip $resv $ecrid $deps "Event Changed" #refresh $resv $deps } conflict-list return } } else { # is it a duplicate entry for the sametime and channel? foreach aul [$resv aul] { if {$epsd == $aul} {continue} lassign $aul aservice_id astart aend aevent_id if {$service_id == $aservice_id && $start == $astart} { update_event $resv 0 $epsd "$deps" "Duplicate Event" conflict-list break } } } } } else { # # Epg entry for the episode found # # Check that details match set epgname [$record get name] set def $svcdef([$record get channel_hsvc]) set deps "[clock format $start -format {%d/%m/%y %H:%M}] [clock format $dur -format {%H:%M}] === slot $slot === $epgname === [$record get channel_name]" log "Episode $deps" 2 set ok 1 set reason "no reason" if {$start != [$record get start]} { set ok 0 set reason "Start Mismatch: $start != [$record get start]" log "+++ $reason +++ $deps" 1 } if {$dur != [$record get duration]} { set ok 0 set reason "Duration Mismatch: $dur != [$record get duration]" log "+++ $reason +++ $deps" 1 } set evt_crid [string toupper [$record get event_crid]] if {[$resv issplit]} { set cl [string first "#" $evt_crid] } else { set cl [string length $evt_crid] } if {![string equal -length $cl $epgcrid $evt_crid] && $epgcrid != ""} { set ok 0 set reason "Crid Mismatch: $epgcrid != $evt_crid" log "+++ $reason +++ $deps" 1 } if {!$ok && !$::opts(noepgchg)} { if {!$::opts(noinplace)} { update_event $resv $record $epsd $deps $reason } else { refresh $resv $deps $reason } conflict-list } # Check for conflicts ($conflicts is null if checking supressed) if {"$slot$end" in $conflicts} { set ok 0 log "+++ Confict exists +++ $deps" 1 if {[$resv issplit]} { # dont conflict check split recordings # (might end up with 2 first half or parts out of order) # also cant find alternates with different #IMI return } #set others [$record othertimes] set others [epg dbfetch dump -crid $epgcrid -nocase 1 -sort "start"] set other [findAlternate $resv $others $start $def 0] if {$other != ""} { set ostart [$other get start] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" # attempt to schedule the alternate if {!$::opts(noinplace)} { if {[$other scheduled]} { log "Alternate already scheduled "$deps--->$dother" 1 set other {} } update_event $resv $other $epsd "$deps--->$dother" "Confict resolution" conflict-list continue } if {[schedule $other $dother "Confict resolution"]} { if {![$resv isseries]} { # delete single recording cancel $resv $deps "Conflict resolution" } else { # skip conflicted epidode skip $resv $svc $event_id $deps "Conflict resolution" } conflict-list return } } } } } # Scan others for a suitable alternate episode proc findAlternate {resv others start definition sametime} { # look for alternate with same definition HD/SD/radio set other [scanAlternates $resv $others $start $definition $sametime 1] if {$other == ""} { # scan again wihout requiring matching definition set other [scanAlternates $resv $others $start $definition $sametime 0] } return $other } # Scan others for a suitable alternate episode proc scanAlternates {resv others start definition sametime samedef} { global svcdef foreach other $others { set ostart [$other get start] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set odef $svcdef([$other get channel_hsvc]) set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" # same start time not suitable match for confilcts if {$ostart == $start && !$sametime} {continue} if {$ostart <= [clock seconds]} {continue} # should favour same definition if {$odef != $definition && $samedef} {continue} log "Alternate Episode $dother" 2 set sched [$other scheduled] if {$sched >2} { log "Already skipped - $dother" 2 continue } set oconflicts [rsv checkconflict \ $ostart $odur \ [system tuners]] # Should ignore conflicts with self set cl [llength $oconflicts] if {"$oname" in $oconflicts} {incr cl -1} if {$cl >= [system tuners]} { # Alternate has Conflicts log "Alternate conflicts $oconflicts - $dother" 2 continue } return $other } return "" } # Strip new: prefix from name prior to search proc strip_new {name} { foreach pfx {"new:" "new series." "new "} { if {[string first $pfx [string tolower $name]] == 0} { set name [string range $name [string length $pfx] end] break } } return [string trim $name] } # Check for prossible changes to series CRID # Unscheduled series at same time/channel as an existing Series # Also one-off programmes matching series name proc scrid_chg {resv desc lasttime} { global thresh svcmap now set name [$resv name] set fudge 60 if {$::opts(noscrid) && $::opts(no1off) } { log "-noSCRID/-no1off - Not checking for SCRID change/ one-off recordings" 2 return } set scrid [$resv get szCRID] set svc $svcmap([$resv get hsvc]) set start [$resv start] set timeslot [clock format $start -format "%H:%M"] #if {$lasttime < $now} {set lasttime $now} set lasttime $now set others [epg dbfetch dump -service $svc -term [strip_new $name] -after $lasttime -before $thresh -sort "start" -debug 0] foreach other $others { set ostart [$other get start] set ostarttime [clock format $ostart -format "%H:%M"] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set occrid [$other get channel_crid] set oscrid [$other get series_crid] set oecrid [$other get event_crid] set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" log "Potential event - $dother" 2 if {$ostart <= $now} { log "Already started - $dother" 2 continue } if {$oscrid !=""} { # Event is part of a series, check start time matches if {$ostarttime == $timeslot} { if {$::opts(noscrid)} { log "-noSCRID - Not applying SCRID change" 2 continue } if {[string equal -nocase "$occrid$oscrid" $scrid]} { # found episode of current series log "Current series - $dother" 1 continue } if {[$other scheduled]} { log "Already scheduled - $dother" 2 continue } set oconflicts [rsv checkconflict \ $ostart $odur \ [system tuners]] set cl [llength $oconflicts] if {$cl >= [system tuners]} { log "Potential New series conflicts $oconflicts - $dother " 1 continue } log "Found new series matching $name - $dother - $oscrid" 1 # szCrid not currently updated by rsvsync so cant update inplace if {false && !$::opts(noinplace)} { $resv set szCRID [string toupper "[$other get channel_crid]$oscrid"] puts [$resv get szCRID] set aul1 [lindex [$resv aul] 0] # only remove 1st AUL entry if it is for an expired event lassign $aul1 service_id start end event_id if {$end > $now} {set aul1 {}} update_event $resv $other $aul1 "$desc-->$dother" "sCRID changed" } else { schedule $other "$dother" "sCRID changed" 2 # only schedule 1st episode, allow humax to add others break } } } else { # Single event, but matches series name if {$::opts(no1off) } { log "-no1off - Not scheduling one-off recordings" 2 continue } if {[$other scheduled]} { log "Potential 1-off already scheduled - $dother" 2 continue } set oconflicts [rsv checkconflict \ $ostart $odur \ [system tuners]] set cl [llength $oconflicts] if {$cl >= [system tuners]} { log "Potential 1-off conflicts $oconflicts - $dother" 1 continue } log "Found 1-off matching $name - $dother" 1 if {!$::opts(noinplace)} { update_event $resv $other {} "$desc-->$dother" "1-off recording" } else { schedule $other "$desc-->$dother" "1-off recording" 1 } } } } # Check for missing episoder of a series CRID proc miss_epsd {resv desc} { if {$::opts(nounsched) } { log "-noUnsched - Not checking for missing episodes" 2 return } global thresh svcmap now set name [$resv name] set svc $svcmap([$resv get hsvc]) set start [$resv start] set timeslot [clock format $start -format "%H:%M"] set ecrid [$resv get szCRID] set scrid [string range $ecrid [string first "/" $ecrid] end] set others [epg dbfetch dump -after $now -before $thresh -scrid $scrid -nocase 1 -sort "start"] foreach other $others { set ostart [$other get start] set odur [$other get duration] set oend $($ostart+$odur) set oname [$other get name] set ocname [$other get channel_name] set ocrid [string toupper [$other get event_crid]] set dother "[clock format $ostart -format {%d/%m/%y %H:%M}] [clock format $odur -format {%H:%M}] === $oname === $ocname" if {[string first $ocrid [$resv get szEventToRecord]] >= 0} { log "Already scheduled episode $desc-->$dother" 2 continue } if {[string first $ocrid [$resv get szRecordedProgCrid]] >= 0} { log "Already recorded/skipped episode $desc-->$dother" 2 continue } set skiplist [$resv skiplist] set ohsvc [$other get channel_hsvc] set oevtid [$other get event_id] log "svc $ohsvc evt $oevtid crid $ocrid Skiplist $skiplist" 3 if {[string first "$ohsvc:$oevtid" $skiplist] >= 0} { log "Already skipped episode $desc-->$dother" 2 continue } if {[$other scheduled]} { log "Already scheduled elsewhere $desc-->$dother" continue } log "Found Unscheduled episode $ocrid $desc-->$dother" 1 update_event $resv $other {} "$desc-->$dother" "Unscheduled episode" } } # Create a new reservation proc schedule {event desc {reason ""} {type 1} } { global svcmap if {[$event scheduled]} { log "*** Already scheduled *** $desc === $reason" 0 return 1 } # mark new event as scheduled set service_id [$event get channel_hsvc] set event_id [$event get event_id] epg update_lookup_tab [$event get service_id] $event_id 1 epg update_lookup_tab $service_id $event_id 1 if {$::opts(test)} { log "*** Test mode =scheduled *** $desc === $reason" 0 return 1 } set r [rsv construct $event $type] if {[$r issplit]} { # turn split rcording into 1off by removing #imi from url #$r set ucRecKind 1 $r set szEventToRecord "1[$r get szCRID]|" } if {[catch {$r insert pending} msg]} { log "+++ Error while scheduling: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** scheduled *** $desc === $reason" 0 system restartpending rsv commit return 1 } } # Refresh a reservation proc refresh {resv desc {reason ""}} { if {$::opts(test)} { log "*** Test mode =refreshed *** $desc === $reason" 0 return 1 } set type 1 if {[catch { $resv clear_ulslot $resv set_refresh $resv insert } msg]} { log "+++ Error while refreshing: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** refreshed *** $desc === $reason" 0 system restartpending rsv commit return 1 } } # Cancel reservation proc cancel {resv desc {reason ""}} { global svcmap # mark event as not scheduled set service_id [$resv get hsvc] set event_id [$resv get usevtid] epg update_lookup_tab $service_id $event_id 0 epg update_lookup_tab $svcmap($service_id) $event_id 0 if {$::opts(test)} { log "*** Test mode =cancelled *** $desc === $reason" 0 return 1 } set type 1 if {[catch { $resv clear_ulslot $resv set_delete $resv insert pending 0 1 } msg]} { log "+++ Error while cancelling: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** cancelled *** $desc === $reason" 0 system restartpending rsv commit return 1 } } # Skip an episode - with apply_skip proc skip {resv xservice xevent desc {reason ""}} { if {$::opts(test)} { log "*** Test mode =skipped *** $desc === $reason" 0 return 1 } if {[catch { $resv apply_skip $xservice $xevent } msg]} { log "+++ Error while skipping: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** skipped *** $desc === $reason" 0 system restartpending rsv commit return 1 } } # Skip an episode - with replace_skip proc replaceskip {resv skipcrid desc {reason ""}} { if {$::opts(test)} { log "*** Test mode =skipped *** $desc === $reason" 0 return 1 } if {[catch { $resv clear_ulslot $resv replace_skip [list $skipcrid] $resv insert } msg]} { log "+++ Error while skipping: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** skipped *** $desc === $reason" 0 system restartpending rsv commit return 1 } } # Update reservation with new event details proc update_event {resv other origaul desc {reason ""}} { if {$origaul != {}} { # mark event not scheduled lassign $origaul service_id start end event_id epg update_lookup_tab $service_id $event_id 0 } if {$other != {}} { # mark new event as scheduled set service_id [$other get channel_hsvc] set event_id [$other get event_id] epg update_lookup_tab $service_id $event_id 1 } if {$::opts(test)} { log "*** Test mode =Updated *** $desc === $reason" 0 return 1 } $resv update_aul $other $origaul # update header with next event $resv set_next_event log "$desc - [$resv aul]-[$resv get ucVolume] " 3 if {[catch { $resv insert } msg]} { log "+++ Error while updating: $msg ++++ $desc === $reason" 0 return 0 } else { log "*** Updated *** $desc === $reason" 0 system restartpending # Ensure our copy matches the updated $resv reset_next_event } } #---------------------------------------------------------------------------------------------------------- # Start of mainline set ::optlist "" set ::opt "-h" set ::debug 0 global optarray set logfd stdout if {[info exists ::auto::logfd]} { set logfd $::auto::logfd } # validate parameters checkopts $argv set now [clock seconds] if {$::opts(thresh)} { set thresh $($now + ($::opts(thresh)*60*60)) } else { set thresh $($now + (9*24*60*60)) } log "Threshold $::opts(thresh) = $thresh [clock format $thresh -format {%d/%m/%Y %H:%M:%S}]" 2 # process command switch -- $opt { -rsv { # "scan the recording schedule" rsvscan } -h - --help - default { # Help puts "schedchk = Check for recording schedule issues and attempt to fix them" puts " " puts "schedchk -h = produce this help" puts "schedchk -rsv = scan the recording schedule" puts "" puts "Options Default (unless changed in Settings) " foreach optl $optarray { lassign $optl desc key default helptxt puts [format "-%-11s %-4s = %s" $key $default $helptxt] } puts "\n Note: Options are not case sensitive" } }