Previous section   Next section

Hack 93 Turning Favorites Lists into JavaScript

figs/expert.giffigs/hack93.gif

With a little Tcl, you can query TiVo for your favorite actors, preferred creatives, Now Showing List, and so forth. Syndicate those lists to your web site or weblog with a little JavaScript and the magic of TiVoWeb.

The problem with pipe-delimited lists [Hack #91] is that you have to get them off your TiVo to another machine and run yet another script to either process the list for display or generate something that you can manipulate. Seems a little complicated to me.

What if what you want is really simple? You just want to have a live version of your To Do List on your web site or weblog. You want anybody who goes to your site to see what's of interest to you on the tube�or at least what TiVo will be recording for you�over the next couple of days. What if I told you it was dirt simple and required none of that pipe-delimited nonsense?

Remember TiVoWeb [Hack #67]. Why not just write a module [Hack #78] that generates some JavaScript to be included in the web page of your choosing? That's exactly what we are going to do.

In fact, writing a TivoWeb module is decidedly simple, as you can see in the following code. TiVoWeb already has a database handle available for use by a module, and all we have to do is write whatever we are planning to write with a call to puts. Whatever you write will get shoved out the socket, right to the browser visiting your site.

The Code

proc action_jtodo { chan path env } {
    global db
    global tzoffset
    eval $env
    
    # pull out the first 50 todo list shows from the database
    set tododir "/Recording/Active"
    set prefix "4"
    transaction {
        set files [mfs scan $tododir -start $prefix -count 50] 
    }
    
    while { [llength $files] > 0 } {
        # iterate through the shows we extracted
        foreach rec $files {
            # grab the FSID of the program from the list
            set fsid [lindex $rec 0]
            
            RetryTransaction {
                # get the object that represents this recording and 
                # the object that represents this episode.  wrap it 
                # in a catch just in case
                # it doesn't work
                set recordingobj [db $db openid $fsid]
                set showingobj [dbobj $recordingobj get Showing]
                set episodeobj [dbobj $showingobj get Program]
                set behaviorobj [dbobj $recordingobj get RecordingBehavior]

                # pull out the date the show aired -- also convert 
                # it to something a bit more human readable
                set showtime [expr ( [dbobj $showingobj get Date] * 86400 )[RETURN]
                + \ [dbobj $showingobj get Time] + $tzoffset ]
                set showtime [clock format $showtime -format "%m/%d"]

                # pull out the show's name and episode title
                regsub -all "\[\{\}\]" [dbobj $episodeobj get Title] ""[RETURN]
                programname
                regsub -all "\[\{\}\]" [dbobj $episodeobj get EpisodeTitle] 
"" \
              episodename

                # get the data to figure out whether this a
                # scheduled recording or a suggested recording
                set presbehavior [dbobj $behaviorobj get[RETURN]
                PresentationBehavior] 
            }

            # output some javascript -- if presbehavior is 6, that
            # means we are looking at a suggested recording
            if { $presbehavior != 6 } {
               puts $chan "document.write( \"<span class=\\\"episodedate\\\[RETURN]
               ">$showtime</span> - <span[RETURN]
               class=\\\"showtitle\\\">$programname</span> <span class=\\\[RETURN]
               "episodetitle\\\">$episodename</span><br/>
\" );" 
            }
            
        # and grab the next 50 television shows
        set lastName [lindex [lindex $files end] 1]
        transaction {
            set files [mfs scan $tododir -start $lastName -count 50]
        }
        if { $lastName == [lindex [lindex $files 0] 1] } {
            set files [lrange $files 1 end]
        }
    }
}

# register the module as JScript ToDo with a friendly 
# description for inclusion in TiVoWeb's main menu
register_module "jtodo" "JScript ToDo" "Generate Javascript with the # ToDo 
list"

Save this file as jtodo.itcl in the /var/hack/tivoweb-tcl/modules directory on your TiVo. Restart TiVoWeb by choosing Restart Full Reload from its menu bar. The module should be noticed and activated when TiVoWeb starts back up.

Running the Hack

Simply insert the following line into your HTML document where you'd like the To Do List to appear:

<script 
language="JavaScript" 
src="http://my_tivo/jtodo">
</script>

Replace my_tivo with the hostname or IP address of your TiVo.

Upon encountering this tag, JavaScript-enabled web browsers (most modern browsers) will grab a fresh copy of the To Do List from your TiVo, inserting it right into the page.

The JavaScript source version of my current To Do List looks like this:

document.write( "<span class=\"episodedate\">06/08</span> - <span class=\
"showtitle\">Lucky</span> <span class=\"episodetitle\">The Method</span><br/
>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">Advanced Paid Program</span> <span class=\"episodetitle\"></
span><br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">Teleworld Paid Program</span> <span class=\"episodetitle\"></
span><br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">Surf Girls</span> <span class=\"episodetitle\"></span><br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">Surf Girls</span> <span class=\"episodetitle\"></span><br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">ABC World News Tonight</span> <span class=\"episodetitle\"></
span><br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">For Love or Money</span> <span class=\"episodetitle\"></span>
<br/>" );
document.write( "<span class=\"episodedate\">06/09</span> - <span class=\
"showtitle\">Road Rules</span> <span class=\"episodetitle\">South Pacific</
span><br/>" );

The module even provides you with stylesheet elements�episodedate, showtitle, and episodetitle�that you can color, size, and style any which way using standard CSS.

Figure 7-3 shows the result, my TiVo's To Do List incorporated into a page on my web site.

Figure 7-3. TiVo's To Do List, JavaScript-included in a web page
figs/tivo_0703.gif

In actuality, you don't want to pull a fresh copy of your To Do List from your TiVo unit every time someone hits your web page. You'd be exposing your TiVo's hostname or address to the world�not a good thing to do, even if you're behind an Apache HTTP proxy (see [Hack #80]). You'll be placing undue strain on your TiVo and the TiVoWeb module as it serves up a response to all those visits to your ultrapopular home page. And then there's the fact that your To Do List doesn't change all that often, so brewing up a fresh copy each time is simply a waste of resources.

Instead, schedule the server on which your web site lives to fetch the JavaScript include once an hour or, better yet, once a day and serve up the local cached (read: saved) copy. You can do so using cron on Unix and Mac OS X servers, or Scheduled Events under Windows. In fact, if you go this direction, you might as well skip the JavaScript include altogether and alter the TiVoWeb module so that it produces plain old HTML:

puts $chan "<em>$programname</em>: $episodename ($showtime)<br />";

This line replaces the line beginning with puts $chan "document.write in the previous module code.

This HTML fragment can easily be incorporated into a web page using Server-Side Includes (http://hoohoo.ncsa.uiuc.edu/docs/tutorials/includes.html) or the like. Here, I include a copy cached as tivo_todo.html into my home page, index.shtml:

<!--#include virtual="./tivo_todo.html" -->

  Previous section   Next section
Top