#!/usr/bin/perl # tv2html.pl - Converts sorted XMLTV files to HTML # Copyright (C) 2002-2003 Toby A Inkster # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # input must be a sorted XMLTV file. # output is an HTML TV guide. use XMLTV; $debuglevel = 0; &read_options; &read_goods; # Find input file name $filename = '-' if (@ARGV == 0); $filename = $ARGV[0] if (@ARGV == 1); usage() if (@ARGV > 1); # This bit is shamelessly stolen from tv_sort -- obtain list of programs ($encoding, $credits, $channels, $progs) = @{XMLTV::parsefile($filename)}; @progs = @$progs; %channelDetails = %$channels; # Put channels in correct order @channelOrder = split(/ /, $options{'ChannelOrder'}); foreach $c (keys %$channels) { $aC{$c} = 0; } $i = 1; foreach $c (@channelOrder) { $aC{$c} = $i; $i++; } foreach $c (keys %aC) { if ($aC{$c} > 0) { @allChannels[$aC{$c}] = $c; } else { @buttEnd = (@buttEnd, $c); } } if ( @buttEnd and ($options{ChannelHideUnordered} != 1) ) { @allChannels = (@allChannels, @buttEnd); } $firstElement = shift @allChannels; @allChannels = ($firstElement, @allChannels) unless ($firstElement eq ''); # Set date and time to some sort of pre-historic values: # 1 June 1980 was when I was born. Hint, hint... nudge, nudge... $myDate = '19800601'; $myHour = '25'; $myClass = 'listCell1'; # boolean (1 or 0) indicating whether the top of the table has been # printed. $myTop = 0; # loop through all programs foreach my $thisProg (@progs) { # just in case %pd = (); # gather program details $pd{time} = $thisProg->{start}; $pd{channel} = $thisProg->{channel}; $pd{title} = $thisProg->{title}->[0]->[0]; $pd{subtitle} = $thisProg->{'sub-title'}->[0]->[0]; $pd{description} = $thisProg->{desc}->[0]->[0]; $pd{category} = $thisProg->{category}->[0]->[0]; # I don't really care about things like # subtitles, stereo, star rating, ep number, # etc. If you do, feel free to add them. # prepare less immediate info $pd{date} = substr($pd{time}, 0, 8); $pd{hour} = substr($pd{time}, 8, 2); $pd{time} = substr($pd{time}, 8, 4); # for pretty # printing if($myTop == 0 && $myDate ne '19800601') { $myTop = 1; &dump_html_head(); } # if we're on to a new hour, then print out the TV guide for # the previous hour and then reset our accumulator. if ( $pd{hour} != $myHour) { &dump_out_html(); $myHour = $pd{hour}; $myDate = $pd{date}; %guideHash = (); } # NASTY DATA FORMAT!!! # Examples -- 8pm, Friday: # $guideHash{'bbc1.bbc.co.uk'}[0]{title} = 'EastEnders' # $guideHash{'bbc1.bbc.co.uk'}[0]{time} = '20:00' # $guideHash{'bbc1.bbc.co.uk'}[1]{title} = 'Alistair McGowan's Big Impression' # $guideHash{'bbc1.bbc.co.uk'}[1]{time} = '20:30' # This is a hash within an array within a hash push @{ $guideHash{$pd{channel}} }, { %pd }; } # Print out the last hour &dump_out_html(); &dump_html_foot(); ########################################################################### ########################################################################### ########################################################################### # Everything below here really needs a clean-up. Will do this after 0.2.0 # ########################################################################### ########################################################################### ########################################################################### # Function for debugging. Plain text is a little easier to read on the # console than HTML. sub dump_out_text() { print "------------------------------------\n"; print "Date: $myDate Hour: $myHour\n"; foreach $channel (@allChannels) { print " $channel:\n"; @progList = @{ $guideHash{$channel} }; foreach $prog (@progList) { print " $prog->{time} - $prog->{title} ($prog->{category})\n"; } } } # HTML Output sub dump_out_html() { if ($options{StyleByHTML} == 1) { $htmlBgPale = 'bgcolor="#c0c0ff"'; $htmlBgMedium = 'bgcolor="#0000ff"'; $htmlBgDark = 'bgcolor="#000080"'; $htmlFontWhite = ''; $htmlFontBlue = ''; $htmlFontEnd = ''; $htmlBold = ''; $htmlBoldEnd = ''; $htmlItalic = ''; $htmlItalicEnd = ''; } # dummy date if ($myDate ne '19800601') { # print out a banner if it's midnight. if ($myHour eq '00') { $d = substr($myDate, 6, 2) . "/" . substr($myDate, 4, 2) . "/" . substr($myDate, 0, 4); $c = $#allChannels + 2; print "$htmlFontWhite$d$htmlFontEnd\n"; print "\n"; print " $htmlFontWhite Time $htmlFontEnd\n"; foreach $channel (@allChannels) { my ($cName, $cLang) = @{XMLTV::best_name($langs, $channelDetails{$channel}->{'display-name'})}; my ($cIcon) = $channelDetails{$channel}->{'icon'}->[0]{src}; if ($options{'DisplayChannels2'} eq 'Name') { print " $htmlFontWhite$cName$htmlFontEnd\n"; } elsif ($options{'DisplayChannels2'} eq 'Caption') { print " $htmlFontWhite$cName$htmlFontEnd
\"$cName\"\n"; } elsif ($options{'DisplayChannels2'} eq 'Icon') { print " \"$cName\"\n"; } else { print " $htmlFontWhite$channel$htmlFontEnd\n"; } } print "\n"; } # print out this hour's TV! print "\n"; print " $htmlFontWhite $myHour:00 $htmlFontEnd\n"; foreach $channel (@allChannels) { print " \n"; @progList = @{ $guideHash{$channel} }; foreach $prog (@progList) { $good = ''; foreach $i (@goods) { if ($prog->{title} =~ /$i/i) { $good = ' class="good"'; #break; } } print " \n"; $formattedTime = substr($prog->{time},0,2) . ":" . substr($prog->{time},2,2); print " $htmlBold$htmlFontBlue " . $formattedTime . " $htmlFontEnd$htmlBoldEnd\n"; print " $htmlBold " . $prog->{title} . " $htmlBoldEnd
\n"; print " " . $prog->{subtitle} . "
\n" if (length($prog->{subtitle}) > 2); if ($options{'DisplayDescriptions'} == 1) { print " " . $prog->{category} . " "; print "$htmlItalic " . $prog->{description} . " $htmlItalicEnd\n"; } elsif ($options{'DisplayDescriptions'} == 2) { $prog->{description} =~ s/\"/"/g; print " {description} . "\">" . $prog->{category} . " "; } print "

\n"; } print " \n"; } print "\n"; } # alternate colours by row if ($myClass eq 'listCell1') { $myClass = 'listCell2'; $myHtml = $htmlBgPale; } else { $myClass = 'listCell1'; $myHtml = ''; } } sub dump_html_head() { $d = substr($myDate, 6, 2) . "/" . substr($myDate, 4, 2) . "/" . substr($myDate, 0, 4); $c = $#allChannels + 2; if ($options{StyleByHTML} == 1) { $htmlBgMedium = 'bgcolor="#0000ff"'; $htmlBgDark = 'bgcolor="#000080"'; $htmlFontWhite = ''; $htmlFontEnd = ''; $htmlBorder = 'border="1"'; } print < TV Guide EOF if ($options{StyleByCSS} == 1) { print < EOF } print <

TV Guide

EOF foreach $channel (@allChannels) { my ($cName, $cLang) = @{XMLTV::best_name($langs, $channelDetails{$channel}->{'display-name'})}; my ($cIcon) = $channelDetails{$channel}->{'icon'}->[0]{src}; if ($options{'DisplayChannels'} eq 'Name') { print " \n"; } elsif ($options{'DisplayChannels'} eq 'Caption') { print " \n"; } elsif ($options{'DisplayChannels'} eq 'Icon') { print " \n"; } else { print " \n"; } } print < EOF } sub dump_html_foot() { print <
$htmlFontWhite$d$htmlFontEnd
$htmlFontWhite Time $htmlFontEnd$htmlFontWhite$cName$htmlFontEnd$htmlFontWhite$cName$htmlFontEnd
\"$cName\"
\"$cName\"$htmlFontWhite$channel$htmlFontEnd

Data from Ananova. XMLTV framework by Ed Avis. HTML output by Toby A Inkster.

Valid HTML 4.01.

EOF } sub read_options() { debug('Beginning reading settings...'); debugUp(); $H = $ENV{'HOME'}; foreach $f ('/etc/tv2html.conf', "$H/.tv2html.conf", "$H/etc/tv2html.conf", '/etc/tv2html.important.conf') { debug("Tryng to open $f"); if (open(FH, $f) ) { debug("Reading settings from $f"); debugUp(); while() { chomp; if ($_ !~ m/^\s*\#/) { ($optionName, @args) = split(/ /, $_); $options{$optionName} = join(' ',@args); debug("Option $optionName read."); } } debugDown(); } else { debug('failed!'); } } debugDown(); debug('done!'); } sub read_goods() { debug('Beginning reading favourites...'); debugUp(); $H = $ENV{'HOME'}; foreach $f ('/etc/tv2html.good', "$H/.tv2html.good", "$H/etc/tv2html.good") { if (open(FH, $f) ) { debug("Reading favourites from $f"); debugUp(); while() { chomp; debug("$_ is good."); push @goods, $_; } debugDown(); close(FH); } } debugDown(); debug('done!'); } sub debug { $d = shift @_; for ($i = 0; $i<$debuglevel; $i++) { print STDERR "\t"; } print STDERR "$d\n"; } sub debugUp { $debuglevel++; } sub debugDown { $debuglevel--; }