TV Calendar Howto


The purpose of this document is to explain how to generate a calendar file in the iCal format containing television listings. The calendar will be constructed on Linux, and can be listed either by channel or by show. PLEASE NOTE: This was a fun weekend hacking project. It’s lashed together with various Linux program and a little perl and bash scripting. Don’t take it too seriously.

Programs and Files

You’ll need the programs and files in the following list.

Install zap2xml

Make sure you have perl installed. Zap2xml uses a number of perl modules from CPAN, notably Compress:Zlib and LWP:UserAgent from libwww. You can install these by running ‘perl -MCPAN -e shell’ then ‘install ‘. More information is on the zap2xml site.

In order to use zap2xml, you need to create an account with Zap2it and set it up as noted on the zap2xml site. That is, perform the steps under ‘Setup’. When you run

zap2xml -p -p yourpassword

you will download several files, then end up with an xmltv listing named xmltv.xml. I also placed my most used options, including the username, password, and number of days to get in the ~/.zap2xmlrc configuration file.

Making calendars

After a pretty extensive google search I found one person that had a method for changing xmltv files into iCal calendar files. Their website had, unfortunately, dissapeared into the digital ether so I used’s wayback machine to get the file they used to do it and I’ve mirrored it on my site.

The prog2ical.xsl file was originally intended to create complete channel listings. At first that was great, but it makes for really big calendars and I really don’t care that ‘Blind Date’ is on WCCB when all I watch on that channel is Football. So with absolutely no previous experience with xsltproc I set about tracking shows instead of channels. It could be better, but hey, it gets the job done. I would be interested in making a few other versions of prog2ical.xsl; for example, one that could track all movies (programme entries with episode-num beginning with MV).

Anyway, to create a calendar put xmltv.xml (downloaded using zap2xml), xmltv.dtd (from the xmltv checkout link above), and my modified prog2ical.xsl in a directory. Then run:

xsltproc --stringparam show YOURSHOW \
         --stringparam timezone YOUR_TZ \
         prog2ical.xsl xmltv.xml

where YOURSHOW is part of the show title you want to list,YOUR_TZ is your timezone (such as US-Eastern), and the result will be YOURSHOW.ics created in the current directory. You can, for example, get all of the Stargate listings in Stargate.ics with:

xsltproc --stringparam show Stargate \
         --stringparam timezone US-Eastern \
         prog2ical.xsl xmltv.xml

Note that this will get Stargate SG-1, Stargate Atlantis, and the Stargate movie if it should happen to be playing. Now the Stargate.ics file can be loaded up in the Mozilla calendar through ‘File->Open Calendar File...’

A little weirdness (spaces and unicode)

Spaces are special characters. To pass them into a program from the shell, they usually have to be escaped or quoted or otherwise handled. In the case of xsltproc, they must be Unicode spaces. Rather than deal with character encoding at the shell level, I’ve opted to do a little search and replace in the new prog2ical.xsl file, using the ‘+’ character to represent a space. As an example, I keep track of NBA Basketball games. In the listing, the title for these programmes is appropriately ‘NBA Basketball’. I get those listings with

xsltproc --stringparam show NBA+Basketball \
         --stringparam timezone US-Eastern \
         prog2ical.xsl xmltv.xml

The resulting output file will contain a unicode space and be named NBA%20Basketball, which is easy enough to rename, replacing the %20 with an underscore.

It’s nice to share (also nice to be lazy)

The Mozilla calendar applications, as well as iCal, have the ability to subscribe to remote calendars. So now that you’ve done all of this work throw it up on your website with a little automation using cron, bash, and some kind of file uploader like curl. Personally, I run this cron job on the server the ics files are hosted on, so I only need to move them to the right place.

I made a directory in my user’s home directory containing the prog2ical.xsl and xmltv.dtd files named tv. Also in that directory I have a bash script called containing the following:

# Shows I want to track
SHOWS=( UFC Stargate Family+Guy Two+and+a+Half+Men NFL+Football )

ICAL_TZ=US-Eastern # timezone
TV_BIN=$HOME/bin   # location containing zap2xml

# Local storage for the xmltv file, cache directory, and dtd

# Public html directory of the webserver

# clean up from last time
rm *.ics 2> /dev/null
rm $TV_PUBLIC/*.ics 2> /dev/null

# get the listing - uses settings in ~/.zap2xmlrc
$TV_BIN/ -q

# make a calendar for each show
for show in ${SHOWS[@]}
  xsltproc --stringparam show $show \
           --stringparam timezone $ICAL_TZ \
           prog2ical.xsl xmltv.xml


# clean up unicode spaces
for file in `ls *\%20*.ics 2> /dev/null`
  new_file=`echo $file | sed 's/%20/_/g' 2> /dev/null`
  mv $file $new_file 2> /dev/null

# move each file to subscription location
for cal_file in `ls *.ics 2> /dev/null`
  mv $cal_file $TV_PUBLIC 2> /dev/null

# or upload each file to a remote location (if you're using curl)
#for cal_file in `ls *.ics 2> /dev/null`
#  curl -T $cal_file

Make sure that’s executable and to wrap it all up, run the script every Sunday at 2am with cron: run ‘crontab -e’ and enter:

0 2 * * 0  /home/username/tv/

Now you can make links to your calendars on your website! Provided that the protocol is handled properly (like on Mac OS X), you can start them with webcal:// instead of http:// so that the calendar program is automatically opened. On Linux, you can go to ‘File->Subscribe to remote calendar...’ and paste the webcal (or http) address in to subscribe.