# Guide Data Checker (GPL'd)
#
# 01/03/2005 - v1.0.1 - Original version from mrtickle's module
# 23/03/2005 - v1.0.2 - Added support to display gaps and missing data
# 04/04/2003 - v1.0.3 - Now handles channels with no data
set gd_expected 0
proc action_gdchecker {chan path env} {
if {$path == "/"} {
puts $chan [html_start "Guide data checker"]
puts $chan [html_table_start "" "" "ALIGN=TOP"]
puts $chan [tr "" [th "" "Guide data checker"]]
puts $chan [tr "" [td [html_link "/gdchecker/datevschannel" "Date vs channel grid"]]]
puts $chan [tr "" [td [html_link "/gdchecker/orphansps" "Orphaned Season Passes"]]]
puts -nonewline $chan [html_table_end]
puts $chan [html_end]
} elseif {$path == "/datevschannel"} {
action_datevschannel $chan
} elseif {$path == "/orphansps"} {
action_orphansps $chan
} else {
puts $chan "Invalid path: $path"
}
}
proc action_datevschannel {chan} {
global channeltablestation channeltablenum
global db
puts $chan [html_start "Date vs channel grid"]
set overallminday 00000
set overallmaxday 99999
foreach channum [lsort -real [array names channeltablenum]] {
set stationid $channeltablenum($channum)
set data $channeltablestation($stationid)
set favourite [lindex $data 1]
# get min and max dates for this channel
set minday 99999
set maxday 00000
ForeachMfsFile fsid name type "/Schedule" "$stationid:" {
scan $name "%d:%d:" schedsid schedday
if {$minday > $schedday} {
set minday $schedday
}
if {$maxday < $schedday} {
set maxday $schedday
}
}
if {[expr $maxday - $minday] < 3} {
# exclude stations with less than three days data
continue
}
# compare with overall min and max
if {$overallminday < $minday} {
set overallminday $minday
}
if {$overallmaxday > $maxday} {
set overallmaxday $maxday
}
}
# overallminday is now the earliest date that they all have data (some
# may have earlier data, but not all). overallmaxday is now the latest
# date that they all have data (some may have later data, but not all).
if {[expr $overallmaxday - $overallminday] >30} {
set overallmaxday [expr $overallminday + 30]
}
puts $chan [html_table_start "" "" ""]
puts $chan [tr "ALIGN=LEFT" [th ""] [th "F"] [th ""] [gdchecker_dateheadermonths $chan $overallminday $overallmaxday]]
puts $chan [tr "ALIGN=CENTER" [th ""] [th "a"] [th ""] [gdchecker_dateheaderdates $chan $overallminday $overallmaxday]]
puts $chan [tr "ALIGN=CENTER" [th "Num"] [th "v"] [th "Callsign"] [gdchecker_dateheaderdays $chan $overallminday $overallmaxday]]
foreach channum [lsort -real [array names channeltablenum]] {
set stationfsid $channeltablenum($channum)
set data $channeltablestation($stationfsid)
set favourite [lindex $data 1]
set callsign [lindex $data 2]
if { $favourite == 1 } {
set favstr "*"
} else {
set favstr ""
}
# now call all the work
puts $chan [tr "ALIGN=CENTER" [td "ALIGN=LEFT" $channum] [td $favstr] [td "ALIGN=LEFT" [html_link "/channel/$stationfsid" $callsign]] [gdchecker_datelinks $chan $overallminday $overallmaxday $stationfsid]]
}
puts -nonewline $chan [html_table_end]
# now the key table
puts $chan "
"
puts $chan [html_table_start "" "" "ALIGN=TOP"]
puts $chan [tr "" [td ""] [td "ALIGN=left" "Select blobs above to jump to listings for each channel/day"]]
set imagestr "#"
puts $chan [tr "" [td "ALIGN=left" "#"] [td "Schedule ends short"]]
puts $chan [tr "" [td "ALIGN=left" "#"] [td "Schedule starts late"]]
puts $chan [tr "" [td "ALIGN=left" "#"] [td "Gaps in schedule data"]]
puts $chan [tr "" [td "ALIGN=left" "#"] [td "placeholder"]]
puts $chan [tr "" [td "ALIGN=left" "#"] [td "Normal listings"]]
puts $chan [html_table_end]
puts $chan [html_end]
}
proc gdchecker_dateheadermonths {chan minday maxday} {
set minseconds [expr $minday * 86400]
set maxseconds [expr $maxday * 86400]
set outputstr ""
set monthcount 0
set monthlast ""
# month, in header cells
for {set i $minseconds} {$i <= $maxseconds} {incr i 86400} {
set timestr [clock format $i -format "%b"]
if {$timestr != $monthlast} {
if {$monthcount != 0} {
# print block of cells for previous month, reset count
append outputstr [th "colspan=$monthcount" $monthlast]
set monthcount 0
}
}
set monthlast $timestr
incr monthcount
}
# print final block of cells
append outputstr [th "colspan=$monthcount" $monthlast]
return $outputstr
}
proc gdchecker_dateheaderdates {chan minday maxday} {
set minseconds [expr $minday * 86400]
set maxseconds [expr $maxday * 86400]
set outputstr ""
# date, in a header cell
for {set i $minseconds} {$i <= $maxseconds} {incr i 86400} {
set timestr [clock format $i -format "%e"]
append outputstr [th $timestr]
}
return $outputstr
}
proc gdchecker_dateheaderdays {chan minday maxday} {
set minseconds [expr $minday * 86400]
set maxseconds [expr $maxday * 86400]
set outputstr ""
# weekday, in a header cell, only want 1st char
for {set i $minseconds} {$i <= $maxseconds} {incr i 86400} {
set timestr [clock format $i -format "%a"]
set timestr [string index $timestr 0]
append outputstr [th $timestr]
}
return $outputstr
}
proc gdchecker_datelinks {chan minday maxday stationfsid} {
global channeltablestation
global gd_expected
# puts $chan "DEBUG: STATIONFSID $stationfsid
"
if {[string index $stationfsid 0] == "/"} {
set stationfsid [string range $stationfsid 1 end]
}
set firstslash [string first "/" $stationfsid]
set seconds ""
if { $firstslash != -1 } {
set stationid [string range $stationfsid 0 [expr $firstslash - 1]]
set seconds [string range $stationfsid [expr $firstslash + 1] end]
} else {
set stationid $stationfsid
}
set minseconds [expr $minday * 86400]
set maxseconds [expr $maxday * 86400]
set outputstr ""
set gd_expected 0
# output a line of cells
for {set i $minseconds} {$i <= $maxseconds} {incr i 86400} {
set timestr [clock format $i -format "%e"]
# now check the station for known patterns
if { [catch {set data $channeltablestation($stationid)}] != 1 } {
set blobstr [split [gdchecker_listings $chan $stationid $i] "|"]
# IE: regsub {,} $blobstr "\n" blobstr
set imagestr "#"
} else {
# SEVERE error - unknown channel, couldn't read callsign
set imagestr "X"
}
append outputstr [td [html_link "/listings/$stationid/$i" $imagestr]]
}
return $outputstr
}
proc gdchecker_listings {chan stationid seconds} {
global db
global channeltablestation
global channeltablenum
set listingsoutputstr ""
set day [expr $seconds / 86400]
set startsecs $seconds
set endsecs [expr $startsecs + 86400]
ForeachMfsFileTrans fsid name type "/Schedule" "$stationid:$day:" 10 {
append listingsoutputstr [gdchecker_listingsrow $chan $fsid $startsecs $endsecs]
}
if {$listingsoutputstr == ""} {
return "blue|No guide data"
} else {
return $listingsoutputstr
}
}
proc gdchecker_listingsrow {chan fsid startsecs endsecs} {
global db
global tzoffset
global gd_expected
set secs 0
set duration 0
set colour "green"
set info ""
set stationday [db $db openid $fsid]
set showings [dbobj $stationday get Showing]
foreach showing $showings {
set time [dbobj $showing get Time]
set secs [expr [dbobj $showing get Date] * 86400 + $time + $tzoffset]
if { $secs >= $startsecs && $secs < $endsecs } {
if {$gd_expected > 0 && $duration == 0 && $secs > $gd_expected && $secs > $startsecs} {
set timestr [clock format $secs -format "%H:%M"]
set info "${info},Day starts late: $timestr"
set colour "orange"
}
if {$gd_expected > 0 && $duration > 0 && $secs != $gd_expected} {
set timestr [clock format $secs -format "%H:%M"]
set timeexp [clock format $gd_expected -format "%H:%M"]
set info "${info},Gap in data: $timeexp-$timestr"
set colour "yellow"
}
set duration [dbobj $showing get Duration]
set gd_expected [expr $secs + $duration]
}
}
if { [expr $secs + $duration] < $endsecs } {
set timestr [clock format [expr $secs + $duration] -format "%H:%M"]
set info "${info},Day ends short: $timestr"
set colour "red"
}
if {[string index $info 0] == ","} {
set info [string range $info 1 end]
}
return "$colour|$info"
}
# #############################################################
proc action_orphansps {chan} {
global db
global tzoffset
global seasonpassdir
puts $chan [html_start "Orphaned Season Pass episodes"]
set priority 0
set splist ""
ForeachMfsFileTrans fsid name type $seasonpassdir "" 20 {
set sp [db $db openid $fsid]
set type [defaultval 1 [dbobj $sp get Type]]
incr priority
lappend splist $priority
if { $type == 1 } {
set series [dbobj $sp get Series]
set spfsid [dbobj $sp fsid]
set seriesfsid [dbobj $series fsid]
set title [strim [dbobj $series get Title]]
lappend splist $seriesfsid $title
set station [dbobj $sp get Station]
set stationfsid [dbobj $station fsid]
set callsign [dbobj $station get CallSign]
lappend splist $stationfsid $callsign
} elseif { $type == 2 } {
set station [dbobj $sp get Station]
set stationfsid [dbobj $station fsid]
set starttimelocal [defaultval 0 [dbobj $sp get StartTimeLocal]]
set starttime [expr $starttimelocal - $tzoffset]
set dowlocal [dbobj $sp get DayOfWeekLocal]
if { [llength $dowlocal] > 1 } {
set rectime ""
foreach dowl $dowlocal {
set tmprectime [get_nextmanualrectime $dowl $starttime]
if { $rectime == "" || $tmprectime < $rectime } {
set rectime $tmprectime
}
}
} else {
set rectime [get_nextmanualrectime $dowlocal $starttime]
}
set datestr [expr $rectime / 86400]
set schedlist [get_fsidbyprefix "/Schedule" "$stationfsid:$datestr:"]
if { [scan [lindex $schedlist 1] "%d:%d:%d:%d:" dummy dummy2 starttimesched duration] == 4 } {
regsub {^0+([1-9])} $starttimesched {\1} starttimesched
regsub {^0+([1-9])} $duration {\1} duration
if {$starttimesched > $starttime} {
set datestr [expr ($rectime / 86400) - 1]
set schedlist [get_fsidbyprefix "/Schedule" "$stationfsid:$datestr:"]
if { [scan [lindex $schedlist 1] "%d:%d:%d:%d:" dummy dummy2 starttimesched duration] != 4 } {
error "Invalid /Schedule format: '[lindex $schedlist 1]'"
}
regsub {^0+([1-9])} $starttimesched {\1} starttimesched
regsub {^0+([1-9])} $duration {\1} duration
}
if { $::dtivo } {
if {$starttimesched + $duration <= $starttime} {
set stoptimestr [format "%05d" [expr $starttimesched + $duration]]
set schedlist [get_fsidbyprefix "/Schedule" "$stationfsid:$datestr:$stoptimestr:"]
}
}
} else {
#error "Invalid /Schedule format: '[lindex $schedlist 1]'"
}
set callsign [dbobj $station get CallSign]
set spfsid [dbobj $sp fsid]
if { $schedlist != "" } {
set stationday [db $db openid [lindex $schedlist 0]]
set showings [dbobj $stationday get Showing]
set mshowing ""
foreach showing $showings {
set stime [dbobj $showing get Time]
set sdur [dbobj $showing get Duration]
if { $stime <= $starttime && $starttime < [expr $stime + $sdur] } {
set mshowing $showing
break
}
}
if { $mshowing != "" } {
set program [dbobj $mshowing get Program]
set series [dbobj $program get Series]
set seriesfsid [dbobj $series fsid]
set title [strim [dbobj $series get Title]]
set title [html_link "/series/$seriesfsid" $title]
lappend splist $seriesfsid $title
} else {
lappend splist 0 "Manual Recording"
# puts "Error finding manual recording"
}
} else {
lappend splist 0 "Manual Recording"
# puts "Error finding manual recording"
}
lappend splist $stationfsid $callsign
} elseif { $type == 3 } {
#wishlist
set theme [dbobj $sp get Theme]
set spfsid [dbobj $sp fsid]
set themefsid [dbobj $theme fsid]
set title [strim [dbobj $theme get Name]]
lappend splist 0 $title 0 ""
}
}
# do this once here, rather than once per search
update_sp_cache
# now print the table from the list, and do searches against each title
puts $chan [html_table_start "" "" ""]
puts $chan [tr "ALIGN=CENTER" [th "Pri"] [th "Title"] [th "Channel"] [th "Matches found from title search"]]
foreach {priority seriesid title stationfsid callsign} $splist {
set rowstr ""
append rowstr [td $priority]
if {$stationfsid == 0} {
# wishlist
append rowstr [td $title] [td "(wishlist)"]
} elseif {$seriesid == 0} {
# some manual SPs
append rowstr [td $title]
append rowstr [td [html_link "/channel/$stationfsid" $callsign]]
} else {
# normal SPs and manual SPs
append rowstr [td [html_link "/series/$seriesid" $title]]
append rowstr [td [html_link "/channel/$stationfsid" $callsign]]
}
# now search for this title, and see how many results we get
# more than one result could be bad! let the user decide
if {$seriesid == 0} {
# don't do the search for wishlists
append rowstr [td "(search not performed)"]
} else {
append rowstr [td [action_spsearch $title]]
}
puts $chan [tr "" $rowstr]
}
puts $chan [html_table_end]
puts $chan [html_end]
}
proc action_spsearch {title} {
global cache_sp_key
global images
# Now output search results. This was a search action
regsub -nocase {^(a|the) } $title {} modq
regsub -all {\$} $modq {} modq
regsub -all {\*} $modq {} modq
regsub -all {\,} $modq {} modq
regsub -all {[^A-Za-z0-9\*\", ]} $modq {} modq
regsub -all {\"} $modq {} modq
regsub "\t$" $modq {} dispq
if {[string length $dispq] == 0} {
return [h2 "Error, empty search query"]
}
if {[string length $dispq] < 2} {
return [h2 "Error, require at least 2 characters in query"]
}
set searchResultsTitle [htmlEncode $dispq]
#set searchResultsTitle "Search Results for \"$searchResultsTitle\""
set fsids [get_textindexsearch $modq 0]
if {[lindex $fsids 0] == -1} {
return "No matches found in the current Guide Data"
} elseif {[lindex $fsids 0] == -2} {
return "Error running search [lrange $fsids 1 end]"
} else {
set spsearch_output ""
# update_sp_cache
foreach item [lrange $fsids 1 end] {
set seriestitle [lindex $item 0]
set fsid [lindex $item 1]
set fsid [expr 0x$fsid]
set genres [lindex $item 2]
regsub {^(.*), (A|The)$} $seriestitle {\2 \1} seriestitle
set slists [get_programshowings $fsid 1]
if {$slists != ""} {
set index [lsearch $cache_sp_key "$fsid|*"]
if {$index > -1} {
set imagestr [img "alt=\"\"" [lindex $images 11]]
} else {
set imagestr "X"
}
set link "/series/$fsid"
if {$spsearch_output != ""} {
set spsearch_output "$spsearch_output
$imagestr [html_link $link [htmlEncode $seriestitle]]"
} else {
set spsearch_output "$imagestr [html_link $link [htmlEncode $seriestitle]]"
}
}
}
if {$spsearch_output != ""} {
return "$spsearch_output"
} else {
return "No matches found in the current Guide Data"
}
}
}
register_module "gdchecker" "GDchecker" "Check Guide Data"