# Copyright (c) 2001 Josha Foust (tivoweb@lightn.org) # $Id: sched.itcl,v 1.2 2005/08/03 06:02:46 davidlallen Exp $ proc RecConflicts { recfsid showing2start showing2end } { global db RetryTransaction { set rec [db $db openid $recfsid] set showing1 [dbobj $rec get Showing] set showing1realstart [expr [dbobj $showing1 get Date] * 86400 + [dbobj $showing1 get Time]] set showing1start [expr $showing1realstart - [defaultval 0 [dbobj $rec get StartPadding]]] set showing1end [expr $showing1realstart + [dbobj $showing1 get Duration] + [defaultval 0 [dbobj $rec get EndPadding]]] if { (($showing1start >= $showing2start) && ($showing1start < $showing2end)) || (($showing1end > $showing2start) && ($showing1end <= $showing2end)) || (($showing1start <= $showing2start) && ($showing1end >= $showing2end))} { if {$::version >= 3} { set recbeh [dbobj $rec get RecordingBehavior] set seltype [dbobj $recbeh get PresentationBehavior] } else { set seltype [dbobj $rec get SelectionType] } if { $seltype == 6 } { return 1 } else { return 2 } } else { return 0 } } } proc RecConflictsList { showingstart showingend } { global db set cancellist {} set cancellistsug {} for {set i -1} {$i <= 1} {incr i} { set date [expr $showingstart / 86400 + $i] ForeachMfsFile fsid name type "/Recording/Active" "4:$date:" { set skip 0 if { [scan name "4:%d:%d:" scandate scantime] == 2 } { regsub {^0+([1-9])} $scantime {\1} scantime set scansecs [expr $scandate * 86400 + $scantime] if {$scansecs < [expr $showingstart - 86400]} { set skip 1 } if {$scansecs > $showingend} { return [list $cancellist $cancellistsug] } } if {!$skip} { set conflicts [RecConflicts $fsid $showingstart $showingend] if { $conflicts == 1 } { lappend cancellistsug $fsid } elseif { $conflicts == 2 } { lappend cancellist $fsid } } } } return [list $cancellist $cancellistsug] } proc GetConflictsList { showingfsid startearlysecs endlatesecs } { global db RetryTransaction { if { [regexp {([0-9]*)/(.*)} $showingfsid junk fsid subobjid] } { set showing [db $db openid $fsid $subobjid] } else { set showing [db $db openid $showingfsid] } set date [dbobj $showing get Date] set time [dbobj $showing get Time] set duration [dbobj $showing get Duration] set showingstart [expr $date * 86400 + $time] set showingend [expr $showingstart + $duration + $endlatesecs] set showingstart [expr $showingstart - $startearlysecs] } set cancellists [RecConflictsList $showingstart $showingend] set cancellist [lindex $cancellists 0] return $cancellist } # Channel 4 # Guide 11 # Name 3 proc MakeTodoRecording { showingfsid recquality howSelected startearlysecs endlatesecs kal authcancellist } { global db set nowtime [clock seconds] set legalrecquals "0 40 75 100" if { [lsearch $legalrecquals $recquality] == -1 } { puts "Error: Illegal record quality" return -1 } # puts "'$showingfsid' '$recquality' '$howSelected' '$startearly' '$endlate' '$kal' '$authcancellist'" # dumpobj $showingfsid RetryTransaction { if { [regexp {([0-9]*)/(.*)} $showingfsid junk fsid subobjid] } { set showing [db $db openid $fsid $subobjid] } else { set showing [db $db openid $showingfsid] } set station [dbobj $showing get Station] set stationfsid [dbobj $station fsid] set date [dbobj $showing get Date] set time [dbobj $showing get Time] set duration [dbobj $showing get Duration] set showingstart [expr $date * 86400 + $time] set showingend [expr $showingstart + $duration + $endlatesecs] set showingstart [expr $showingstart - $startearlysecs] } if { $nowtime > $showingstart } { puts "Error: Showing started in the past" return -2 } set cancellists [RecConflictsList $showingstart $showingend] set cancellist [lindex $cancellists 0] set cancellistsug [lindex $cancellists 1] if { $::dtivo && $::num_tuners == 2 } { set conflicts 0 foreach conflict $cancellist { RetryTransaction { set cc_rec [db $db openid $conflict] set cc_showing [dbobj $cc_rec get Showing] set cc_showingfsid "[dbobj $cc_showing fsid]/[dbobj $cc_showing subobjid]" set cc_startearlysecs [defaultval 0 [dbobj $cc_rec get StartPadding]] set cc_endlatesecs [defaultval 0 [dbobj $cc_rec get EndPadding]] } set conflict_conflictslist [GetConflictsList $cc_showingfsid $cc_startearlysecs $cc_endlatesecs] set conflictindex [lsearch -exact $conflict_conflictslist $conflict] set conflict_conflictslist [lreplace $conflict_conflictslist $conflictindex $conflictindex] foreach conflict_conflict $conflict_conflictslist { if { [lsearch -exact $cancellist $conflict_conflict] != -1 } { incr conflicts } } } if { $conflicts == 0 } { set conflictssug 0 set cancellistsug_actual {} foreach conflict $cancellistsug { RetryTransaction { set cc_rec [db $db openid $conflict] set cc_showing [dbobj $cc_rec get Showing] set cc_showingfsid "[dbobj $cc_showing fsid]/[dbobj $cc_showing subobjid]" set cc_startearlysecs [defaultval 0 [dbobj $cc_rec get StartPadding]] set cc_endlatesecs [defaultval 0 [dbobj $cc_rec get EndPadding]] set cc_duration [dbobj $cc_showing get Duration] set cc_date [dbobj $cc_showing get Date] set cc_time [dbobj $cc_showing get Time] set cc_showingstart [expr $cc_date * 86400 + $cc_time] set cc_showingend [expr $cc_showingstart + $cc_duration + $cc_endlatesecs] set cc_showingstart [expr $cc_showingstart - $cc_startearlysecs] } set conflict_conflictslists [RecConflictsList $cc_showingstart $cc_showingend] set conflict_conflictslist [concat [lindex $conflict_conflictslists 0] [lindex $conflict_conflictslists 1]] set conflictindex [lsearch -exact $conflict_conflictslist $conflict] set conflict_conflictslist [lreplace $conflict_conflictslist $conflictindex $conflictindex] foreach conflict_conflict $conflict_conflictslist { if { [lsearch -exact $cancellist $conflict_conflict] != -1 } { lappend cancellistsug_actual $conflict } elseif { [lsearch -exact $cancellistsug $conflict_conflict] != -1 && [lsearch -exact $cancellistsug_actual $conflict] == -1 && [lsearch -exact $cancellistsug_actual $conflict_conflict] == -1 } { lappend cancellistsug_actual $conflict } } } set cancellist {} set cancellistsug $cancellistsug_actual } } if { [llength $cancellist] > 0 } { # Check if all conflicts are in the authorized cancel list # IE the list we showed the user foreach cancelfsid $cancellist { if { [lsearch $authcancellist $cancelfsid] == -1 } { puts "Error: Unauthorized cancel fsid '$cancelfsid'" return -3 } } # Cancel conflicts foreach cancelfsid $cancellist { DeleteTodoRec $cancelfsid 10 "Deleting to record another program" } } # Cancel conflicting suggestions silently if { [llength $cancellistsug] > 0 } { foreach cancelfsid $cancellistsug { DeleteTodoRec $cancelfsid 10 "Deleting to record another program" } } set previousrecfsid "" set timestr [format "%05d" $time] # ForeachMfsFile fsid name type "/Recording/Cancelled" "$date:$timestr:$stationfsid:" { # if { $previousrecfsid != "" } { # puts "Error: uhh, more than one recording in a date/time/station slot" # return -4 # } # set previousrecfsid $fsid # } RetryTransaction { set previousrecfsid [lindex [get_fsidbyprefix "/Recording/Cancelled" "$date:$timestr:$stationfsid:"] 0] if { $previousrecfsid != "" } { # Use a previously scheduled and cancelled recording if it exists set recordingfsid $previousrecfsid # puts "set recordingfsid $previousrecfsid" set recording [db $db openid $recordingfsid] # puts "set recording \[db $db openid $recordingfsid\]" # puts "Recording (prev): $recordingfsid" set confrec [dbobj $recording get ConflictsWithRecording] if { $confrec != "" } { set confstate [dbobj $confrec get State] set confseltype [dbobj $confrec get SelectionType] if { $confstate == 6 && $confseltype == 9 } { dbobj $confrec set ConflictsWithRecording $recording # puts "dbobj $confrec set ConflictsWithRecording $recording" dbobj $confrec set CancelReason 2 # puts "dbobj $confrec set CancelReason 2" dbobj $confrec set CancelDate [expr $nowtime / 86400] # puts "dbobj $confrec set CancelDate \[expr $nowtime / 86400\]" dbobj $confrec set CancelTime [expr $nowtime % 86400] # puts "dbobj $confrec set CancelTime \[expr $nowtime % 86400\]" dbobj $confrec set ErrorString "Deleting to record another program" # puts "dbobj $confrec set ErrorString \"Deleting to record another program\"" # \{User requested explicit 11487 18300 - Got instead 0 (2475 MB)(11487 18300)(5400):E!:75\} dbobj $confrec set State 2 # puts "dbobj $confrec set State 2" } } dbobj $recording remove ConflictsWithRecording # puts "dbobj $recording remove ConflictsWithRecording" } else { if { [regexp {([0-9]*)/(.*)} $showingfsid junk fsid subobjid] } { set showing [db $db openid $fsid $subobjid] # puts "set showing \[db $db openidconstruction $fsid $subobjid\]" } else { set showing [db $db openid $showingfsid] # puts "set showing \[db $db openid $showingfsid\]" } set recording [db $db create Recording] set recordingfsid [dbobj $recording fsid] # puts "set recording \[db $db create Recording\]" # puts "set recordingfsid \[dbobj $recording fsid\]" # puts "Recording: $recordingfsid" set newshowing [db $db createsub Showing $recording] dbobj $newshowing copyfrom $showing dbobj $newshowing set Reason 2 dbobj $recording set Showing $newshowing # puts "set newshowing \[db $db createsub Showing $recording\]" # puts "dbobj $newshowing copyfrom $showing" # puts "dbobj $newshowing set Reason 2" # puts "dbobj $recording set Showing $newshowing" } set showingfsid [dbobj $recording gettarget Showing] # puts "set showingfsid \[dbobj $recording gettarget Showing\]" dbobj $recording set BitRate 0 # puts "dbobj $recording set BitRate 0" if { $kal == 0 } { dbobj $recording set ExpirationDate 24855 dbobj $recording set ExpirationTime 0 # puts "dbobj $recording set ExpirationDate 24855" # puts "dbobj $recording set ExpirationTime 0" } else { dbobj $recording set ExpirationDate [expr $date + $kal] dbobj $recording set ExpirationTime $time # puts "dbobj $recording set ExpirationDate [expr $date + $kal]" # puts "dbobj $recording set ExpirationTime $time" } if {$::version >= 3} { dbobj $recording set DeletionDate 24855 dbobj $recording set UsedBy 1 } dbobj $recording set RecordQuality $recquality # puts "dbobj $recording set RecordQuality $recquality" if { $startearlysecs != 0 } { dbobj $recording set StartPadding $startearlysecs # puts "dbobj $recording set StartPadding \[expr 60 * $startearly\]" } if { $endlatesecs != 0 } { dbobj $recording set EndPadding $endlatesecs # puts "dbobj $recording set EndPadding \[expr 60 * $endlate\]" } if { [dbobj $recording get Score] == "" } { if {$::version >= 3} { dbobj $recording set Score 0 } else { dbobj $recording set Score 9900 } # puts "dbobj $recording set Score 9900" } # Should probably have some more accurate code here dbobj $recording set SelectionType $howSelected if {$::version >= 3} { set newrecbeh [db $db createsub RecordingBehavior $recording] dbobj $newrecbeh set DiskBehavior 5 #dbobj $newrecbeh set DiskBehavior 2 dbobj $newrecbeh set PresentationBehavior 1 dbobj $newrecbeh set ProgramGuideBehavior 1 dbobj $newrecbeh set TunerBehavior 1 dbobj $recording set RecordingBehavior $newrecbeh } # puts "dbobj $recording set SelectionType $howSelected" dbobj $recording set State 6 # puts "dbobj $recording set State 6" } return $showingfsid } proc DeleteNowShowingRec { recfsid } { global db set canceldate [expr [clock seconds] / 86400] set canceltime [expr [clock seconds] % 86400] RetryTransaction { set rec [db $db openid $recfsid] set state [dbobj $rec get State] if { $state != 4 } { return 0 } else { dbobj $rec set CancelReason 12 dbobj $rec set DeletionDate $canceldate dbobj $rec set DeletionTime $canceltime set errorstring [dbobj $rec get ErrorString] set elength [string length $errorstring] if { $elength > 0 } { set errorstring [string trim $errorstring "\{\}"] dbobj $rec set ErrorString "$errorstring Deleted by user" } else { dbobj $rec set ErrorString "Deleted by user" } dbobj $rec set State 5 } } return 1 } proc CancelAllSeries { objectid } { global db set cancellist {} ForeachMfsFile fsid name type "/Recording/Active" "4" { RetryTransaction { set rec [db $db openid $fsid] set showing [dbobj $rec get Showing] set program [dbobj $showing get Program] set series [dbobj $program get Series] set seriesfsid [dbobj $series fsid] if {$seriesfsid == $objectid} { lappend cancellist $fsid } } } foreach cancelid $cancellist { DeleteTodoRec $cancelid 24 "Cancelled by user" } } proc UndeleteRec { recfsid } { global db RetryTransaction { set rec [db $db openid $recfsid] set state [dbobj $rec get State] if { $state != 5 } { return 0 } else { set parts [dbobj $rec get Part] if { $parts == "" } { return 0 } else { dbobj $rec remove CancelReason dbobj $rec remove CancelDate dbobj $rec remove CancelTime dbobj $rec remove ErrorString dbobj $rec set State 4 } } } return 1 } proc DeleteTodoRec { recfsid cancelreason errorstring } { global db set canceldate [expr [clock seconds] / 86400] set canceltime [expr [clock seconds] % 86400] RetryTransaction { set rec [db $db openid $recfsid] set state [dbobj $rec get State] if { $state != 6 } { return 0 } else { dbobj $rec set CancelReason $cancelreason dbobj $rec set CancelDate $canceldate dbobj $rec set CancelTime $canceltime dbobj $rec set ErrorString $errorstring dbobj $rec set State 2 } } return 1 } proc CreateSeasonPass { sptype stationfsid seriesfsid quality startearlysecs endlatesecs kam showtype keepuntil } { global db global seasonpassdir # New SeasonPass format for DTivo v6.3 software if [PrefixMatches "6.3" $::tivoswversion] { # # HACK: Don't yet know how to create NpkChannelDefinition so # we will try and reuse an existing one and see if that # works. # set NpkChannelDefinition "Required" } else { set NpkChannelDefinition "N/A" } set maxpri -1 ForeachMfsFile fsid name type $seasonpassdir "" { scan $name "%d~%d" num dummy if { $num > $maxpri } { set maxpri $num } if {$NpkChannelDefinition == "Required"} { # Check to see if an existing Npk value can be reused catch { RetryTransaction { set spfsid [db $db openid $fsid] set station [dbobj $spfsid get Station] if {[dbobj $station fsid] == $stationfsid} { set NpkChannelDefinition [dbobj $spfsid get NpkChannelDefinition] } } } } } incr maxpri if {$NpkChannelDefinition == "Required"} { # Npk was not found in SeasonPasses so let's check in Recordings ForeachMfsFileTrans fsid name type "/Recording/Active" "" 15 { if {$NpkChannelDefinition == "Required"} { set spfsid [db $db openid $fsid] set showing [dbobj $spfsid get Showing] set station [dbobj $showing get Station] if {[dbobj $station fsid] == $stationfsid} { set NpkChannelDefinition [dbobj $spfsid get NpkChannelDefinition] } } } if {$NpkChannelDefinition == "Required"} { return 0 } } RetryTransaction { set sp [db $db create SeasonPass] dbobj $sp set Type $sptype dbobj $sp set Priority $maxpri if { $sptype == 1 } { set series [db $db openid $seriesfsid] dbobj $sp set Series $series if {$::version >= 3} { dbobj $sp set ShowStatus $showtype } else { dbobj $sp set FirstRun $showtype } } set station [db $db openid $stationfsid] dbobj $sp set Station $station dbobj $sp set RecordQuality $quality if { $startearlysecs != 0 } { dbobj $sp set StartTimePadding $startearlysecs } if { $endlatesecs != 0 } { dbobj $sp set EndTimePadding $endlatesecs } if { $kam != 0 } { dbobj $sp set MaxRecordings $kam } if { $keepuntil != 1 } { dbobj $sp set KeepTime $keepuntil } if {$NpkChannelDefinition != "N/A"} { foreach item $NpkChannelDefinition { dbobj $sp add NpkChannelDefinition $item } } set spfsid [dbobj $sp fsid] } return $spfsid } proc UpdateSeasonPass { objectid showtype startearlysecs endlatesecs quality kam keepuntil } { global db RetryTransaction { set sp [db $db openid $objectid] set type [defaultval 1 [dbobj $sp get Type]] if { $type == 1 || $type == 3 } { if {$::version >= 3} { set oldfirstrun [defaultval 0 [dbobj $sp get ShowStatus]] if { $oldfirstrun != $showtype } { dbobj $sp set ShowStatus $showtype } } else { set oldfirstrun [defaultval 0 [dbobj $sp get FirstRun]] if { $oldfirstrun != $showtype } { dbobj $sp set FirstRun $showtype } } } set oldstarttime [defaultval 0 [dbobj $sp get StartTimePadding]] if { $oldstarttime != $startearlysecs } { if { $startearlysecs == 0 } { dbobj $sp remove StartTimePadding } else { dbobj $sp set StartTimePadding $startearlysecs } } set oldendtime [defaultval 0 [dbobj $sp get EndTimePadding]] if { $oldendtime != $endlatesecs } { if { $endlatesecs == 0 } { dbobj $sp remove EndTimePadding } else { dbobj $sp set EndTimePadding $endlatesecs } } set oldrecquality [defaultval 100 [dbobj $sp get RecordQuality]] if { $oldrecquality != $quality } { dbobj $sp set RecordQuality $quality } set oldkeepatmost [defaultval 0 [dbobj $sp get MaxRecordings]] if { $oldkeepatmost != $kam } { dbobj $sp set MaxRecordings $kam } set oldkeepuntil [defaultval 1 [dbobj $sp get KeepTime]] if { $oldkeepuntil != $keepuntil } { dbobj $sp set KeepTime $keepuntil } } } proc DeleteSeasonPass { spfsid } { global db set canceldate [expr [clock seconds] / 86400] set canceltime [expr [clock seconds] % 86400] ForeachMfsFile fsid name type "/Recording/Active" "4" { RetryTransaction { set rec [db $db openid $fsid] set state [dbobj $rec get State] if { $state == 6 } { set match 0 set spobjs [dbobj $rec get ProgramSource] foreach spobj $spobjs { set sfsid [dbobj $spobj fsid] if { $sfsid == $spfsid } { set match 1 } else { set indexpath [dbobj $spobj get IndexPath] if { [regexp {/Rubbish/} $indexpath dummy] == 0 } { set match 0 break } } } if { $match } { dbobj $rec set CancelReason 16 dbobj $rec set CancelDate $canceldate dbobj $rec set CancelTime $canceltime dbobj $rec set ErrorString "FindActions" dbobj $rec set State 2 } } } } RetryTransaction { set sp [db $db openid $spfsid] dbobj $sp markasrubbish } }