Radio programs, calendars, Date::Simple and avoiding the web

brian_d_foy on 2004-05-21T08:29:26

I like to listen to particular NPR programs while I work, but I do not like stopping whatever I am doing to get the next show going. NPR changed the way they structured the web, making it much more baroque and broken and stupid. They previously had a "current show" link, which always led to the audio of the last show (no matter the date it might be when I select it).

Now NPR has this really goofed, two-layer JavaScript thing going on. The previously non-stupid and convenient link is now a JavaScript action which has to look in a couple different places to figure out what to do.

It is apparent why they did this, although not why they should. They now offer audio in Windows Media Format, so they have extra options in the process. They also standardize the audio links among all of their programs. Behind the scenes, I think they also do some round-robin load balancing.

That does not help me much though. I want to click once to start listening to a show. I do not want to select a bookmark, find the link, then click on it. Since they went to this goofy JavaScript action link model, I have to do a lot of work.

I wrote a little CGI script to get around this. If I know the show's code, the date, and the media type (RealAudio), I can construct the right link. This script only create links valid on for that day. If I call the script at 1 am (not an unusual time for me to work), the script tries to redirect me to a URL that spits out null files (since those shows have not yet aired). In short, this script works within its very narrowly defined parameters, which you should read as "is stupid".

#!/usr/bin/perl

=head1 NAME

npr_today.cgi - redirect to current National Public Radio shows

=head1 SYNOPSIS

http://www.example.com/cgi-bin/npr-today.cgi?ATC http://www.example.com/cgi-bin/npr-today.cgi?ME =head1 DESCRIPTION

This script computes the current URL for a National Public Radio audio feed (which depends on the date), then redirects to that URL. This process skips a lot of javascript which www.npr.org uses to figure this out.

=head2 Show codes

=over 4

=item ATC

All Things Considered

=item ME

Morning Edition

=back

=head1 SOURCE AVAILABILITY

This source is part of a SourceForge project which always has the latest sources in CVS, as well as all of the previous releases.

http://sourceforge.net/projects/brian-d-foy/

If, for some reason, I disappear from the world, one of the other members of the project can shepherd this module appropriately.

=head1 AUTHOR

brian d foy, Ebdfoy@cpan.orgE

=head1 COPYRIGHT

Copyright 2004, brian d foy, All rights reserved.

You may use this program under the same terms as Perl itself.

=cut

my %show_codes = map { $_, 1 } qw( ATC ME FA );

my $show_code = $ENV{QUERY_STRING};

unless( exists $show_codes{ $show_code } ) { print <<"HTTP"; Status: 408 Bad Request Content-type: text/plain

I do not recognize the NPR show code [$Show_code]. HTTP exit; } my @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); my( $day, $month, $year ) = (localtime)[3,4,5];

my $date = sprintf "%02d-%s-%4d", $day, $months[$month], $year + 1900;

my $url = join '', "http://www.npr.org/dmg/dmg.php?prgCode=", $show_code, "&showDate=", $date, "&segNum=&mediaPref=RM"; print <<"HTTP"; Status: 303 See other Location: $url

Redirect to $url Redirect to $url HTTP


This script also ignores another problem: What if I missed yesterday's shows? I can only get the current ones. This script also does not handle the weekend shows.

I did not look forward to the idea of making this script understand yesterday, the week before, or anything like that. With a lot of extra programming I could do that, and it certainly is not hard: it is just boring programming.

Instead, I decided to create a calendar for all of the links for this month, and, while I am at it, all of the links for last month, in case I am in the first couple days of the month. I ended up using HTML::Calendar::Simple and Date::Simple. Why didn't I know about Date::Simple before? It rocks. And, check out that first map: I iterate through method names, not objects. :)

#!/usr/bin/perl
use strict;
use warnings;

use Date::Simple qw(:all); use HTML::Calendar::Simple;

my %shows = ( weekend => [ qw(WESAT WESUN) ], weekday => [ qw(ME ATC FA) ], );

my $this = [ map { today()->$_ } qw(year month) ]; my $last = $this->[1] == 1 ? [ $this->[0] - 1, 12 ] : [ $this->[0], $this->[1] - 1 ];

my @months = map { HTML::Calendar::Simple->new( { year => $_->[0], month => $_->[1] } ) } ( $this, $last );

foreach my $this_month ( @months ) { my( $year, $month ) = map { $this_month->$_ } qw(year month);

foreach my $this_day ( 1 .. days_in_month( $year, $month ) ) { my $date = ymd( $year, $month, $this_day ); my $npr_date = $date->format( "%d-%B-%Y" ); my $weekday = $date->day_of_week() % 6;

my $shows = $weekday ? $shows{weekday} : $shows{weekend};

foreach my $show ( @$shows ) { my $link = ram_href( $show, $npr_date ); my $href = qq|$show|; $this_month->daily_info( { day => $this_day, $show => $href, }); } } }

my $html = join '', map { qq|| . $_->calendar_month . "\n" } @months;

print <<"HERE"; brian's NPR Listening Calendar

brian's NPR Listening Calendar



$html
HERE

sub ram_href { "http://www.npr.org/dmg/dmg.php?prgCode=" . $_[0] . "&showDate=" . $_[1] . "&segNum=&mediaPref=RM"; }


I run the script through cron at the start of the month and save the output as a static file.

This is quite kludgey. The output is ugly, although I cleaned it up slightly with a style sheet. However, it solves my problem, and has a cool hidden feature: the shows I have already listened to show up as visited links (and if I really wanted to do work, I could make the visitied link color the same as the background). The browser knows what I have visited even if I got there through another path, such as the NPR web site or my earlier script.