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 ...
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 ...