PDA

View Full Version : Reworking PublicRadioFanBrowser Plugin to Utilize AlienBBCport



Thomas B. Malsbury
2004-12-21, 07:41
I was just wondering how much work it would be to rework the current
PublicRadioFanBrowser plugin to handle RealAudio streams through AlienBBC.

Currently the plugin only requests MP3 streams from PublicRadioFan.com.
It is simple to request addition formats (real audio in this case) by
adding the following to the request url, &sty=rm (real audio). I was
thinking that it could parse the page retrieved using &sty=rm&sty=mp3 in
the request url. Then the the streams that come up as mp3 can be
handled as in the past and passed directly to slimserver. Streams that
come up as real audio could be reformatted to include the AlienBBC proxy
as used in the creation of the This American Life playlists.

This would greatly expand the available Public Radio streams to
Slimserver ( on linux ;) )

Just a thought,

Tom

ps: I have attached the PublicRadioFanBrowser.pm in its current state if
anyone would like to have a look at it.

# PublicRadioFanComBrowser.pm Copyright (C) 2003 Ted Rathkopf
# version 0.1, 21 September 2003
#
# A Slimp3 plugin for browsing the PublicRadioFan.com web directory of
# mp3 streams. Inspired by ShoutcastBrowser, which was in turn
# inspired by streamtuner.
#
# This code is derived from code with the following copyright message:
#
# ShoutcastBrowser.pm Copyright (C) 2003 Peter Heslin
#
# SliMP3 Server Copyright (C) 2001 Sean Adams, Slim Devices Inc.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License,
# version 2.
#
# Also contains code derived from from Kevin Walsh's Weather.pm

#
# This plugin wouldn't be possible without the Kevin A. Kelly's
# wonderful website publicradiofan.com. If you find this plugin
# useful, please donate to publicradiofan.com.
# http://www.publicradiofan.com/donate.html

# The PublicRadioFan.com website is owned by Kevin A. Kelly. The
# site and its database (c) 2001-2003, Kevin A. Kelly.
#

package Plugins::PublicRadioFanBrowser;
use strict;

################### Configuration Section ########################
#
my $base_url = "http://www.publicradiofan.com";
my $when = "nowsoon"; # "now" or "nowsoon"

my $timezone="-6,CST,-5,CDT,Central"; #default ('cause that's where I live)

# The timezone should be set for the timezone in which the slimp3 is running.
# uncomment one of the following:

# $timezone="-10,HST,-10,HST,Hawaii";
# $timezone="-9,AST,-8,ADT,Alaska";
$timezone="-8,PST,-7,PDT,Pacific";
# $timezone="-7,MST,-7,MST,Arizona";
# $timezone="-7,MST,-6,MDT,Mountain";
# $timezone="-6,CST,-6,CST,Saskatchewan";
# $timezone="-6,CST,-5,CDT,Central";
# $timezone="-5,EST,-5,EST,Indiana";
# $timezone="-5,EST,-4,EDT,Eastern";
# $timezone="-4,AST,-3,ADT,Atlantic";
# $timezone="0,GMT,1,BST,Britain";
# $timezone="1,CET,2,CEST,Central Europe";
# $timezone="-12,(UTC-12),-12,(UTC-12),(UTC-12)";
# $timezone="-11,(UTC-11),-11,(UTC-11),(UTC-11)";
# $timezone="-10,(UTC-10),-10,(UTC-10),(UTC-10)";
# $timezone="-9,(UTC-9),-9,(UTC-9),(UTC-9)";
# $timezone="-8,(UTC-8),-8,(UTC-8),(UTC-8)";
# $timezone="-7,(UTC-7),-7,(UTC-7),(UTC-7)";
# $timezone="-6,(UTC-6),-6,(UTC-6),(UTC-6)";
# $timezone="-5,(UTC-5),-5,(UTC-5),(UTC-5)";
# $timezone="-4,(UTC-4),-4,(UTC-4),(UTC-4)";
# $timezone="-3,(UTC-3),-3,(UTC-3),(UTC-3)";
# $timezone="-2,(UTC-2),-2,(UTC-2),(UTC-2)";
# $timezone="-1,(UTC-1),-1,(UTC-1),(UTC-1)";
# $timezone="0,UTC,0,UTC,UTC";
# $timezone="1,(UTC+1),1,(UTC+1),(UTC+1)";
# $timezone="2,(UTC+2),2,(UTC+2),(UTC+2)";
# $timezone="3,(UTC+3),3,(UTC+3),(UTC+3)";
# $timezone="4,(UTC+4),4,(UTC+4),(UTC+4)";
# $timezone="5,(UTC+5),5,(UTC+5),(UTC+5)";
# $timezone="6,(UTC+6),6,(UTC+6),(UTC+6)";
# $timezone="7,(UTC+7),7,(UTC+7),(UTC+7)";
# $timezone="8,(UTC+8),8,(UTC+8),(UTC+8)";
# $timezone="9,(UTC+9),9,(UTC+9),(UTC+9)";
# $timezone="10,(UTC+10),10,(UTC+10),(UTC+10)";
# $timezone="11,(UTC+11),11,(UTC+11),(UTC+11)";
# $timezone="12,(UTC+12),12,(UTC+12),(UTC+12)";
# $timezone="13,(UTC+13),13,(UTC+13),(UTC+13)";


#
################### End Configuration Section ####################
my $directory_url = "$base_url/cgi-bin/whatson.pl";
my $startat = 0;

my (%current_genre, %current_program, %old_program,
%current_stream, %old_stream, %status);

my @genres = ('Music','Non-Music');
my @programs;

my $musicurl = "$directory_url?when=$when\&type=music\&sty=mp3";
my $nonmusicurl = "$directory_url?when=$when\&type=non-music\&sty=mp3";

my $file_timeout = 600; #in seconds
my $force_reload = 1;

use Slim::Control::Command;
use Slim::Utils::Strings qw (string);
use LWP::Simple;
use LWP::UserAgent;
use HTTP::Cookies;
use HTML::TreeBuilder;
use File::Temp qw/ tempfile tempdir /;

my $tempdir = tempdir("prfXXXXX", TMPDIR => 1 );
my $musicfn = $tempdir . "/music.html";
my $nonmusicfn = $tempdir . "/non-music.html";

my (%streams, %programs, %programids);

my $cookie_jar = HTTP::Cookies->new;


my $ua = LWP::UserAgent->new;
my $musicrequest = HTTP::Request->new('GET', $musicurl);
my $nonmusicrequest = HTTP::Request->new('GET', $nonmusicurl);
my $musicresponse;
my $nonmusicresponse;

$cookie_jar->set_cookie(0, 'Time Zone', $timezone, '/', 'publicradiofan.com', 80, 0, 0, 31536000);
$cookie_jar->add_cookie_header($musicrequest);
$cookie_jar->add_cookie_header($nonmusicrequest);

sub getDisplayName() {return string('PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME') }

sub strings()
{
local $/ = undef;
<DATA>;
}


sub reload_htmlfiles() {
$force_reload = 0;
%streams = ();
%programs = ();
# print "reloading...\n";
$musicresponse = $ua->request($musicrequest, $musicfn);
$nonmusicresponse = $ua->request($nonmusicrequest, $nonmusicfn);

# if (getstore($musicurl, $musicfn) != 200 ||
# getstore($nonmusicurl, $nonmusicfn) != 200) {
# my $client = shift;
# $status{$client} = -1;
# $client->update();
# }

}

sub check_and_reload_htmlfiles() {
# print "checking....force=$force_reload\n";
my @fileattribs = stat $musicfn;
reload_htmlfiles if ($force_reload ||
time - $fileattribs[9] > $file_timeout);
}

sub addMenu {
my $menu = "RADIO";
return $menu;
}

##### Main mode for genres #####

sub setMode() {

my $client = shift;
$client->lines(\&lines);
$status{$client} = 0;
$client->update();

# Get genres

check_and_reload_htmlfiles();

$status{$client} = 1;

$client->update();
}

my %functions = (
'up' => sub {
my $client = shift;
$current_genre{$client} = Slim::Buttons::Common::scroll(
$client,
-1,
$#genres + 1,
$current_genre{$client} || 0,
);
$client->update();
},
'down' => sub {
my $client = shift;
$current_genre{$client} = Slim::Buttons::Common::scroll(
$client,
1,
$#genres + 1,
$current_genre{$client} || 0,
);
$client->update();
},
'left' => sub {
my $client = shift;
Slim::Buttons::Common::popModeRight($client);
},
'right' => sub {
my $client = shift;
Slim::Buttons::Common::pushModeLeft($client, 'PublicRadioPrograms');
},
'jump_rew' => sub {
my $client = shift;
$status{$client} = 0;
$force_reload = 1;
&setMode($client);
},
);



sub lines {
my $client = shift;
my (@lines);
$current_genre{$client} ||= 0;

if ($status{$client} == 0) {

$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_BEG');
$lines[1] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
} elsif ($status{$client} == -1) {
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
$lines[1] = '';
} elsif ($status{$client} == 1) {
my $current_name = $genres[$current_genre{$client}];
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_GENRES').
' (' .
($current_genre{$client} + 1) . ' ' .
Slim::Utils::Strings::string('OF') . ' ' .
($#genres + 1) . ') ' ;
$lines[1] = $current_name;
$lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
}

return @lines;
}


sub getFunctions() {
return \%functions;
}

##### Sub-mode for programs #####

my $programs_mode_sub = sub {
my $client = shift;
$client->lines(\&ProgramsLines);
$status{$client} = 0;
$current_program{$client} = $old_program{$current_genre{$client}}{$client} || 0;
$client->update();

# print "\n" . exists($programs{$current_genre{$client}}) . "\n";


unless (exists $programs{$current_genre{$client}} && $force_reload == 0) {
@programs = ();
my $order_by = '';

my $genre_name = $genres[$current_genre{$client}];
$genre_name =~ s/M/m/;
$genre_name =~ s/N/n/;

my $genre_file = $tempdir . "/" . $genre_name . ".html";

# my $url = "$directory_url?when=$when\&type=$genre_name\&sty=mp3";

# my $content = get($url);
# unless ($content)
# {
# $status{$client} = -1;
# $client->update();
# return;
# }

check_and_reload_htmlfiles();
my $tree = HTML::TreeBuilder->new();


$tree->parse_file($genre_file);
# $tree->parse($content);
$tree->eof();


my @tds = $tree->look_down('_tag', 'td',
'class', 'bct'
);

foreach my $td (@tds) {
my $text = $td->as_text;
my @links = $td->extract_links('a');
my $prfprogram_id = $links[0][1][0];

if ($prfprogram_id) {
push @programs, [$prfprogram_id, $text];
}
}

$programs{$current_genre{$client}} = [@programs];
%streams = ();

#print "\n\nPrograms: ".scalar @programs."\n";
#print $_->[1]."\n" for @programs;

$tree->delete;
}
$status{$client} = 1;
$client->update();

};

sub ProgramsLines() {

my $client = shift;
my (@lines);
$current_program{$client} ||= 0;
$current_genre{$client} ||= 0;

if ($status{$client} == 0) {
$lines[0] = '';
if ($force_reload) {
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
}
$lines[1] = '';
} elsif ($status{$client} == -1) {
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
$lines[1] = '';
} elsif ($status{$client} == 1) {
# print STDERR join ', ', %programs;
my @xprograms = @{ $programs{$current_genre{$client}} };

my $current_array = $xprograms[$current_program{$client}];
my $current_name = $current_array->[1];

$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_PROGRAMS'). ' '.
Slim::Utils::Strings::string('FOR') . ' ' .
$genres[$current_genre{$client}] .
' (' .
($current_program{$client} + 1) . ' ' .
Slim::Utils::Strings::string('OF') . ' ' .
($#xprograms + 1) . ') ' ;
$lines[1] = $current_name;
$lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
}

return @lines;
}

my %ProgramsFunctions = (
'up' => sub {
my $client = shift;
my @programs = @{ $programs{$current_genre{$client}} };
$current_program{$client} = Slim::Buttons::Common::scroll(
$client,
-1,
$#programs + 1,
$current_program{$client} || 0,
);
$client->update();
},
'down' => sub {
my $client = shift;
my @programs = @{ $programs{$current_genre{$client}} };
$current_program{$client} = Slim::Buttons::Common::scroll(
$client,
1,
$#programs + 1,
$current_program{$client} || 0,
);
$client->update();
},
'left' => sub {
my $client = shift;
$old_program{$current_genre{$client}}{$client} = $current_program{$client};
Slim::Buttons::Common::popModeRight($client);
},
'right' => sub {
my $client = shift;
$old_program{$current_genre{$client}}{$client} = $current_program{$client};
Slim::Buttons::Common::pushModeLeft($client, 'PublicRadioStreams');
},
'jump_rew' => sub {
my $client = shift;
$status{$client} = 0;
$force_reload = 1;
delete $programs{$current_genre{$client}};
$programs_mode_sub->($client);
},
);

#
# sub mode for streams
#

my $streams_mode_sub = sub {
my $client = shift;
$client->lines(\&StreamsLines);
$status{$client} = 0;
$current_stream{$client} = $old_stream{$current_program{$client}}{$client} || 0;
$client->update();

unless (exists $streams{$current_program{$client}}) {

my @pn = $programs[$current_program{$client}];
my $prfprogram_id = $pn[0][0];
my $program_name = $pn[0][1];
my $short_pn;
($short_pn) = ($program_name =~ /^(.*) \(.*\)/);
my $genre_name = $genres[$current_genre{$client}];
$genre_name =~ s/M/m/;
$genre_name =~ s/N/n/;

my $genre_file = $tempdir . "/" . $genre_name . ".html";

# my $url = "$directory_url?when=$when\&type=$genre_name\&sty=mp3";

# my $content = get($url);

# unless ($content)
# {
# $status{$client} = -1;
# $client->update();
# return;
# }

check_and_reload_htmlfiles();
my $tree = HTML::TreeBuilder->new();

# print "$genre_file\n";
# $tree->parse($content);
$tree->parse_file($genre_file);
$tree->eof();

my $prog = $tree->look_down('_tag', 'a',
'href', $prfprogram_id
);

if (!defined($prog)) {
$force_reload = 1;
Slim::Buttons::Common::popModeRight($client);
}

$prog = $prog->parent->parent;
my $thisprog = 1;
my $progtime;
my @tds = ();
my @streams;

my $ptr=$prog->right;
while ($thisprog && $ptr) {
if ($ptr->look_down('class','bct')) {
$thisprog = 0;
} else {
my $timeptr = $ptr->look_down('class','bcta',
sub {
not $_[0]->look_down('_tag', 'a')
});

($progtime) =
($timeptr->as_text =~ /\s*(\d*:\d*...\d*:\d*.)\s*/);

my $textline1 = $short_pn . " (" . $progtime . ")";

my $showlistptr = $ptr->look_down('class','bcta',
sub {
$_[0]->look_down('_tag', 'a')
});
# get station information and put things into the streams array
my $stationname;
my $stationstreamcount = 0;
my @showwalkerlist = $showlistptr->find_by_tag_name('a');

foreach my $showwalker (@showwalkerlist) {

my $foo = $showwalker->look_down('tag', 'b');

if ($showwalker->look_down('_tag','b')) {
($stationname) = ($showwalker->as_text =~ /\s*(\S*)\s*/);
$stationstreamcount = 0;
}
if ($showwalker->look_down('alt','[MP3]')) {
my @streamlinks = $showwalker->extract_links('a');
$stationstreamcount++;
my $textline2 = $stationname;
if ($stationstreamcount > 1) {
$textline2 .= " ($stationstreamcount)";
}
my $link = $streamlinks[0][0][0];

push @streams, [$link, $textline1, $textline2];
}
}

$streams{$current_program{$client}} = [@streams];

$ptr = $ptr->right;
}
}


$tree->delete;
}
$status{$client} = 1;
$client->update();

};



my %StreamsFunctions = (
'up' => sub {
my $client = shift;
my @streams = @{ $streams{$current_program{$client}} };
$current_stream{$client} = Slim::Buttons::Common::scroll(
$client,
-1,
$#streams + 1,
$current_stream{$client} || 0,
);
$client->update();
},
'down' => sub {
my $client = shift;
my @streams = @{ $streams{$current_program{$client}} };
$current_stream{$client} = Slim::Buttons::Common::scroll(
$client,
1,
$#streams + 1,
$current_stream{$client} || 0,
);
$client->update();
},
'left' => sub {
my $client = shift;
$old_stream{$current_program{$client}}{$client} = $current_stream{$client};
Slim::Buttons::Common::popModeRight($client);
},
'right' => sub {
my $client = shift;
Slim::Display::Animation::bumpRight($client);
},
'play' => sub {
my $client = shift;
my @streams = @{ $streams{$current_program{$client}} };
my $current_array = $streams[$current_stream{$client}];
my $playlist_url = $current_array->[0];

Slim::Control::Command::execute($client, ['playlist', 'load', $playlist_url]);
},
'jump_rew' => sub {
my $client = shift;
$status{$client} = 0;
$force_reload = 1;
delete $streams{$current_program{$client}};
$streams_mode_sub->($client);
},
);


sub StreamsLines() {

my $client = shift;
my (@lines);
$current_stream{$client} ||= 0;

if ($status{$client} == 0) {
$lines[0] = '';
if ($force_reload) {
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
}
$lines[1] = '';
} elsif ($status{$client} == -1) {
$lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
$lines[1] = '';
} elsif ($status{$client} == 1) {
# print STDERR join ', ', %streams;
my @streams = @{ $streams{$current_program{$client}} };

my $current_array = $streams[$current_stream{$client}];

my $textline1 = $current_array->[1];
my $textline2 = $current_array->[2];

# print "textline1: $textline1\n";
# print "textline2: $textline2\n";


$lines[0] = $textline1 .
' (' .
($current_stream{$client} + 1) . ' ' .
Slim::Utils::Strings::string('OF') . ' ' .
($#streams + 1) . ') ' ;
$lines[1] = $textline2;
}

return @lines;
}



# Add extra mode

Slim::Buttons::Common::addMode('PublicRadioProgram s', \%ProgramsFunctions, $programs_mode_sub);

Slim::Buttons::Common::addMode('PublicRadioStreams ', \%StreamsFunctions, $streams_mode_sub);

1;

__DATA__
PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME
EN PublicRadioFan.com Streams

PLUGIN_PUBLICRADIOFANBROWSER_GENRES
EN Public Radio Genres

PLUGIN_PUBLICRADIOFANBROWSER_CONNECTING
EN Connecting...

PLUGIN_PUBLICRADIOFANBROWSER_BEG
EN Please donate to PublicRadioFan.com

PLUGIN_PUBLICRADIOFANBROWSER_NETWORK_ERROR
EN Error: PublicRadioFan.comnot available

PLUGIN_PUBLICRADIOFANBROWSER_STREAMS
EN Streams

PLUGIN_PUBLICRADIOFANBROWSER_PROGRAMS
EN Programs

PLUGIN_PUBLICRADIOFANBROWSER_DOTS
EN ...

Ben Klaas
2004-12-21, 08:19
Tom-- we're thinking in parallel...I am planning on revving the playlist
creator script I made for specific shows to include real audio, if
specified by the user on the command-line (something like,
--include_real). That's the short-term--I should be able to do that in
10 minutes or so. For the longer-term, I (or someone else...I don't
care) will start developing a new version of the PublicRadioFanBrowser
plugin that not only includes the real audio option, but also a
configurable "show browser" in addition to a "what's on now" browser.

#!/ben

Thomas B. Malsbury wrote:

> I was just wondering how much work it would be to rework the current
> PublicRadioFanBrowser plugin to handle RealAudio streams through
> AlienBBC.
>
> Currently the plugin only requests MP3 streams from
> PublicRadioFan.com. It is simple to request addition formats (real
> audio in this case) by adding the following to the request url,
> &sty=rm (real audio). I was thinking that it could parse the page
> retrieved using &sty=rm&sty=mp3 in the request url. Then the the
> streams that come up as mp3 can be handled as in the past and passed
> directly to slimserver. Streams that come up as real audio could be
> reformatted to include the AlienBBC proxy as used in the creation of
> the This American Life playlists.
> This would greatly expand the available Public Radio streams to
> Slimserver ( on linux ;) )
>
> Just a thought,
>
> Tom
>
> ps: I have attached the PublicRadioFanBrowser.pm in its current state
> if anyone would like to have a look at it.
>
>------------------------------------------------------------------------
>
># PublicRadioFanComBrowser.pm Copyright (C) 2003 Ted Rathkopf
># version 0.1, 21 September 2003
>#
># A Slimp3 plugin for browsing the PublicRadioFan.com web directory of
># mp3 streams. Inspired by ShoutcastBrowser, which was in turn
># inspired by streamtuner.
>#
># This code is derived from code with the following copyright message:
>#
># ShoutcastBrowser.pm Copyright (C) 2003 Peter Heslin
>#
># SliMP3 Server Copyright (C) 2001 Sean Adams, Slim Devices Inc.
># This program is free software; you can redistribute it and/or
># modify it under the terms of the GNU General Public License,
># version 2.
>#
># Also contains code derived from from Kevin Walsh's Weather.pm
>
>#
># This plugin wouldn't be possible without the Kevin A. Kelly's
># wonderful website publicradiofan.com. If you find this plugin
># useful, please donate to publicradiofan.com.
># http://www.publicradiofan.com/donate.html
>
># The PublicRadioFan.com website is owned by Kevin A. Kelly. The
># site and its database (c) 2001-2003, Kevin A. Kelly.
>#
>
>package Plugins::PublicRadioFanBrowser;
>use strict;
>
>################### Configuration Section ########################
>#
>my $base_url = "http://www.publicradiofan.com";
>my $when = "nowsoon"; # "now" or "nowsoon"
>
>my $timezone="-6,CST,-5,CDT,Central"; #default ('cause that's where I live)
>
># The timezone should be set for the timezone in which the slimp3 is running.
># uncomment one of the following:
>
># $timezone="-10,HST,-10,HST,Hawaii";
># $timezone="-9,AST,-8,ADT,Alaska";
> $timezone="-8,PST,-7,PDT,Pacific";
># $timezone="-7,MST,-7,MST,Arizona";
># $timezone="-7,MST,-6,MDT,Mountain";
># $timezone="-6,CST,-6,CST,Saskatchewan";
># $timezone="-6,CST,-5,CDT,Central";
># $timezone="-5,EST,-5,EST,Indiana";
># $timezone="-5,EST,-4,EDT,Eastern";
># $timezone="-4,AST,-3,ADT,Atlantic";
># $timezone="0,GMT,1,BST,Britain";
># $timezone="1,CET,2,CEST,Central Europe";
># $timezone="-12,(UTC-12),-12,(UTC-12),(UTC-12)";
># $timezone="-11,(UTC-11),-11,(UTC-11),(UTC-11)";
># $timezone="-10,(UTC-10),-10,(UTC-10),(UTC-10)";
># $timezone="-9,(UTC-9),-9,(UTC-9),(UTC-9)";
># $timezone="-8,(UTC-8),-8,(UTC-8),(UTC-8)";
># $timezone="-7,(UTC-7),-7,(UTC-7),(UTC-7)";
># $timezone="-6,(UTC-6),-6,(UTC-6),(UTC-6)";
># $timezone="-5,(UTC-5),-5,(UTC-5),(UTC-5)";
># $timezone="-4,(UTC-4),-4,(UTC-4),(UTC-4)";
># $timezone="-3,(UTC-3),-3,(UTC-3),(UTC-3)";
># $timezone="-2,(UTC-2),-2,(UTC-2),(UTC-2)";
># $timezone="-1,(UTC-1),-1,(UTC-1),(UTC-1)";
># $timezone="0,UTC,0,UTC,UTC";
># $timezone="1,(UTC+1),1,(UTC+1),(UTC+1)";
># $timezone="2,(UTC+2),2,(UTC+2),(UTC+2)";
># $timezone="3,(UTC+3),3,(UTC+3),(UTC+3)";
># $timezone="4,(UTC+4),4,(UTC+4),(UTC+4)";
># $timezone="5,(UTC+5),5,(UTC+5),(UTC+5)";
># $timezone="6,(UTC+6),6,(UTC+6),(UTC+6)";
># $timezone="7,(UTC+7),7,(UTC+7),(UTC+7)";
># $timezone="8,(UTC+8),8,(UTC+8),(UTC+8)";
># $timezone="9,(UTC+9),9,(UTC+9),(UTC+9)";
># $timezone="10,(UTC+10),10,(UTC+10),(UTC+10)";
># $timezone="11,(UTC+11),11,(UTC+11),(UTC+11)";
># $timezone="12,(UTC+12),12,(UTC+12),(UTC+12)";
># $timezone="13,(UTC+13),13,(UTC+13),(UTC+13)";
>
>
>#
>################### End Configuration Section ####################
>my $directory_url = "$base_url/cgi-bin/whatson.pl";
>my $startat = 0;
>
>my (%current_genre, %current_program, %old_program,
> %current_stream, %old_stream, %status);
>
>my @genres = ('Music','Non-Music');
>my @programs;
>
>my $musicurl = "$directory_url?when=$when\&type=music\&sty=mp3";
>my $nonmusicurl = "$directory_url?when=$when\&type=non-music\&sty=mp3";
>
>my $file_timeout = 600; #in seconds
>my $force_reload = 1;
>
>use Slim::Control::Command;
>use Slim::Utils::Strings qw (string);
>use LWP::Simple;
>use LWP::UserAgent;
>use HTTP::Cookies;
>use HTML::TreeBuilder;
>use File::Temp qw/ tempfile tempdir /;
>
>my $tempdir = tempdir("prfXXXXX", TMPDIR => 1 );
>my $musicfn = $tempdir . "/music.html";
>my $nonmusicfn = $tempdir . "/non-music.html";
>
>my (%streams, %programs, %programids);
>
>my $cookie_jar = HTTP::Cookies->new;
>
>
>my $ua = LWP::UserAgent->new;
>my $musicrequest = HTTP::Request->new('GET', $musicurl);
>my $nonmusicrequest = HTTP::Request->new('GET', $nonmusicurl);
>my $musicresponse;
>my $nonmusicresponse;
>
>$cookie_jar->set_cookie(0, 'Time Zone', $timezone, '/', 'publicradiofan.com', 80, 0, 0, 31536000);
>$cookie_jar->add_cookie_header($musicrequest);
>$cookie_jar->add_cookie_header($nonmusicrequest);
>
>sub getDisplayName() {return string('PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME') }
>
>sub strings()
>{
> local $/ = undef;
> <DATA>;
>}
>
>
>sub reload_htmlfiles() {
> $force_reload = 0;
> %streams = ();
> %programs = ();
> # print "reloading...\n";
> $musicresponse = $ua->request($musicrequest, $musicfn);
> $nonmusicresponse = $ua->request($nonmusicrequest, $nonmusicfn);
>
> # if (getstore($musicurl, $musicfn) != 200 ||
> # getstore($nonmusicurl, $nonmusicfn) != 200) {
> # my $client = shift;
> # $status{$client} = -1;
> # $client->update();
> # }
>
>}
>
>sub check_and_reload_htmlfiles() {
> # print "checking....force=$force_reload\n";
> my @fileattribs = stat $musicfn;
> reload_htmlfiles if ($force_reload ||
> time - $fileattribs[9] > $file_timeout);
>}
>
>sub addMenu {
> my $menu = "RADIO";
> return $menu;
>}
>
>##### Main mode for genres #####
>
>sub setMode() {
>
> my $client = shift;
> $client->lines(\&lines);
> $status{$client} = 0;
> $client->update();
>
> # Get genres
>
> check_and_reload_htmlfiles();
>
> $status{$client} = 1;
>
> $client->update();
>}
>
>my %functions = (
> 'up' => sub {
> my $client = shift;
> $current_genre{$client} = Slim::Buttons::Common::scroll(
> $client,
> -1,
> $#genres + 1,
> $current_genre{$client} || 0,
> );
> $client->update();
> },
> 'down' => sub {
> my $client = shift;
> $current_genre{$client} = Slim::Buttons::Common::scroll(
> $client,
> 1,
> $#genres + 1,
> $current_genre{$client} || 0,
> );
> $client->update();
> },
> 'left' => sub {
> my $client = shift;
> Slim::Buttons::Common::popModeRight($client);
> },
> 'right' => sub {
> my $client = shift;
> Slim::Buttons::Common::pushModeLeft($client, 'PublicRadioPrograms');
> },
> 'jump_rew' => sub {
> my $client = shift;
> $status{$client} = 0;
> $force_reload = 1;
> &setMode($client);
> },
> );
>
>
>
>sub lines {
> my $client = shift;
> my (@lines);
> $current_genre{$client} ||= 0;
>
> if ($status{$client} == 0) {
>
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_BEG');
> $lines[1] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
> } elsif ($status{$client} == -1) {
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
> $lines[1] = '';
> } elsif ($status{$client} == 1) {
> my $current_name = $genres[$current_genre{$client}];
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_GENRES').
> ' (' .
> ($current_genre{$client} + 1) . ' ' .
> Slim::Utils::Strings::string('OF') . ' ' .
> ($#genres + 1) . ') ' ;
> $lines[1] = $current_name;
> $lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
> }
>
> return @lines;
>}
>
>
>sub getFunctions() {
> return \%functions;
>}
>
>##### Sub-mode for programs #####
>
>my $programs_mode_sub = sub {
> my $client = shift;
> $client->lines(\&ProgramsLines);
> $status{$client} = 0;
> $current_program{$client} = $old_program{$current_genre{$client}}{$client} || 0;
> $client->update();
>
> # print "\n" . exists($programs{$current_genre{$client}}) . "\n";
>
>
> unless (exists $programs{$current_genre{$client}} && $force_reload == 0) {
> @programs = ();
> my $order_by = '';
>
> my $genre_name = $genres[$current_genre{$client}];
> $genre_name =~ s/M/m/;
> $genre_name =~ s/N/n/;
>
> my $genre_file = $tempdir . "/" . $genre_name . ".html";
>
> # my $url = "$directory_url?when=$when\&type=$genre_name\&sty=mp3";
>
> # my $content = get($url);
> # unless ($content)
> # {
> # $status{$client} = -1;
> # $client->update();
> # return;
> # }
>
> check_and_reload_htmlfiles();
> my $tree = HTML::TreeBuilder->new();
>
>
> $tree->parse_file($genre_file);
> # $tree->parse($content);
> $tree->eof();
>
>
> my @tds = $tree->look_down('_tag', 'td',
> 'class', 'bct'
> );
>
> foreach my $td (@tds) {
> my $text = $td->as_text;
> my @links = $td->extract_links('a');
> my $prfprogram_id = $links[0][1][0];
>
> if ($prfprogram_id) {
> push @programs, [$prfprogram_id, $text];
> }
> }
>
> $programs{$current_genre{$client}} = [@programs];
> %streams = ();
>
> #print "\n\nPrograms: ".scalar @programs."\n";
> #print $_->[1]."\n" for @programs;
>
> $tree->delete;
> }
> $status{$client} = 1;
> $client->update();
>
>};
>
>sub ProgramsLines() {
>
> my $client = shift;
> my (@lines);
> $current_program{$client} ||= 0;
> $current_genre{$client} ||= 0;
>
> if ($status{$client} == 0) {
> $lines[0] = '';
> if ($force_reload) {
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
> }
> $lines[1] = '';
> } elsif ($status{$client} == -1) {
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
> $lines[1] = '';
> } elsif ($status{$client} == 1) {
> # print STDERR join ', ', %programs;
> my @xprograms = @{ $programs{$current_genre{$client}} };
>
> my $current_array = $xprograms[$current_program{$client}];
> my $current_name = $current_array->[1];
>
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_PROGRAMS'). ' '.
> Slim::Utils::Strings::string('FOR') . ' ' .
> $genres[$current_genre{$client}] .
> ' (' .
> ($current_program{$client} + 1) . ' ' .
> Slim::Utils::Strings::string('OF') . ' ' .
> ($#xprograms + 1) . ') ' ;
> $lines[1] = $current_name;
> $lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
> }
>
> return @lines;
>}
>
>my %ProgramsFunctions = (
> 'up' => sub {
> my $client = shift;
> my @programs = @{ $programs{$current_genre{$client}} };
> $current_program{$client} = Slim::Buttons::Common::scroll(
> $client,
> -1,
> $#programs + 1,
> $current_program{$client} || 0,
> );
> $client->update();
> },
> 'down' => sub {
> my $client = shift;
> my @programs = @{ $programs{$current_genre{$client}} };
> $current_program{$client} = Slim::Buttons::Common::scroll(
> $client,
> 1,
> $#programs + 1,
> $current_program{$client} || 0,
> );
> $client->update();
> },
> 'left' => sub {
> my $client = shift;
> $old_program{$current_genre{$client}}{$client} = $current_program{$client};
> Slim::Buttons::Common::popModeRight($client);
> },
> 'right' => sub {
> my $client = shift;
> $old_program{$current_genre{$client}}{$client} = $current_program{$client};
> Slim::Buttons::Common::pushModeLeft($client, 'PublicRadioStreams');
> },
> 'jump_rew' => sub {
> my $client = shift;
> $status{$client} = 0;
> $force_reload = 1;
> delete $programs{$current_genre{$client}};
> $programs_mode_sub->($client);
> },
> );
>
>#
># sub mode for streams
>#
>
>my $streams_mode_sub = sub {
> my $client = shift;
> $client->lines(\&StreamsLines);
> $status{$client} = 0;
> $current_stream{$client} = $old_stream{$current_program{$client}}{$client} || 0;
> $client->update();
>
> unless (exists $streams{$current_program{$client}}) {
>
> my @pn = $programs[$current_program{$client}];
> my $prfprogram_id = $pn[0][0];
> my $program_name = $pn[0][1];
> my $short_pn;
> ($short_pn) = ($program_name =~ /^(.*) \(.*\)/);
> my $genre_name = $genres[$current_genre{$client}];
> $genre_name =~ s/M/m/;
> $genre_name =~ s/N/n/;
>
> my $genre_file = $tempdir . "/" . $genre_name . ".html";
>
> # my $url = "$directory_url?when=$when\&type=$genre_name\&sty=mp3";
>
> # my $content = get($url);
>
> # unless ($content)
> # {
> # $status{$client} = -1;
> # $client->update();
> # return;
> # }
>
> check_and_reload_htmlfiles();
> my $tree = HTML::TreeBuilder->new();
>
> # print "$genre_file\n";
> # $tree->parse($content);
> $tree->parse_file($genre_file);
> $tree->eof();
>
> my $prog = $tree->look_down('_tag', 'a',
> 'href', $prfprogram_id
> );
>
> if (!defined($prog)) {
> $force_reload = 1;
> Slim::Buttons::Common::popModeRight($client);
> }
>
> $prog = $prog->parent->parent;
> my $thisprog = 1;
> my $progtime;
> my @tds = ();
> my @streams;
>
> my $ptr=$prog->right;
> while ($thisprog && $ptr) {
> if ($ptr->look_down('class','bct')) {
> $thisprog = 0;
> } else {
> my $timeptr = $ptr->look_down('class','bcta',
> sub {
> not $_[0]->look_down('_tag', 'a')
> });
>
> ($progtime) =
> ($timeptr->as_text =~ /\s*(\d*:\d*...\d*:\d*.)\s*/);
>
> my $textline1 = $short_pn . " (" . $progtime . ")";
>
> my $showlistptr = $ptr->look_down('class','bcta',
> sub {
> $_[0]->look_down('_tag', 'a')
> });
> # get station information and put things into the streams array
> my $stationname;
> my $stationstreamcount = 0;
> my @showwalkerlist = $showlistptr->find_by_tag_name('a');
>
> foreach my $showwalker (@showwalkerlist) {
>
> my $foo = $showwalker->look_down('tag', 'b');
>
> if ($showwalker->look_down('_tag','b')) {
> ($stationname) = ($showwalker->as_text =~ /\s*(\S*)\s*/);
> $stationstreamcount = 0;
> }
> if ($showwalker->look_down('alt','[MP3]')) {
> my @streamlinks = $showwalker->extract_links('a');
> $stationstreamcount++;
> my $textline2 = $stationname;
> if ($stationstreamcount > 1) {
> $textline2 .= " ($stationstreamcount)";
> }
> my $link = $streamlinks[0][0][0];
>
> push @streams, [$link, $textline1, $textline2];
> }
> }
>
> $streams{$current_program{$client}} = [@streams];
>
> $ptr = $ptr->right;
> }
> }
>
>
> $tree->delete;
> }
> $status{$client} = 1;
> $client->update();
>
>};
>
>
>
>my %StreamsFunctions = (
> 'up' => sub {
> my $client = shift;
> my @streams = @{ $streams{$current_program{$client}} };
> $current_stream{$client} = Slim::Buttons::Common::scroll(
> $client,
> -1,
> $#streams + 1,
> $current_stream{$client} || 0,
> );
> $client->update();
> },
> 'down' => sub {
> my $client = shift;
> my @streams = @{ $streams{$current_program{$client}} };
> $current_stream{$client} = Slim::Buttons::Common::scroll(
> $client,
> 1,
> $#streams + 1,
> $current_stream{$client} || 0,
> );
> $client->update();
> },
> 'left' => sub {
> my $client = shift;
> $old_stream{$current_program{$client}}{$client} = $current_stream{$client};
> Slim::Buttons::Common::popModeRight($client);
> },
> 'right' => sub {
> my $client = shift;
> Slim::Display::Animation::bumpRight($client);
> },
> 'play' => sub {
> my $client = shift;
> my @streams = @{ $streams{$current_program{$client}} };
> my $current_array = $streams[$current_stream{$client}];
> my $playlist_url = $current_array->[0];
>
> Slim::Control::Command::execute($client, ['playlist', 'load', $playlist_url]);
> },
> 'jump_rew' => sub {
> my $client = shift;
> $status{$client} = 0;
> $force_reload = 1;
> delete $streams{$current_program{$client}};
> $streams_mode_sub->($client);
> },
> );
>
>
>sub StreamsLines() {
>
> my $client = shift;
> my (@lines);
> $current_stream{$client} ||= 0;
>
> if ($status{$client} == 0) {
> $lines[0] = '';
> if ($force_reload) {
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
> }
> $lines[1] = '';
> } elsif ($status{$client} == -1) {
> $lines[0] = Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
> $lines[1] = '';
> } elsif ($status{$client} == 1) {
> # print STDERR join ', ', %streams;
> my @streams = @{ $streams{$current_program{$client}} };
>
> my $current_array = $streams[$current_stream{$client}];
>
> my $textline1 = $current_array->[1];
> my $textline2 = $current_array->[2];
>
> # print "textline1: $textline1\n";
> # print "textline2: $textline2\n";
>
>
> $lines[0] = $textline1 .
> ' (' .
> ($current_stream{$client} + 1) . ' ' .
> Slim::Utils::Strings::string('OF') . ' ' .
> ($#streams + 1) . ') ' ;
> $lines[1] = $textline2;
> }
>
> return @lines;
>}
>
>
>
># Add extra mode
>
>Slim::Buttons::Common::addMode('PublicRadioProgram s', \%ProgramsFunctions, $programs_mode_sub);
>
>Slim::Buttons::Common::addMode('PublicRadioStreams ', \%StreamsFunctions, $streams_mode_sub);
>
>1;
>
>__DATA__
>PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME
> EN PublicRadioFan.com Streams
>
>PLUGIN_PUBLICRADIOFANBROWSER_GENRES
> EN Public Radio Genres
>
>PLUGIN_PUBLICRADIOFANBROWSER_CONNECTING
> EN Connecting...
>
>PLUGIN_PUBLICRADIOFANBROWSER_BEG
> EN Please donate to PublicRadioFan.com
>
>PLUGIN_PUBLICRADIOFANBROWSER_NETWORK_ERROR
> EN Error: PublicRadioFan.comnot available
>
>PLUGIN_PUBLICRADIOFANBROWSER_STREAMS
> EN Streams
>
>PLUGIN_PUBLICRADIOFANBROWSER_PROGRAMS
> EN Programs
>
>PLUGIN_PUBLICRADIOFANBROWSER_DOTS
> EN ...
>
>

Ben Klaas
2004-12-21, 12:44
attached is v1.1 of my Public Radio Fan show playlist creator. I've
added a command-line option for including real audio streams, and I'm
now using the more formal Getopt::Long for command-line arguments.

cheers,
#!/ben

note-- usage has changed from the original version. Here's the --help
output.

[bklaas@shaggy bin]$ ./prfan_playlist.pl --help

################################################## #####
usage: prfan_playlist.pl (--help) --title title_of_playlist --programid
program_id_of_show (--real)

Example: ./prfan_playlist.pl --title "Wait Wait" --programid 46
--real
--title
Specify a title for the playlist. The script will
create a directory with
this name and a set of 1 stream playlist files for each
station/time slot combination
--programid
Specify the programid of the show for which you want to
create a playlist.
You get the programid from the URL for the show on
publicradiofan.com
--real
Include this option if you want real audio streams to
be included.
note: you need to have AlienBBC installed to stream
real audio out slimserver

################################################## #####


Ben Klaas wrote:
> Tom-- we're thinking in parallel...I am planning on revving the playlist
> creator script I made for specific shows to include real audio, if
> specified by the user on the command-line (something like,
> --include_real). That's the short-term--I should be able to do that in
> 10 minutes or so. For the longer-term, I (or someone else...I don't
> care) will start developing a new version of the PublicRadioFanBrowser
> plugin that not only includes the real audio option, but also a
> configurable "show browser" in addition to a "what's on now" browser.
>
> #!/ben
>
> Thomas B. Malsbury wrote:
>
>> I was just wondering how much work it would be to rework the current
>> PublicRadioFanBrowser plugin to handle RealAudio streams through
>> AlienBBC.
>>
>> Currently the plugin only requests MP3 streams from
>> PublicRadioFan.com. It is simple to request addition formats (real
>> audio in this case) by adding the following to the request url,
>> &sty=rm (real audio). I was thinking that it could parse the page
>> retrieved using &sty=rm&sty=mp3 in the request url. Then the the
>> streams that come up as mp3 can be handled as in the past and passed
>> directly to slimserver. Streams that come up as real audio could be
>> reformatted to include the AlienBBC proxy as used in the creation of
>> the This American Life playlists.
>> This would greatly expand the available Public Radio streams to
>> Slimserver ( on linux ;) )
>>
>> Just a thought,
>>
>> Tom
>>
>> ps: I have attached the PublicRadioFanBrowser.pm in its current state
>> if anyone would like to have a look at it.
>>
>> ------------------------------------------------------------------------
>>
>> # PublicRadioFanComBrowser.pm Copyright (C) 2003 Ted Rathkopf
>> # version 0.1, 21 September 2003
>> # # A Slimp3 plugin for browsing the PublicRadioFan.com web directory of
>> # mp3 streams. Inspired by ShoutcastBrowser, which was in turn
>> # inspired by streamtuner.
>> #
>> # This code is derived from code with the following copyright message:
>> #
>> # ShoutcastBrowser.pm Copyright (C) 2003 Peter Heslin
>> #
>> # SliMP3 Server Copyright (C) 2001 Sean Adams, Slim Devices Inc.
>> # This program is free software; you can redistribute it and/or
>> # modify it under the terms of the GNU General Public License,
>> # version 2.
>> #
>> # Also contains code derived from from Kevin Walsh's Weather.pm
>>
>> #
>> # This plugin wouldn't be possible without the Kevin A. Kelly's
>> # wonderful website publicradiofan.com. If you find this plugin
>> # useful, please donate to publicradiofan.com.
>> # http://www.publicradiofan.com/donate.html
>>
>> # The PublicRadioFan.com website is owned by Kevin A. Kelly. The
>> # site and its database (c) 2001-2003, Kevin A. Kelly.
>> #
>>
>> package Plugins::PublicRadioFanBrowser;
>> use strict;
>>
>> ################### Configuration Section ########################
>> #
>> my $base_url = "http://www.publicradiofan.com";
>> my $when = "nowsoon"; # "now" or "nowsoon"
>>
>> my $timezone="-6,CST,-5,CDT,Central"; #default ('cause that's where I
>> live)
>>
>> # The timezone should be set for the timezone in which the slimp3 is
>> running.
>> # uncomment one of the following:
>>
>> # $timezone="-10,HST,-10,HST,Hawaii";
>> # $timezone="-9,AST,-8,ADT,Alaska";
>> $timezone="-8,PST,-7,PDT,Pacific";
>> # $timezone="-7,MST,-7,MST,Arizona";
>> # $timezone="-7,MST,-6,MDT,Mountain";
>> # $timezone="-6,CST,-6,CST,Saskatchewan";
>> # $timezone="-6,CST,-5,CDT,Central";
>> # $timezone="-5,EST,-5,EST,Indiana";
>> # $timezone="-5,EST,-4,EDT,Eastern";
>> # $timezone="-4,AST,-3,ADT,Atlantic";
>> # $timezone="0,GMT,1,BST,Britain";
>> # $timezone="1,CET,2,CEST,Central Europe";
>> # $timezone="-12,(UTC-12),-12,(UTC-12),(UTC-12)";
>> # $timezone="-11,(UTC-11),-11,(UTC-11),(UTC-11)";
>> # $timezone="-10,(UTC-10),-10,(UTC-10),(UTC-10)";
>> # $timezone="-9,(UTC-9),-9,(UTC-9),(UTC-9)";
>> # $timezone="-8,(UTC-8),-8,(UTC-8),(UTC-8)";
>> # $timezone="-7,(UTC-7),-7,(UTC-7),(UTC-7)";
>> # $timezone="-6,(UTC-6),-6,(UTC-6),(UTC-6)";
>> # $timezone="-5,(UTC-5),-5,(UTC-5),(UTC-5)";
>> # $timezone="-4,(UTC-4),-4,(UTC-4),(UTC-4)";
>> # $timezone="-3,(UTC-3),-3,(UTC-3),(UTC-3)";
>> # $timezone="-2,(UTC-2),-2,(UTC-2),(UTC-2)";
>> # $timezone="-1,(UTC-1),-1,(UTC-1),(UTC-1)";
>> # $timezone="0,UTC,0,UTC,UTC";
>> # $timezone="1,(UTC+1),1,(UTC+1),(UTC+1)";
>> # $timezone="2,(UTC+2),2,(UTC+2),(UTC+2)";
>> # $timezone="3,(UTC+3),3,(UTC+3),(UTC+3)";
>> # $timezone="4,(UTC+4),4,(UTC+4),(UTC+4)";
>> # $timezone="5,(UTC+5),5,(UTC+5),(UTC+5)";
>> # $timezone="6,(UTC+6),6,(UTC+6),(UTC+6)";
>> # $timezone="7,(UTC+7),7,(UTC+7),(UTC+7)";
>> # $timezone="8,(UTC+8),8,(UTC+8),(UTC+8)";
>> # $timezone="9,(UTC+9),9,(UTC+9),(UTC+9)";
>> # $timezone="10,(UTC+10),10,(UTC+10),(UTC+10)";
>> # $timezone="11,(UTC+11),11,(UTC+11),(UTC+11)";
>> # $timezone="12,(UTC+12),12,(UTC+12),(UTC+12)";
>> # $timezone="13,(UTC+13),13,(UTC+13),(UTC+13)";
>>
>>
>> #
>> ################### End Configuration Section ####################
>> my $directory_url = "$base_url/cgi-bin/whatson.pl";
>> my $startat = 0;
>>
>> my (%current_genre, %current_program, %old_program,
>> %current_stream, %old_stream, %status);
>>
>> my @genres = ('Music','Non-Music');
>> my @programs;
>>
>> my $musicurl = "$directory_url?when=$when\&type=music\&sty=mp3";
>> my $nonmusicurl = "$directory_url?when=$when\&type=non-music\&sty=mp3";
>>
>> my $file_timeout = 600; #in seconds
>> my $force_reload = 1;
>>
>> use Slim::Control::Command;
>> use Slim::Utils::Strings qw (string);
>> use LWP::Simple;
>> use LWP::UserAgent;
>> use HTTP::Cookies;
>> use HTML::TreeBuilder;
>> use File::Temp qw/ tempfile tempdir /;
>>
>> my $tempdir = tempdir("prfXXXXX", TMPDIR => 1 );
>> my $musicfn = $tempdir . "/music.html";
>> my $nonmusicfn = $tempdir . "/non-music.html";
>>
>> my (%streams, %programs, %programids);
>>
>> my $cookie_jar = HTTP::Cookies->new;
>>
>>
>> my $ua = LWP::UserAgent->new;
>> my $musicrequest = HTTP::Request->new('GET', $musicurl);
>> my $nonmusicrequest = HTTP::Request->new('GET', $nonmusicurl);
>> my $musicresponse;
>> my $nonmusicresponse;
>>
>> $cookie_jar->set_cookie(0, 'Time Zone', $timezone, '/',
>> 'publicradiofan.com', 80, 0, 0, 31536000);
>> $cookie_jar->add_cookie_header($musicrequest);
>> $cookie_jar->add_cookie_header($nonmusicrequest);
>>
>> sub getDisplayName() {return
>> string('PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME') }
>>
>> sub strings() { local $/ = undef;
>> <DATA>;
>> }
>>
>>
>> sub reload_htmlfiles() {
>> $force_reload = 0;
>> %streams = ();
>> %programs = ();
>> # print "reloading...\n";
>> $musicresponse = $ua->request($musicrequest, $musicfn);
>> $nonmusicresponse = $ua->request($nonmusicrequest, $nonmusicfn);
>>
>> # if (getstore($musicurl, $musicfn) != 200 || #
>> getstore($nonmusicurl, $nonmusicfn) != 200) {
>> # my $client = shift;
>> # $status{$client} = -1;
>> # $client->update();
>> # }
>>
>> }
>>
>> sub check_and_reload_htmlfiles() {
>> # print "checking....force=$force_reload\n";
>> my @fileattribs = stat $musicfn;
>> reload_htmlfiles if ($force_reload ||
>> time - $fileattribs[9] > $file_timeout);
>> }
>>
>> sub addMenu {
>> my $menu = "RADIO";
>> return $menu;
>> }
>>
>> ##### Main mode for genres #####
>>
>> sub setMode() {
>>
>> my $client = shift;
>> $client->lines(\&lines);
>> $status{$client} = 0;
>> $client->update();
>>
>> # Get genres
>>
>> check_and_reload_htmlfiles();
>>
>> $status{$client} = 1;
>>
>> $client->update();
>> }
>>
>> my %functions = (
>> 'up' => sub {
>> my $client = shift;
>> $current_genre{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> -1,
>>
>> $#genres + 1,
>>
>> $current_genre{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'down' => sub {
>> my $client = shift;
>> $current_genre{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> 1,
>>
>> $#genres + 1,
>>
>> $current_genre{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'left' => sub {
>> my $client = shift;
>> Slim::Buttons::Common::popModeRight($client);
>> },
>> 'right' => sub {
>> my $client = shift;
>> Slim::Buttons::Common::pushModeLeft($client,
>> 'PublicRadioPrograms');
>> },
>> 'jump_rew' => sub {
>> my $client = shift;
>> $status{$client} = 0;
>> $force_reload = 1;
>> &setMode($client);
>> },
>> );
>>
>>
>>
>> sub lines {
>> my $client = shift;
>> my (@lines);
>> $current_genre{$client} ||= 0;
>>
>> if ($status{$client} == 0) {
>>
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_BEG');
>> $lines[1] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
>> } elsif ($status{$client} == -1) {
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
>>
>> $lines[1] = '';
>> } elsif ($status{$client} == 1) {
>> my $current_name = $genres[$current_genre{$client}];
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_GENRES').
>> ' (' . ($current_genre{$client} + 1) . '
>> ' . Slim::Utils::Strings::string('OF') . ' ' .
>> ($#genres + 1) . ') ' ;
>> $lines[1] = $current_name;
>> $lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
>> }
>> return @lines;
>> }
>>
>> sub getFunctions() {
>> return \%functions;
>> }
>>
>> ##### Sub-mode for programs #####
>>
>> my $programs_mode_sub = sub {
>> my $client = shift;
>> $client->lines(\&ProgramsLines);
>> $status{$client} = 0;
>> $current_program{$client} =
>> $old_program{$current_genre{$client}}{$client} || 0;
>> $client->update();
>>
>> # print "\n" . exists($programs{$current_genre{$client}}) . "\n";
>>
>>
>> unless (exists $programs{$current_genre{$client}} && $force_reload
>> == 0) {
>> @programs = ();
>> my $order_by = '';
>> my $genre_name = $genres[$current_genre{$client}];
>> $genre_name =~ s/M/m/;
>> $genre_name =~ s/N/n/;
>>
>> my $genre_file = $tempdir . "/" . $genre_name . ".html";
>>
>> # my $url =
>> "$directory_url?when=$when\&type=$genre_name\&sty=mp3";
>>
>> # my $content = get($url);
>> # unless ($content)
>> # {
>> # $status{$client} = -1;
>> # $client->update();
>> # return;
>> # } check_and_reload_htmlfiles();
>> my $tree = HTML::TreeBuilder->new();
>>
>>
>> $tree->parse_file($genre_file);
>> # $tree->parse($content);
>> $tree->eof();
>>
>>
>> my @tds = $tree->look_down('_tag', 'td',
>> 'class', 'bct'
>> );
>> foreach my $td (@tds) {
>> my $text = $td->as_text;
>> my @links = $td->extract_links('a');
>> my $prfprogram_id = $links[0][1][0];
>>
>> if ($prfprogram_id) {
>> push @programs, [$prfprogram_id, $text];
>> }
>> }
>>
>> $programs{$current_genre{$client}} = [@programs];
>> %streams = ();
>>
>> #print "\n\nPrograms: ".scalar @programs."\n";
>> #print $_->[1]."\n" for @programs;
>>
>> $tree->delete;
>> }
>> $status{$client} = 1;
>> $client->update();
>>
>> };
>>
>> sub ProgramsLines() {
>>
>> my $client = shift;
>> my (@lines);
>> $current_program{$client} ||= 0;
>> $current_genre{$client} ||= 0;
>>
>> if ($status{$client} == 0) {
>> $lines[0] = '';
>> if ($force_reload) {
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
>> }
>> $lines[1] = '';
>> } elsif ($status{$client} == -1) {
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
>>
>> $lines[1] = '';
>> } elsif ($status{$client} == 1) {
>> # print STDERR join ', ', %programs;
>> my @xprograms = @{ $programs{$current_genre{$client}} };
>> my $current_array = $xprograms[$current_program{$client}];
>> my $current_name = $current_array->[1];
>>
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_PROGRAMS').
>> ' '.
>> Slim::Utils::Strings::string('FOR') . ' ' .
>> $genres[$current_genre{$client}] .
>> ' (' .
>> ($current_program{$client} + 1) . ' ' .
>> Slim::Utils::Strings::string('OF') .
>> ' ' . ($#xprograms + 1) . ')
>> ' ;
>> $lines[1] = $current_name;
>> $lines[3] = Slim::Hardware::VFD::symbol('rightarrow');
>> }
>> return @lines;
>> }
>>
>> my %ProgramsFunctions = (
>> 'up' => sub {
>> my $client = shift;
>> my @programs = @{
>> $programs{$current_genre{$client}} };
>> $current_program{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> -1,
>>
>> $#programs + 1,
>>
>> $current_program{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'down' => sub {
>> my $client = shift;
>> my @programs = @{
>> $programs{$current_genre{$client}} };
>> $current_program{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> 1,
>>
>> $#programs + 1,
>>
>> $current_program{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'left' => sub {
>> my $client = shift;
>>
>> $old_program{$current_genre{$client}}{$client} =
>> $current_program{$client};
>>
>> Slim::Buttons::Common::popModeRight($client);
>> },
>> 'right' => sub {
>> my $client = shift;
>>
>> $old_program{$current_genre{$client}}{$client} =
>> $current_program{$client};
>>
>> Slim::Buttons::Common::pushModeLeft($client, 'PublicRadioStreams');
>> },
>> 'jump_rew' => sub {
>> my $client = shift;
>> $status{$client} = 0;
>> $force_reload = 1;
>> delete
>> $programs{$current_genre{$client}};
>> $programs_mode_sub->($client);
>> },
>> );
>>
>> #
>> # sub mode for streams
>> #
>>
>> my $streams_mode_sub = sub {
>> my $client = shift;
>> $client->lines(\&StreamsLines);
>> $status{$client} = 0;
>> $current_stream{$client} =
>> $old_stream{$current_program{$client}}{$client} || 0;
>> $client->update();
>>
>> unless (exists $streams{$current_program{$client}}) {
>> my @pn = $programs[$current_program{$client}];
>> my $prfprogram_id = $pn[0][0];
>> my $program_name = $pn[0][1];
>> my $short_pn;
>> ($short_pn) = ($program_name =~ /^(.*) \(.*\)/);
>> my $genre_name = $genres[$current_genre{$client}];
>> $genre_name =~ s/M/m/;
>> $genre_name =~ s/N/n/;
>>
>> my $genre_file = $tempdir . "/" . $genre_name . ".html";
>>
>> # my $url =
>> "$directory_url?when=$when\&type=$genre_name\&sty=mp3";
>>
>> # my $content = get($url);
>>
>> # unless ($content)
>> # {
>> # $status{$client} = -1;
>> # $client->update();
>> # return;
>> # } check_and_reload_htmlfiles();
>> my $tree = HTML::TreeBuilder->new();
>>
>> # print "$genre_file\n";
>> # $tree->parse($content);
>> $tree->parse_file($genre_file);
>> $tree->eof();
>>
>> my $prog = $tree->look_down('_tag', 'a',
>> 'href', $prfprogram_id
>> );
>>
>> if (!defined($prog)) {
>> $force_reload = 1;
>> Slim::Buttons::Common::popModeRight($client);
>> }
>>
>> $prog = $prog->parent->parent;
>> my $thisprog = 1;
>> my $progtime;
>> my @tds = ();
>> my @streams;
>>
>> my $ptr=$prog->right;
>> while ($thisprog && $ptr) {
>> if ($ptr->look_down('class','bct')) {
>> $thisprog = 0;
>> } else {
>> my $timeptr = $ptr->look_down('class','bcta',
>> sub {
>> not
>> $_[0]->look_down('_tag', 'a')
>> });
>>
>> ($progtime) = ($timeptr->as_text
>> =~ /\s*(\d*:\d*...\d*:\d*.)\s*/);
>>
>> my $textline1 = $short_pn . " (" . $progtime . ")";
>>
>> my $showlistptr = $ptr->look_down('class','bcta',
>> sub {
>>
>> $_[0]->look_down('_tag', 'a')
>> });
>> # get station information and put things into the
>> streams array
>> my $stationname;
>> my $stationstreamcount = 0;
>> my @showwalkerlist = $showlistptr->find_by_tag_name('a');
>>
>> foreach my $showwalker (@showwalkerlist) {
>>
>> my $foo = $showwalker->look_down('tag', 'b');
>>
>> if ($showwalker->look_down('_tag','b')) {
>> ($stationname) = ($showwalker->as_text =~
>> /\s*(\S*)\s*/);
>> $stationstreamcount = 0;
>> }
>> if ($showwalker->look_down('alt','[MP3]')) {
>> my @streamlinks =
>> $showwalker->extract_links('a');
>> $stationstreamcount++;
>> my $textline2 = $stationname;
>> if ($stationstreamcount > 1) {
>> $textline2 .= " ($stationstreamcount)";
>> }
>> my $link = $streamlinks[0][0][0];
>>
>> push @streams, [$link, $textline1, $textline2];
>> }
>> }
>>
>> $streams{$current_program{$client}} = [@streams];
>>
>> $ptr = $ptr->right;
>> }
>> }
>>
>>
>> $tree->delete;
>> }
>> $status{$client} = 1;
>> $client->update();
>>
>> };
>>
>>
>>
>> my %StreamsFunctions = (
>> 'up' => sub {
>> my $client = shift;
>> my @streams = @{
>> $streams{$current_program{$client}} };
>> $current_stream{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> -1,
>>
>> $#streams + 1,
>>
>> $current_stream{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'down' => sub {
>> my $client = shift;
>> my @streams = @{
>> $streams{$current_program{$client}} };
>> $current_stream{$client} =
>> Slim::Buttons::Common::scroll(
>>
>> $client,
>>
>> 1,
>>
>> $#streams + 1,
>>
>> $current_stream{$client} || 0,
>>
>> );
>> $client->update();
>> },
>> 'left' => sub {
>> my $client = shift;
>>
>> $old_stream{$current_program{$client}}{$client} =
>> $current_stream{$client};
>> Slim::Buttons::Common::popModeRight($client);
>> },
>> 'right' => sub {
>> my $client = shift;
>> Slim::Display::Animation::bumpRight($client);
>> },
>> 'play' => sub {
>> my $client = shift;
>> my @streams = @{
>> $streams{$current_program{$client}} };
>> my $current_array =
>> $streams[$current_stream{$client}];
>> my $playlist_url = $current_array->[0];
>>
>> Slim::Control::Command::execute($client, ['playlist', 'load',
>> $playlist_url]);
>> },
>> 'jump_rew' => sub {
>> my $client = shift;
>> $status{$client} = 0;
>> $force_reload = 1;
>> delete $streams{$current_program{$client}};
>> $streams_mode_sub->($client);
>> },
>> );
>>
>>
>> sub StreamsLines() {
>>
>> my $client = shift;
>> my (@lines);
>> $current_stream{$client} ||= 0;
>>
>> if ($status{$client} == 0) {
>> $lines[0] = '';
>> if ($force_reload) {
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_CONNECTING');
>> }
>> $lines[1] = '';
>> } elsif ($status{$client} == -1) {
>> $lines[0] =
>> Slim::Utils::Strings::string('PLUGIN_PUBLICRADIOFA NBROWSER_NETWORK_ERROR');
>>
>> $lines[1] = '';
>> } elsif ($status{$client} == 1) {
>> # print STDERR join ', ', %streams;
>> my @streams = @{ $streams{$current_program{$client}} };
>> my $current_array = $streams[$current_stream{$client}];
>> my $textline1 = $current_array->[1];
>> my $textline2 = $current_array->[2];
>>
>> # print "textline1: $textline1\n";
>> # print "textline2: $textline2\n";
>>
>>
>> $lines[0] = $textline1 .
>> ' (' . ($current_stream{$client} + 1) .
>> ' ' . Slim::Utils::Strings::string('OF') . ' '
>> . ($#streams + 1) . ') ' ;
>> $lines[1] = $textline2;
>> }
>> return @lines;
>> }
>>
>>
>>
>> # Add extra mode
>>
>> Slim::Buttons::Common::addMode('PublicRadioProgram s',
>> \%ProgramsFunctions, $programs_mode_sub);
>>
>> Slim::Buttons::Common::addMode('PublicRadioStreams ',
>> \%StreamsFunctions, $streams_mode_sub);
>>
>> 1;
>>
>> __DATA__
>> PLUGIN_PUBLICRADIOFANBROWSER_MODULE_NAME
>> EN PublicRadioFan.com Streams
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_GENRES
>> EN Public Radio Genres
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_CONNECTING
>> EN Connecting...
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_BEG
>> EN Please donate to PublicRadioFan.com
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_NETWORK_ERROR
>> EN Error: PublicRadioFan.comnot available
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_STREAMS
>> EN Streams
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_PROGRAMS
>> EN Programs
>>
>> PLUGIN_PUBLICRADIOFANBROWSER_DOTS
>> EN ...
>>
>>
>
>