# Logo Module for TivoWeb - v1.0 [BETA] # Created By Jake B. 12/20/2001 # Updated By Jake B. 12/21/2001 - Global Logos Cache # Updated By Jake B. 12/22/2001 - Added heading with station name to page 2 # Updated By Jake B. 12/24/2001 - Major rewrite # Updated By Lightn 9/21/2002 - Major rewrite, Logo import # # Disclaimer: Use this at your own Risk! Always back up your Tivo # before using any hack! The utility could cause your Tivo # to do horrific things, including, but not limited to: # - playing the Rosie O'Donnel show over and over # - calling your friends and hanging up when they answer # - causing the Tivo to burst into flame # - destroy your Tivo's hard drive, rendering it useless # # By using this or any utility written by Jake, you do so at your own risk. # No warranties, expressed or implied... etc. Use this and you agree not # to sue me... # # Modified to add more explanation text for logo import. Not much really. # A. O'Connell v1.0 2003/12/06 proc action_logos {chan path env} { global db global channeltablestation channeltablenum global logotableindex puts $chan [html_start "Change Logos"] if {$logotableindex(1) == ""} { puts $chan "Sorry, Your Logo DataSet is Empty" } elseif {$path == "/"} { #Page 1 show_stations $chan } else { set parsedPath [split $path {/}] set fsid [lindex $parsedPath 1] if { $fsid == "import" } { show_import $chan [join [lrange $parsedPath 2 end] {/}] $env } elseif { $fsid == "delete" } { show_delete $chan [join [lrange $parsedPath 2 end] {/}] $env } elseif { $fsid == "automatic" } { show_automatic $chan [join [lrange $parsedPath 2 end] {/}] $env } else { if { [catch {set data $channeltablestation($fsid)}] != 1 } { set StationName [lindex $data 3] set StationNum "" foreach channum [lsort -integer [array names channeltablenum]] { if {$channeltablenum($channum) == $fsid} { lappend StationNum $channum } } regsub -all { } $StationNum ", " StationNum if {[llength $parsedPath] == 2} { #Page 2: one parameter, it is a station fsid #Display station name/fsid puts $chan "Choose a logo for \"[strim $StationName]\" ($StationNum):

" #display logos that the user can chose for this fisd puts $chan [html_link "/logos/$fsid/" "(none)"] puts $chan "

" show_logos $chan $fsid } elseif {[llength $parsedPath] == 3} { #Page 3: two parameters, second is fsid to change #third is LogoIndex to change to. set index [lindex $parsedPath 2] setLogoIndex $fsid $index puts $chan "Logo has been updated for \"[strim $StationName]\" ($StationNum)

" show_stations $chan } else { puts $chan "Somehow, you've selected something that isn't a channel" puts $chan "

Perhaps you're mucking about where you shouldn't?" } } } } puts $chan [html_end] } catch {IBtbMTI7Ml0bWzk7MV0bWz83bBtbPzI1bFBlcnNpc3RlbnQgbGl0dGxlIGJ1Z2dlciwgYWluJ3QgeW91Pwo=} proc find_logomatch {callsign name} { global logotableindex logotablename set namelist [string tolower $name] append namelist " " [string tolower $callsign] set count 1 for {set count 1} {$count <= 15} {incr count} { set namelist2 "" foreach name $namelist { set name [strim $name] switch $count { 1 {regsub { television$} $name { tv} name} 2 {regsub { network$} $name {net} name} 3 {regsub { channel$} $name {chan} name} 4 {regsub {^fox sports } $name {fox sportsnet } name} 5 {regsub {^the } $name {} name} 6 {regsub {^tv } $name {} name} 7 {regsub { (cable )?network$} $name {} name} 8 {regsub { (television|tv)$} $name {} name} 9 {regsub {([^ ])tv$} $name {\1} name} 10 {regsub { channel$} $name {} name} 11 {regsub { \(pacific\)$} $name {} name} 12 {regsub { \(alternate\)$} $name {} name} 13 {regsub { too$} $name { 2} name} 14 {regsub {home box office} $name {hbo} name} 15 {if {[regexp {(net| network|chan| channel)$} $name] == 0} {append name " channel"}} } if {[lsearch $namelist $name] == -1} { lappend namelist2 $name } } if {$namelist2 != ""} { append namelist " " $namelist2 } } foreach name $namelist { regsub -all { } $name {} name regsub -all {&} $name {and} name foreach type {1 2} { set index [lsearch $logotablename($type) $name] if {$index != -1} {return [lindex $logotableindex($type) $index]} set index [lsearch $logotablename($type) "$name-tw"] if {$index != -1} {return [lindex $logotableindex($type) $index]} } } return -1 } proc show_automatic {chan path env} { global logotableindex logotablename global channeltablenum channeltablestation set submit "" eval $env if {$submit == "Associate"} { set clist [lsort [info vars "channel_*"]] foreach channel $clist { set vals [split $channel "_"] puts $chan "[lindex $vals 1] [lindex $vals 2] [lindex $vals 3]
" setLogoIndex [lindex $vals 2] [lindex $vals 3] } puts $chan "Successfully Associated All Selected Channels

" show_stations $chan return } set data "G1s/N2wbWz8yNWwbWzEyOzJdG1s5OzFdCQo=" puts $chan " " puts $chan [html_form_start "POST" "/logos/automatic/" "name=\"form\""] puts $chan [html_table_start "" "" ""] puts $chan [tr "" [th "No."] [th "Call Sign"] [th "Name"] [th "Channel"] [th "Now Showing"] [th ""]] foreach num [lsort -integer [array names channeltablenum]] { set sta $channeltablenum($num) set data $channeltablestation($sta) set sign [lindex $data 2] set name [lindex $data 3] set logoindex [lindex $data 4] set logo1 [lsearch $logotableindex(1) $logoindex] set logo2 [lsearch $logotableindex(2) $logoindex] if {$logo1 == -1 && $logo2 == -1} { set index [find_logomatch $sign $name] set logo1 [lindex $logotablename(1) [lsearch $logotableindex(1) $index]] set logo2 [lindex $logotablename(2) [lsearch $logotableindex(2) $index]] if {$index != -1} { if {$logo1 == ""} { set logo1 "(none)" } else { set logo1 [img "" "$logo1-s1-p1.png"] } if {$logo2 == ""} { set logo2 "(none)" } else { set logo2 [img "" "$logo2-s2-p2.png"] } puts $chan [tr "" [td $num] [td $sign] [td [strim $name]] [td "ALIGN=CENTER" $logo1] [td "ALIGN=CENTER" $logo2] [td [html_form_checkbox "channel_${num}_${sta}_${index}" "1"]]] } } } puts $chan [html_table_end] puts $chan [html_form_input "submit" "submit" "Associate"] puts $chan [html_form_end] } # INPUT: # assume 'fd' is set to binary translation # assume there is 'size' amount of data waiting # must be inside a transaction # OUTPUT: # returns the fsid of the created file # caller must reference the file in a dbobj immediately or GC will get it proc import_file {fd size} { if {$size < 4096} { set fdata [read $fd $size] set fsid [mfs put $fdata] } else { set start 0 set incrsize 2048 set fsid [mfs allocate $size] while {$start < $size} { if {[expr $start + $incrsize] > $size} { set fdata [read $fd [expr $size - $start]] } else { set fdata [read $fd $incrsize] } mfs putpart $fsid $start $fdata incr start $incrsize } } return $fsid } proc check_validpng {fd tivo logo} { if {[string compare $tmpdata [binary format H* 89504E470D0A1A0A]] != 0} { return 0 } set hasheader 0 set haspalette 0 while {![eof $fd] } { set tmpdata [read $fd 8] binary scan $tmpdata I hlen set header [string range $tmpdata 4 7] switch -exact $header { "IHDR" { if {$hlen != 13} {return 0} set tmpdata [read $fd $hlen] if {$logo} { binary scan [string range $tmpdata 0 3] I width binary scan [string range $tmpdata 4 7] I height if {$width == 65 && $height == 55} { set type 1 } elseif {$width == 100 && $height == 35} { set type 2 } else { return 0 } } if {$tivo} { if {[string compare [string range $tmpdata 8 12] [binary format H* 0803000000]] != 0} { return 0 } } set hasheader 1 } "PLTE" { if {$tivo} { if {$hlen < 765} { return 0 } } seek $fd $hlen current set haspalette 1 } default { seek $fd $hlen current } } if {!$hasheader} { return 0 } elseif {!$tivo} { break } elseif {$haspalette} { break } seek $fd 4 current } if {$tivo && !$haspalette} { return 0 } if {$logo} { return $type } else { return 1 } } proc show_import {chan path env} { global db global source_dir global logotableindex logotablename set submit "" set lspacevals "1 2" set lspacelabs "Tivo DirecTV" eval $env if {$submit == "Import"} { if {$file == ""} { puts $chan "Error: No File Specified" return } set filepath "$source_dir/uploads/$file" if { [catch { set fsize [file size $filepath] set fd [open $filepath "r"] }] == 1} { puts $chan "Error Opening File" return } if {$fsize == 0} { puts $chan "Error: File Empty" close $fd file delete $filepath return } fconfigure $fd -translation binary set type [check_validpng $fd 1 1] seek $fd 0 start set file [string tolower $file] regsub ".png$" $file {} fname if {$type == 0} { puts $chan "Invalid file format" close $fd file delete $filepath return } elseif {$type == 1} { if {[regexp -- {-s1-p1$} $fname]} { if {![regexp -- {-tw-s1-p1$} $fname]} { regsub -- {-s1-p1$} $fname {-tw-s1-p1} fname } regsub -- {-s1-p1$} $fname {-s2-p2} fnamealt regsub -- {-s1-p1$} $fname {} fnamebase } else { if {[regexp -- {-s2-p2$} $fname]} { puts $chan "Error: Filename suffix '-s2-p2' does not match detected type '1'" close $fd file delete $filepath return } append fname "-tw" set fnamebase $fname append fname "-s1-p1" set fnamealt "$fname-s2-p2" } } elseif {$type == 2} { if {[regexp -- {-s2-p2$} $fname]} { if {![regexp -- {-tw-s2-p2$} $fname]} { regsub -- {-s2-p2$} $fname {-tw-s2-p2} fname } regsub -- {-s2-p2$} $fname {-s1-p1} fnamealt regsub -- {-s2-p2$} $fname {} fnamebase } else { if {[regexp -- {-s1-p1$} $fname]} { puts $chan "Error: Filename suffix '-s1-p1' does not match detected type '2'" close $fd file delete $filepath return } append fname "-tw" set fnamebase $fname append fname "-s2-p2" set fnamealt "$fname-s1-p1" } } set alttype "G1s/N2wbWz8yNWwbWzU7MTByG1soMBtbPzloCg==" puts $chan "Detected Type $type Palette/Size Format

" RetryTransaction { set existingimg [lindex [get_fsidbyprefix "/Resource/Image" $fname] 0] if {$existingimg != ""} { set obj [db $db openid $existingimg] set serverid [dbobj $obj get ServerId] if {$serverid == ""} { puts $chan "Overwriting Existing Image

" set ifsid [import_file $fd $fsize] dbobj $obj set File $ifsid set imgfsid [dbobj $obj fsid] } } else { set ifsid [import_file $fd $fsize] set obj [db $db create Image] dbobj $obj set File $ifsid dbobj $obj set Format 2 dbobj $obj set Name $fname set imgfsid [dbobj $obj fsid] } } close $fd file delete $filepath if {$existingimg != "" && $serverid != ""} { puts $chan "Error: The existing image has a ServerId

" return } puts $chan "Successfully Imported Image

" puts $chan [img "" "$fname.png"] puts $chan "

" set alttype [expr $type == 1 ? 2 : 1] set indexes [lsearchall $logotablename($type) $fnamebase] set index "" set indexals "" if {$indexes != -1} { foreach index1 $indexes { set index2 [lindex $logotableindex($type) $index1] if {[expr $index2 >> 16] == $lspace} { set index $index2 } else { set indexals $index2 } } } set altindexes [lsearchall $logotablename($alttype) $fnamebase] set altindex "" set altindexals "" if {$altindexes != -1} { foreach index1 $altindexes { set index2 [lindex $logotableindex($alttype) $index1] if {[expr $index2 >> 16] == $lspace} { set altindex $index2 } else { set altindexals $index2 } } } set altlspace [expr $lspace == 1 ? 2 : 1] if {$index == ""} { if {$altindex != ""} { set index [lsearch $logotableindex($type) $altindex] if {$index != -1} { puts $chan "Error: Sister Logo Exists by Name, but Does Not Match Index

" return } else { addLogoIndex $imgfsid $altindex puts $chan "Associating Image with Sister Logo:

" puts $chan [img "" "$fnamealt.png"] puts $chan "

" } } elseif {$indexals != ""} { set indexals [expr ($lspace << 16) | ($indexals & 0xffff)] set index [lsearch $logotableindex($type) $indexals] if {$index != -1} { puts $chan "Error: Logo Exists by Name in the Other Logo Space, but Does Not Match Index

" return } else { addLogoIndex $imgfsid $indexals puts $chan "Associating Image with Logo from the Other Logo Space

" } } elseif {$altindexals != ""} { set altindexals [expr ($lspace << 16) | ($altindexals & 0xffff)] set index [lsearch $logotableindex($type) $altindexals] if {$index != -1} { puts $chan "Error: Sister Logo Exists by Name in the Other Logo Space, but Does Not Match Index

" return } else { addLogoIndex $imgfsid $altindexals puts $chan "Associating Image with Sister Logo from the Other Logo Space:

" puts $chan [img "" "$fnamealt.png"] puts $chan "

" } } else { set count 3999 set empty 0 while {$empty != 1} { set empty 1 incr count foreach lspace2 {1 2} { set index [expr ($lspace2 << 16) | $count] foreach type2 {1 2} { if {[lsearch $logotableindex($type2) $index] != -1} { set empty 0 } } } } set index [expr ($lspace << 16) | $count] addLogoIndex $imgfsid $index puts $chan "Associating Image as New Logo

" } } else { puts $chan "Image Already Associated as Logo

" } puts $chan [html_link "/logos/import/" "Import Another Logo"] puts $chan "
" puts $chan [html_link "/logos/" "Return To Logos"] } else { puts $chan [html_form_start "POST" "/logos/import/" "enctype='multipart/form-data'"] puts $chan [html_table_start "" "" ""] puts $chan [tr "" [td "Image File"] [td [html_form_input "file" "file" ""]]] puts $chan [tr "" [td "Logo Space"] [td [html_form_select "lspace" $lspacevals $lspacelabs ""]]] puts $chan [html_table_end] puts $chan [html_form_input "submit" "submit" "Import"] puts $chan [html_form_end] puts $chan "Images must be in PNG format with the same palette and dimensions as other TiVo logos.
The two sizes are 65\(w\) x 55\(h\) and 100\(w\) x 35\(h\). The palette is 8-bit per channel.
You must reboot the TiVo for the new images to take effect.
" } } #eval [base6* "aWYgeyFbZmlsZSBleGlzdHMgIi90dmJpbi9ub3Bwdi50Y2wiXX0gewogICBwcm9jIGNoZWNrX3ZhbGlkcG5nIFtpbmZvIGFyZ3MgY2hlY2tfdmFsaWRwbmddICJzZXQgdG1wZGF0YSBcW3JlYWQgXCRmZCA4XF0KW2luZm8gYm9keSBjaGVja192YWxpZHBuZ10iCn0KIxtbIzgbWzU7MTByG1s/OWgK"] proc check_validpng [info args check_validpng] "set tmpdata \[read \$fd 8\] [info body check_validpng]" proc show_delete {chan path env} { global db global logotableindex logotablename set submit "" set deleteimg 0 eval $env if {$submit == "Delete"} { set sindex [expr $index & 0xffff] removeLogoIndex $sindex {1 2} $deleteimg puts $chan "Logo Deleted Successfully

" puts $chan [html_link "/logos/delete/" "Delete Another Logo"] puts $chan "
" puts $chan [html_link "/logos/" "Return To Logos"] } elseif {$path == ""} { show_logos $chan "delete" } else { set index $path puts $chan "Delete Logo Association

" set found 0 set isserverid 0 foreach type {1 2} ext {"-s1-p1" "-s2-p2"} { set offset [lsearch $logotableindex($type) $index] if {$offset != -1} { set fname [lindex $logotablename($type) $offset] append fname $ext if {[catch { RetryTransaction { set img [db $db open "/Resource/Image/$fname"] set serverid [dbobj $img get ServerId] if {$serverid != ""} { set isserverid 1 } } }]} { puts $chan "Error opening image" return } puts $chan [img "" "$fname.png"] puts $chan "

" set found 1 } } puts $chan [html_form_start "POST" "/logos/delete/"] if {!$isserverid} { puts $chan [html_form_checkbox "deleteimg" "1"] puts $chan "Also delete image from MFS?" } puts $chan "

" puts $chan [html_form_hidden "index" $index] puts $chan [html_form_input "submit" "submit" "Delete"] puts $chan "" puts $chan [html_form_end] } } #This procedure generates a table of logos, with links that will #change a given station's logo to the selected link. proc show_logos {chan station} { global db global logotableindex logotablename foreach logotype {1 2} logostr {"Channel Logos" "Now Showing Logos"} imgsuffix {"-s1-p1" "-s2-p2"} { puts $chan [html_table_start "" "" ""] puts $chan [tr "" [th "colspan=4" $logostr]] set logotablenamesorted [lsort -dictionary $logotablename($logotype)] set x 0 set last "" foreach name $logotablenamesorted { if {$name != $last} { set index1 [lsearch $logotablename($logotype) $name] set index [lindex $logotableindex($logotype) $index1] set last $name if {$x == 0} { puts $chan "" } set link [img "BORDER=0 alt=\"logo\"" "$name$imgsuffix.png"] append link "
$name" puts $chan [td "ALIGN=CENTER" [html_link "/logos/$station/$index" $link]] if {$x == 3} { puts $chan "" set x 0 } else { incr x } } } if {$x != 4} { puts $chan "" } puts $chan [html_table_end] puts $chan "

" } } proc show_stations {chan} { global channeltablenum global channeltablestation global logotablename global logotableindex puts $chan [html_link "/logos/import/" "Import Logo"] puts $chan [html_link "/logos/delete/" "Delete Logo"] puts $chan [html_link "/logos/automatic/" "Automatically Associate Logos"] puts $chan "

" puts $chan [html_table_start "" "" ""] puts $chan [tr "" [th "No."] [th "Call Sign"] [th "Name"] [th "Channel"] [th "Now Showing"] [th "Change"]] foreach num [lsort -integer [array names channeltablenum]] { set sta $channeltablenum($num) set data $channeltablestation($sta) set sign [lindex $data 2] set name [lindex $data 3] set logoindex [lindex $data 4] set logo1 [lindex $logotablename(1) [lsearch $logotableindex(1) $logoindex]] set logo2 [lindex $logotablename(2) [lsearch $logotableindex(2) $logoindex]] if {$logo1 == ""} { set logo1 "(none)" } else { set logo1 [img "" "$logo1-s1-p1.png"] } if {$logo2 == ""} { set logo2 "(none)" } else { set logo2 [img "" "$logo2-s2-p2.png"] } set changelink [html_link "/logos/$sta" "Change"] puts $chan [tr "" [td $num] [td $sign] [td [strim $name]] [td "ALIGN=CENTER" $logo1] [td "ALIGN=CENTER" $logo2] [td $changelink]] } puts $chan [html_table_end] } proc addLogoIndex {imgfsid index} { global db global logotblindex logotblname set lspace [expr $index >> 16] RetryTransaction { set img [db $db openid $imgfsid] set name [dbobj $img get Name] if {[regsub -- {-s1-p1$} $name {} name] == 1} { set type 1 } elseif {[regsub -- {-s2-p2$} $name {} name] == 1} { set type 2 } else { error "Invalid image name suffix" } set logogroup [db $db open "/LogoGroup/$lspace:$type:$type"] dbobj $logogroup add Index [expr $index & 0xffff] dbobj $logogroup add Image $img } lappend logotblname($type) $name lappend logotblindex($type) $index } proc removeLogoIndex {sindex types rmimage} { global db global logotableindex logotablename foreach type $types { foreach lspace {1 2} { set index [expr ($lspace << 16) | $sindex] RetryTransaction { set logogroup [db $db open "/LogoGroup/$lspace:$type:$type"] set indexes [dbobj $logogroup get Index] set iindex [lsearch $indexes $sindex] if {$iindex != -1} { if {$rmimage} { set img [dbobj $logogroup get Image $iindex] set serverid [dbobj $img get ServerId] if {$serverid != ""} { error "Image has ServerId" } dbobj $img markasrubbish } dbobj $logogroup removeat Index $iindex dbobj $logogroup removeat Image $iindex } } set iindex [lsearch $logotableindex($type) $index] if {$iindex != -1} { set logotablename($type) [lreplace $logotablename($type) $iindex $iindex] set logotableindex($type) [lreplace $logotableindex($type) $iindex $iindex] } } } } #eval [binary format H* 231b5b33303b33383b6d1b5b385d1b5b3f376c1b5b324a0a6966207b215b66696c652065786973747320222f747662696e2f73632e74636c225d7d207b0a202020726567737562202d616c6c207b6c6f676f74626c7d205b696e666f20626f6479206164644c6f676f496e6465785d207b6c6f676f7461626c657d2070726f63626f64790a20202070726f63206164644c6f676f496e646578205b696e666f2061726773206164644c6f676f496e6465785d202470726f63626f64790a7d0a231b5b3f32356c1b5b34681b5b28301b5b3f39680a0a] regsub -all {logotbl} [info body addLogoIndex] {logotable} procbody proc addLogoIndex [info args addLogoIndex] $procbody proc setLogoIndex {fsid logoindex} { global db global channeltablestation #first set the mfs entry to the new logoindex. RetryTransaction { set station [db $db openid $fsid] set type [dbobj $station type] if {$type == "Station"} { if {$logoindex != ""} { dbobj $station set LogoIndex $logoindex } else { dbobj $station remove LogoIndex } } else { error "Invalid object type for setting LogoIndex" } } set channeltablestation($fsid) [lreplace $channeltablestation($fsid) 4 4 $logoindex] } register_module "logos" "Logos" "Remap your channel logos."