# Copyright (c) 2001 Josha Foust (tivoweb@lightn.org) # $Id: index.itcl,v 1.25.2.10 2003/01/01 02:15:24 lightn Exp $ proc get_recordindexsearch {indexfsid startoffset maxoffset recsize incrsize searchkey searchtype matchsize} { set match 0 for {set offset $startoffset} {$offset < $maxoffset} {incr offset $incrsize} { set end $incrsize if { $maxoffset - $offset < $incrsize } { set end [expr $maxoffset - $offset] } RetryTransaction { set indexdata [mfs getpart $indexfsid $offset $end] } set slen [expr $end / $recsize] set top $slen set current [expr $top / 2] set bottom 0 set count 0 while { $top >= $bottom } { set data [string range $indexdata [expr $current * $recsize] [expr $current * $recsize + $matchsize]] #binary scan $data H8 fsidnum #puts "$searchtype $offset $top $bottom $current [expr 0x$fsidnum]" set compare [string compare $data $searchkey] if {$compare == 0 || ($searchtype == 0 && $compare == 1)} { if { $current <= 0 } { set match 1 break } set data2 [string range $indexdata [expr ($current-1) * $recsize] [expr ($current-1) * $recsize + $matchsize]] if {[string compare $data2 $searchkey] == -1} { set match 1 break } else { set top [expr $current - 1] } } elseif {$compare == -1} { set bottom [expr $current + 1] } else { set top [expr $current - 1] } set current [expr $bottom + ($top - $bottom) / 2] incr count if { $count > $slen } { error "Error: infinite loop in binary search ($bottom $top $current $slen)" } } if { $match == 1} { if {$searchtype == 2} { set data [string range $indexdata [expr $current * $recsize + $matchsize + 1] [expr ($current+1) * $recsize - 1]] unset indexdata return $data } else { unset indexdata return [expr ($offset-$startoffset)/$recsize + $current] } } } unset indexdata if {$searchtype == 2} { return "" } else { return -1 } } proc get_programshowings {progfsid watch args} { global db global guideindexdir global programindexstartday global channeltablefsid global channeltablestation global channeltablenum global channeltableindex global version3 set nowsecs [clock seconds] if {[llength $args] > 0} { set genres [lindex $args 0] } else { set genres "" } set reload_index 0 RetryTransaction { set channelfsid [lindex [mfs find $guideindexdir/ChannelTable] 0] if { $channeltablefsid != $channelfsid } { set reload_index 1 } if {$genres != ""} { set showingkeyfsid [lindex [mfs find $guideindexdir/Showing.key] 0] set showingindex [lindex [mfs find $guideindexdir/Showing.index] 0] set showingkeydata [mfs getpart $showingkeyfsid 0x0 0x18] } set programkeyfsid [lindex [mfs find $guideindexdir/Program.key] 0] set programindex [lindex [mfs find $guideindexdir/Program.index] 0] set programkeydata [mfs getpart $programkeyfsid 0x0 0x18] } binary scan [string range $programkeydata 0x00 0x03] I recsize binary scan [string range $programkeydata 0x04 0x07] I totalnumkeys binary scan [string range $programkeydata 0x08 0x0B] I incrsize binary scan [string range $programkeydata 0x10 0x13] I numkeys binary scan [string range $programkeydata 0x14 0x17] I programindexstartday if {$genres != ""} { binary scan [string range $showingkeydata 0x00 0x03] I showingrecsize binary scan [string range $showingkeydata 0x04 0x07] I showingtotalnumkeys binary scan [string range $showingkeydata 0x08 0x0B] I showingincrsize binary scan [string range $showingkeydata 0x10 0x13] I showingnumkeys } if { $reload_index } { init_channelindex init_genreindex init_ns_cache } set fsidbin [binary format I $progfsid] set startoffset 24 set maxoffset [expr $startoffset + $recsize * $numkeys] set first [get_recordindexsearch $programkeyfsid $startoffset $maxoffset $recsize $incrsize $fsidbin 0 3] if { $first == -1 } { error "Error couldn't find starting offset in program key" } set startoffset [expr $first * $incrsize] set maxoffset [expr $startoffset + $incrsize] if { $maxoffset > $recsize * $totalnumkeys } { set maxoffset [expr $recsize * $totalnumkeys] } set current [get_recordindexsearch $programindex $startoffset $maxoffset $recsize $incrsize $fsidbin 1 3] set showings "" if {$current >= 0} { if {$watch == 0} { RetryTransaction { set channeltabledata [mfs get $channeltablefsid] } } set i [expr ($current-1) * $recsize] set compare 0 set offset $startoffset set init 1 set prevstation "" set prevsecs "" while { $compare == 0 } { incr i $recsize if { $init == 1 || ($i >= $end && $compare == 0) } { if { $init == 0 } { set i 0 incr offset $incrsize } set end $incrsize if { $offset + $end > $recsize * $totalnumkeys } { set end [expr $recsize * $totalnumkeys - $offset] } RetryTransaction { set programdata [mfs getpart $programindex $offset $end] } set init 0 } set data [string range $programdata $i [expr $i + $recsize - 1]] set fsiddata [string range $data 0 3] set compare [string compare $fsiddata $fsidbin] if {$compare == 0} { binary scan $data x4H8 showingdata if {$version3} { set channel [expr 0x$showingdata & 0x07FF] } else { set channel [expr 0x$showingdata & 0x03FF] } if {$watch == 0} { binary scan [string range $channeltabledata [expr $channel*8 + 4] [expr $channel*8 + 7]] I station } else { if {[catch {set station $channeltableindex($channel)}]} { continue } } if {$version3} { set time [expr 0x$showingdata >> 11] } else { set time [expr 0x$showingdata >> 10] } set seconds [expr $programindexstartday * 86400 + $time] if { $seconds < $nowsecs } { continue } if {$seconds == $prevsecs && $prevstation == $station} { continue } set prevstation $station set prevsecs $seconds if {$genres != ""} { set showingdata2 [string range $data 4 7] set startoffset 24 set maxoffset [expr $startoffset + $showingrecsize * $showingnumkeys] set first [get_recordindexsearch $showingkeyfsid $startoffset $maxoffset $showingrecsize $showingincrsize $showingdata2 0 3] if { $first == -1 } { error "Error couldn't find starting offset in showing key" } set startoffset [expr $first * $showingincrsize] set maxoffset [expr $startoffset + $showingincrsize] if { $maxoffset > $showingrecsize * $showingtotalnumkeys } { set maxoffset [expr $showingrecsize * $showingtotalnumkeys] } set sdata [get_recordindexsearch $showingindex $startoffset $maxoffset $showingrecsize $showingincrsize $showingdata2 2 3] binary scan $sdata H16 sdata if {$sdata != ""} { if {[genrematch $sdata $genres] == 0} { continue } } } lappend showings [list $seconds $station] # puts "$seconds $station" } elseif {$compare == 1} { break } else { error "Error: fsid is less that search param" } } if {$watch == 0} { unset channeltabledata } } return $showings } proc tms_to_fsid {tmsid} { global guideindexdir global db RetryTransaction { set tmskeyfsid [lindex [mfs find $guideindexdir/Tms.key] 0] set tmsindex [lindex [mfs find $guideindexdir/Tms.index] 0] set tmskeydata [mfs getpart $tmskeyfsid 0x0 0x18] } binary scan [string range $tmskeydata 0x00 0x03] I recsize binary scan [string range $tmskeydata 0x04 0x07] I totalnumkeys binary scan [string range $tmskeydata 0x08 0x0B] I incrsize binary scan [string range $tmskeydata 0x10 0x13] I numkeys set prefix [string range $tmsid 0 1] set number [string range $tmsid 2 end] if [expr [string length $number] == 10] { set mn 0 if {[string compare "4294967296" $number] <= 0} { set numbers [bignum_divide $number "4294967296"] set n1 [lindex $numbers 0] set n2 [lindex $numbers 1] } } else { set mn 256 set n1 0 set n2 $number } regsub ^0+(.+) $n1 \\1 n1 regsub ^0+(.+) $n2 \\1 n2 set search [binary format a2SII $prefix $mn $n1 $n2] # look through the key-file to get a starting point set startoffset 24 set maxoffset [expr $startoffset + $recsize * $numkeys] set first [get_recordindexsearch $tmskeyfsid $startoffset $maxoffset $recsize $incrsize $search 0 11] if { $first == -1 } { error "Error couldn't find starting offset in tms key" } # next, go throught index-file to get the exact match set startoffset [expr $first * $incrsize] set maxoffset [expr $startoffset + $incrsize] if { $maxoffset > $recsize * $totalnumkeys } { set maxoffset [expr $recsize * $totalnumkeys] } set fdata [get_recordindexsearch $tmsindex $startoffset $maxoffset $recsize $incrsize $search 2 11] if {[string length $fdata] == 0} { return "" } binary scan $fdata I fsid return $fsid } proc bignum_subtract {a b} { set la [string length $a] set lb [string length $b] if {$la < $lb} { set formatstring [format "%%0%s%s" $lb "s"] set a [format $formatstring $a] set la $lb } else { set formatstring [format "%%0%s%s" $la "s"] set b [format $formatstring $b] set lb $la } set result "" set carry 0 for {set index [expr $lb-1]} {$index >= 0} {incr index -1} { set current [expr [string index $a $index] - [string index $b $index]] if {$carry == 1} { incr current -1 } if {$current < 0} { set carry 1 incr current 10 } else { set carry 0 } set result [format "%s%s" $current $result] } if {$carry == 1} { set result [format "-%s" $result] } return $result } # calculate dividend / divisor proc bignum_divide {dividend divisor} { set result 0 set temp $dividend while {[string index $temp 0] != "-"} { incr result 1 set prevtemp $temp set temp [bignum_subtract $temp $divisor] } return "[expr $result - 1] $prevtemp" } proc genrematch {genrebytes genres} { global genretable set last "" set glist "" set glen [string length $genrebytes] for {set i 0} {$i < $glen} {incr i 2} { set gval [expr 0x[string range $genrebytes $i [expr $i+1]]] if {$last == $gval} { break } set last $gval set gval [lindex $genretable $gval] lappend glist $gval } foreach genre $genres { if {$genre != 0} { if { !$::dtivo || $genre > 14 || ($genre == 1 || $genre == 5 || $genre == 8) } { if {[lsearch $glist $genre] < 0} { return 0 } } } } return 1 } proc init_genreindex {} { global db global guideindexdir global genretable RetryTransaction { set genretablefsid [lindex [mfs find $guideindexdir/GenreTable] 0] set genretabledata [mfs get $genretablefsid] } set genretable "" binary scan [string range $genretabledata 0x4 0x7] I numkeys #set numkeys [expr ([string length $genretabledata] - 0x8) / 0x30] for {set i 0} {$i < $numkeys} {incr i} { binary scan [string range $genretabledata [expr $i*0x30 + 0x8] [expr $i*0x30 + 0xB]] I val lappend genretable $val } } proc init_logoindex {} { global db global logotableindex global logotablename foreach logotype {1 2} { set logotableindex($logotype) "" set logotablelogo($logotype) "" set logotablename($logotype) "" } set LogoGroups "" ForeachMfsFile fsid name type "/LogoGroup" "" { lappend LogoGroups $fsid } #fill logotablelogo and logotableindex foreach fsid $LogoGroups { RetryTransaction { set LogoGroupEntry [db $db openid $fsid] set LogoGroupSpace [dbobj $LogoGroupEntry get LogoSpace] set LogoGroupSize [dbobj $LogoGroupEntry get Size] set LogoGroupImages [dbobj $LogoGroupEntry gettarget Image] set LogoGroupIndexes [dbobj $LogoGroupEntry get Index] foreach targ $LogoGroupImages ndx $LogoGroupIndexes { set EncodedIndex [expr ($LogoGroupSpace << 16) | ($ndx & 0xffff)] lappend logotableindex($LogoGroupSize) $EncodedIndex lappend logotablelogo($LogoGroupSize) $targ } } } #fill the logotablename foreach logotype {1 2} imgsuffix {"-s1-p1" "-s2-p2"} { for {set x 0} {$x < [llength $logotablelogo($logotype)]} {incr x 50} { RetryTransaction { foreach fsid [lrange $logotablelogo($logotype) $x [expr $x+49]] { regexp {([0-9]*)/(.*)} $fsid junk id subid set logo [db $db openidconstruction $id $subid] set name [dbobj $logo get Name] regsub -- "$imgsuffix\$" $name {} name lappend logotablename($logotype) $name } } } } } proc init_channelindex {} { global db global guideindexdir global channeltablefsid global channeltablestation global channeltablenum global channeltableindex global logotableindex global logotablename if {[info exists logotableindex1] == 0} { init_logoindex } if {[info exists channeltablestation]} { unset channeltablestation unset channeltablenum } if {[info exists channeltableindex]} { unset channeltableindex } RetryTransaction { set setup [db $db open /Setup] set sources [dbobj $setup get Source] set channels "" foreach source $sources { append channels [dbobj $source gettarget Channel] " " } set channelcount [llength $channels] } set increment 30 #puts "channelcount = $channelcount" for {set j 0} {$j < $channelcount} {incr j $increment} { #puts "j = $j" set channels2 [lrange $channels $j [expr $j + $increment - 1]] RetryTransaction { foreach channel $channels2 { regexp {([0-9]*)/(.*)} $channel junk id subid set channelobj [db $db openidconstruction $id $subid] set record [defaultval 1 [dbobj $channelobj get Record]] set favorite [defaultval 0 [dbobj $channelobj get Favorite]] if { $record > 0 } { set num [dbobj $channelobj get Number] set num [expr $num & 0xFFFF] set station [dbobj $channelobj get Station] set stationfsid [dbobj $station fsid] set callsign [dbobj $station get CallSign] set stationname [dbobj $station get Name] set logoindex [dbobj $station get LogoIndex] set channeltablenum($num) $stationfsid set channeltablestation($stationfsid) [list $num $favorite $callsign $stationname $logoindex] } } } } RetryTransaction { set channeltablefsid [lindex [mfs find $guideindexdir/ChannelTable] 0] set channeltabledata [mfs get $channeltablefsid] } binary scan [string range $channeltabledata 0 3] I numkeys for {set i 0} {$i < $numkeys} {incr i} { binary scan [string range $channeltabledata [expr $i*8 + 4] [expr $i*8 + 11]] ISS stationfsid dummy chnum if { [catch {set test $channeltablenum($chnum)}] == 0 } { set channeltableindex($i) $stationfsid } } } proc init_ns_cache {} { global db global cache_ns_moddate global cache_ns_rec global cache_ns_series global nowshowingdir global version3 set cache_ns_rec "" set cache_ns_series "" set cache_ns_moddate "" if {$version3} { set nowshowingdir "/Recording/NowShowingByClassic" } else { set nowshowingdir "/Recording/NowShowing" } catch { RetryTransaction { set nsfsid [mfs find $nowshowingdir] set nsfsid [lindex $nsfsid 0] set cache_ns_moddate [mfs moddate $nsfsid] } } if {$cache_ns_moddate == ""} { return } ForeachMfsFileTrans fsid name type $nowshowingdir "" 20 { set rec [db $db openid $fsid] set showing [dbobj $rec get Showing] set program [dbobj $showing get Program] set seriesfsid [dbobj $program gettarget Series] regsub {/-1$} $seriesfsid {} seriesfsid #set series [dbobj $program get Series] if {$seriesfsid != ""} { # set seriesfsid [dbobj $series fsid] lappend cache_ns_rec $fsid lappend cache_ns_series $seriesfsid } } } proc init_sp_cache {} { global db global cache_sp_moddate global cache_sp_fsid global cache_sp_key global seasonpassdir set cache_sp_fsid "" set cache_sp_key "" set cache_sp_moddate "" catch { RetryTransaction { set spfsid [mfs find $seasonpassdir] set spfsid [lindex $spfsid 0] set cache_sp_moddate [mfs moddate $spfsid] } } if { $cache_sp_moddate == "" } { return } ForeachMfsFileTrans fsid name "tyDb" $seasonpassdir "" 20 { # puts "$fsid $name $type" set sp [db $db openid $fsid] set type [defaultval 1 [dbobj $sp get Type]] if { $type == 1 } { set series [dbobj $sp get Series] set seriesfsid [dbobj $series fsid] set station [dbobj $sp get Station] set stationfsid [dbobj $station fsid] lappend cache_sp_fsid $fsid lappend cache_sp_key "$seriesfsid|$stationfsid" } } } proc update_sp_cache {} { global db global cache_sp_moddate global cache_sp_fsid global cache_sp_key set spmoddate "" catch { RetryTransaction { set spfsid [mfs find $seasonpassdir] set spfsid [lindex $spfsid 0] set spmoddate [mfs moddate $spfsid] } } if {$spmoddate == "" || $spmoddate == $cache_sp_moddate} { return } set count 0 set newcache_sp_fsid $cache_sp_fsid set newcache_sp_key $cache_sp_key RetryTransaction { foreach fsid $cache_sp_fsid { if { [catch {db $db openid $fsid} sp] } { set newcache_sp_fsid [lreplace $newcache_sp_fsid $count $count] set newcache_sp_key [lreplace $newcache_sp_key $count $count] # puts "Removing $fsid from sp cache" } else { incr count } } } set cache_sp_fsid $newcache_sp_fsid set cache_sp_key $newcache_sp_key ForeachMfsFile fsid name type $seasonpassdir "" { if { [lsearch $cache_sp_fsid $fsid] == -1 } { RetryTransaction { set sp [db $db openid $fsid] set type [defaultval 1 [dbobj $sp get Type]] if { $type == 1 } { set series [dbobj $sp get Series] set seriesfsid [dbobj $series fsid] set station [dbobj $sp get Station] set stationfsid [dbobj $station fsid] lappend cache_sp_fsid $fsid lappend cache_sp_key "$seriesfsid|$stationfsid" # puts "Adding $fsid to sp cache" } } } } set cache_sp_moddate $spmoddate } if {$version3} { set guideindexdir "/GuideIndexV2" } else { set guideindexdir "/GuideIndex" } if {$version3} { set seasonpassdir "/SeasonPass/User" } else { set seasonpassdir "/SeasonPass" } if { $reload == 0 } { init_logoindex init_channelindex init_genreindex init_ns_cache init_sp_cache }