#!/usr/bin/perl -w # # TV listings toy # use lib qw( /Users/waider/src/perl ); use lib qw( /sw/lib/perl5 ); use DBI; use File::Path; use CGI; use CGI::Carp qw( fatalsToBrowser ); use Date::Parse; use POSIX; use Digest::MD5; use XMLTV; use Data::Dumper; use URI::Escape; use WaiderDotIe qw( getconfig do_cookie_dance get_user_data put_user_data ); use lib qw( /Users/waider/src/perl/Movies/lib ); use Hydra::Movie::CNDB; use strict; my $generator = "/usr/bin/tv_grab_ie.pl"; if ( ! -x $generator ) { $generator = "/sw/bin/tv_grab_ie.pl"; } my $conf = getconfig(); $conf->{cachedir} = "/var/cache/xmltv"; # hey, why not? my ( $host, $port, $database, $dbuser, $dbpass ) = ( $conf->{host}, $conf->{port}, $conf->{database}, $conf->{dbuser}, $conf->{dbpass} ); my $dbh = DBI->connect( "DBI:mysql:database=$database;host=$host;port=$port", $dbuser, $dbpass ) or die $DBI::errstr; my ( $content, $query ); my ( $cndb, $moviesonly, $nowonly, $progressive ) = ( 0, 1, 0, 0 ); my @movies; my ( $min, $hour, $mday, $month, $year ); my $id; my %chanlist; my @chanlist; my $changed = 0; my $debug = $ENV{'DEBUG'}; $| = 1; my $profile; # Get date info my $runtime = time; my $expires = 0; ( undef, $min, $hour, $mday, $month, $year, undef ) = localtime( $runtime ); $month++; $year = $year + 1900; # rollover is at 5am if ( $hour < 5 ) { my $date = $runtime; $date -= 60 * 60 * 24; ( undef, $min, $hour, $mday, $month, $year, undef ) = localtime( $date ); $month++; $year = $year + 1900; } if ( $ENV{'REMOTE_ADDR' }) { $query = new CGI; $id = do_cookie_dance( $query ); $profile = get_user_data( $dbh, $id ); $debug = $query->param( 'debug' ); eval { %chanlist = %{$profile->{'films.pl_chanlist'}}; map { push @chanlist, $_ if $chanlist{$_} eq "new" } keys %chanlist; }; if ( defined( $profile->{'films.pl_chanarray'})) { @chanlist = @{$profile->{'films.pl_chanarray'}}; } if ( defined( $query->param( 'date' ))) { my $date = $query->param( 'date' ); ( $year, $month, $mday ) = $date =~ /^(\d{4})(\d{2})(\d{2})$/; } $cndb = $query->param( 'cndb' ) || 0; $moviesonly = $query->param( 'moviesonly' ) || 1; $nowonly = $query->param( "nowonly" ) || 0; $progressive = $query->param( "progressive" ) || 0; } else { # pull ID from command line if possible $id = shift; $cndb = $ENV{CNDB}; $moviesonly = $ENV{MOVIESONLY}; } if ( !defined( $year ) or !defined( $mday ) or !defined( $month )) { die "can't make sense of the date"; } # Check for an XML file my $xmlfile = sprintf( "%s/%02d%02d%02d.xml", $conf->{cachedir}, $mday, $month, $year ); my $ref; if ( -s $xmlfile ) { eval { $ref = XMLTV::parsefile( $xmlfile ); $content = "Yay"; # keep later code happy }; } else { # We don't have a cache file that fits exactly. Let's get one. print STDERR "No $xmlfile found, fetching one\n" if $debug; # a bit clunky my $generate = `PERL5LIB=/sw/lib/perl5 $generator --date '$year/$month/$mday' 2>/var/tmp/tv_grab.log > $xmlfile`; print STDERR "generator said: $generate\n" if $debug and $generate; if ( ! -s $xmlfile ) { $generate ||= 'No XML produced'; my $error = ""; if ( open( my $ERR, " ); } my ( $exit, $signal, $core ) = ( $? >> 8, $? & 127, $? & 128 ); die "Failed to create $xmlfile\n" . "$generator returned $exit (sig $signal, core $core)\n\n" . "$generate\n\n$error"; } eval { $ref = XMLTV::parsefile( $xmlfile ); $content = "Yay"; # also }; # we'll assume success unlink( "/var/tmp/tv_grab.log" ); } # if we failed to parse the cache/generated file, trash it. It may be # corrupted. if ( !defined( $ref )) { unlink( $xmlfile ); } my ( $encoding, $credits, $ch, $progs ) = @{$ref}; my $langs = [ 'en' ]; # check for new channels for my $channel ( keys %{$ch} ) { my ( $logchannel, $lang ) = @{XMLTV::best_name( $langs, $ch->{$channel}->{'display-name'})}; if ( !defined( $logchannel )) { warn "no display-name for " . Dumper( $ch->{$channel} ); next; } if ( !defined( $chanlist{$logchannel})) { $chanlist{$logchannel} = "new"; push @chanlist, $logchannel; $changed = 1; } } # convert the programme data into something usable by the legacy code for my $programme ( @{$progs}) { my %movie; ( $movie{channel} ) = @{XMLTV::best_name( $langs, $ch->{$programme->{channel}}->{'display-name'} )}; if ( !defined( $movie{channel} )) { die "your code is fuxored...\n" . Dumper( $programme ); } if ( $chanlist{$movie{channel}} eq "hide" ) { next; } ( $movie{description} ) = @{XMLTV::best_name( $langs, $programme->{desc} )}; ( $movie{title} ) = @{XMLTV::best_name( $langs, $programme->{title} )}; $movie{start} = substr( $programme->{start}, 8, 2 ) . ":" . substr( $programme->{start}, 10, 2 ); my $unixtime = $programme->{start}; $unixtime =~ s@^(....)(..)(..)(..)(..)(..)@$1/$2/$3 $4:$5@; $unixtime = str2time( $unixtime ); $movie{unixtime} = $unixtime; $movie{stop} = $programme->{stop}; if ( defined( $movie{stop})) { my $unixtime = $movie{stop}; $unixtime =~ s@^(....)(..)(..)(..)(..)(..)@$1/$2/$3 $4:$5@; $movie{stop} = str2time( $unixtime ); } $movie{film} = 0; $movie{year} = 0; if ( $movie{description} =~ /^\((\d{4})(, (.+?))?\)\s*(.*)$/s ) { $movie{year} = $1; $movie{genre} = $3; $movie{film} = 1; $movie{description} = $4; } elsif ( $programme->{date} ) { # XXX $movie{year} = substr( $programme->{date}, 0, 4 ); $movie{film} = 1; } if ( !$expires and $unixtime > $runtime ) { $expires = $unixtime; } push @movies, \%movie; } print STDERR "Expires: " . scalar( localtime( $expires )) . "\n" if $debug; # Output Section if ( $ENV{'REMOTE_ADDR' }) { # back/forward one day my $today = str2time( sprintf( "%02d-%02d-%04d", $month, $mday, $year )); my $prev = $today - ( 60 * 60 * 24 ); my $next = $today + ( 60 * 60 * 24 ); my $url = "/cgi-bin/films.pl?"; $url .= "cndb=1&" if $cndb; $url .= "moviesonly=" . $moviesonly . "&"; $next = $url . "date=" . strftime( "%Y%m%d", localtime( $next )); $prev = $url . "date=" . strftime( "%Y%m%d", localtime( $prev )); $expires ||= $runtime; # wrong wrong wrong my $cookie = $query->cookie( -name => 'rssid', -value => $id, -path => '/', -expires => '+1y' ); print $query->header( -expires => "+" . ( $expires - $runtime ) . "s", -cookie => $cookie, -Cache_Control => "max-age=" . ( $expires - $runtime )); # the doctype probably isn't strictly correct, but it's a nice idea print <<"EOH"; Movies for $mday/$month/$year EOH if ( !defined( $content )) { print <<"EOT";

Looks like we drew a blank on $mday/$month/$year\n

Proxy Settings:
http_proxy=$ENV{http_proxy}
\nno_proxy=$ENV{no_proxy}

EOT exit; } my $prog = $url . "progressive=1"; my $profile = ""; print <<"EOH";

Previous | Next | Now | Next | Full | Change User

$profile EOH } my $next = ""; my $now = ""; if ( defined( $query) and $progressive ) { if ( $progressive == 2 ) { my %channels; my %times; # date-sort the movies @movies = sort { $a->{unixtime} <=> $b->{unixtime}} @movies; map { my @s; if ( defined( $channels{$_->{channel}} )) { @s = @{$channels{$_->{channel}}}; } if (( $_->{stop}||$_->{unixtime} ) >= $runtime ) { if ( $_->{unixtime} < $runtime ) { $_->{unixtime} = $runtime; } push @s, $_; $channels{$_->{channel}} = \@s; $times{$_->{unixtime}} = 1; } } @movies; print "\n"; print ""; for my $time ( sort keys %times ) { print ""; } print "\n"; my $idx = 0; for my $channel ( @chanlist ) { print ""; my @times = sort keys %times; for my $time ( @times ) { next if !defined( $channels{$channel}); my @shows = @{$channels{$channel}}; my $filler = ""; my $cols = 1; my $style = ""; while ( !defined( $shows[0])) { shift @shows; } if ( $time eq $times[0] and $shows[0]->{unixtime} != $time ) { $filler = "" . strftime( "%H:%M: ", localtime( $time )); $filler .= "no show until "; $filler .= strftime( "%H:%M", localtime( $shows[0]->{unixtime} )); $filler .= ""; for my $t ( @times ) { last if $shows[0]->{unixtime} == $t; $cols++; } $cols--; } else { for my $s ( @shows ) { $s->{stop} = $times[-1] unless $s->{stop}; next if $s->{stop} < $time; next if $s->{unixtime} > $time; if ( $s->{unixtime} == $time ) { $filler = "
"; $filler .= ""; $filler .= $s->{title}; if ( $s->{film}) { $style = " style=\"background-color: blue\""; } $filler .= "
"; # $filler .=<<"EOF"; # #EOF $filler .= "
"; $filler .= $s->{channel} . "
\n"; $filler .= $s->{start}; $filler .= " - " . strftime( "%H:%M", localtime( $s->{stop})) if defined( $s->{stop}); $filler .= "
\n"; $filler .= $s->{title} . "
\n"; $filler .= ( $s->{description} || "no info"); $filler .= "
"; # how many cols does it span? if (defined( $s->{stop})) { for my $t ( sort keys %times ) { if ( $t >= $s->{stop} ) { last; } if ( $t > $s->{unixtime }) { $cols++; } } } } } } if ( $filler ) { print ""; } $idx++; } print "\n"; } print "
"; print "Showtime"; print ""; if ( $time == $runtime ) { print "NOW"; } else { print strftime( "%H:%M", localtime( $time )); } print "
"; print $channel; print ""; print "$filler"; print "
\n"; } else { my @starts; my $oldchannel = ""; # date-sort the movies @movies = sort { $a->{unixtime} <=> $b->{unixtime}} @movies; my $basetime = $movies[0]->{unixtime}; if ( $nowonly ) { $basetime = $runtime; } push @starts, [ $runtime, "now", $runtime ]; my $x = 20; my $y = 0; my $idx = 0; for my $channel ( @chanlist ) { next if $channel eq $oldchannel; # dedupe $oldchannel = $channel; $x += 20; print "
"; print "$channel"; MOVIE: for my $midx ( 0..$#movies ) { my $m = $movies[$midx]; next MOVIE unless $m->{channel} eq $channel; $y = $m->{unixtime} - $basetime; if ( $y < 0 ) { if ( defined( $m->{stop})) { $y = $m->{stop} - $basetime; if ( $y > 0 ) { $y = 0; } else { next MOVIE; } } } $y /= 5; $y += 150; # not working yet - width my $w = ""; if ( defined( $m->{stop})) { $w = $m->{stop} - $m->{unixtime}; $w /= 5; $w = " width: $ {w}px"; } print "
"; print $m->{title}; print "
"; print "
"; print $m->{channel} . "
\n"; print $m->{start}; print " - " . strftime( "%H:%M", localtime( $m->{stop})) if defined( $m->{stop}); print "
\n"; print $m->{title} . "
\n"; print ( $m->{description} || "no info"); print "
"; $idx++; push @starts, [ $m->{unixtime}, $m->{start}, $m->{stop}||$m->{unixtime} ]; } print "
\n"; } # Print time markers for my $t ( @starts ) { $y = $t->[0] - $basetime; next if $y < 0; $y /= 5; $y += 150; print "
"; print $t->[1]; print "
"; } } } else { print "
\n" if defined( $query ); for my $movie ( sort { $a->{unixtime} <=> $b->{unixtime}} @movies ) { next if ( !$movie->{film} and $moviesonly ); my $searchurl = uri_escape( $movie->{title} . ( $movie->{year}? " (" . $movie->{year} . ")" : "")) . '"'; my $bgcolor = ""; if ( $runtime >= $movie->{unixtime} and $runtime <= ( $movie->{stop}||$movie->{unixtime})) { $bgcolor = "class=\"tvnow\"" unless $nowonly; $searchurl .= "\" name=\"now\"" unless $now; $now = $movie->{title} unless $now; } else { next if $nowonly; } if ( defined( $query )) { print "
"; } # Mark what's up next. if ( !$next && $movie->{unixtime} >= $runtime ) { if ( defined( $query )) { $searchurl .= "\" name=\"next\""; } else { print "NEXT >>>"; } $next = $movie; } if ( defined( $query ) && $movie->{film} ) { print ""; } else { if ( defined( $query ) && $searchurl =~ /name="(now|next)"/) { print ""; } } print $movie->{title}; if ( $movie->{film}) { print " (" . ($movie->{year}||"????") . "):" } else { print ":"; } print "" if $query && $movie->{film}; print " " . $movie->{channel} . ", " . $movie->{start}; print strftime( " - %H:%M", localtime( $movie->{stop} )) if $movie->{stop}; if ( $query ) { my $beg = $movie->{unixtime}; my $stop = $movie->{stop}; my $desc = uri_escape( $movie->{title} . " @ " . $movie->{channel} ); my $detail = uri_escape( $movie->{description}||"" ); if ( defined( $beg ) && defined( $stop ) && defined( $desc ) && defined ( $detail )) { print <<"CAL"; [reminder] CAL } } print "
" if $query; print "\n"; if ( defined( $query )) { print "
" . $movie->{'description'}; } # The "too much free time on my hands" section if (( $cndb||0 ) && $movie->{film}) { my @urls; my $urls = Hydra::Movie::CNDB::search( $movie->{title} ); for my $m ( @{$urls->{exact}} ) { if ( defined( $m->{year} ) and abs( $m->{year} - $movie->{year} ) <=1 ) { push @urls, $m; } else { # hmm. push @urls, $m if !defined( $m->{year} ); } } for my $url ( @urls ) { $url->detail(); # don't bother with no-skin movies that are in CNDB next unless $url->{skin}; my $title = $url->{title}; print "

Skin in {cndb} . "\">$title:\n

\n"; print "

\n"; } } print "
\n" if $query; } print "
\n" if $query; } # trailer if ( defined( $query )) { print "\n"; print "\n"; if ( $changed ) { #$profile->{'films.pl_chanlist'} = \%chanlist; $profile->{'films.pl_chanarray'} = \@chanlist; put_user_data( $dbh, $id, $profile ); } }