#!/usr/bin/perl -Tw
use LWP::Simple;
use HTML::Parser;
my $cachedir="/tmp/on.radio.cache";
my $outputdir="/tmp/streams";
my $URL="http://www.internode.on.net/residential/entertainment/broadband_radio/";
my $cachefile=$cachedir."/"."root";
-d $cachedir || die "Cache dir $cachedir does not exist\n";
use Data::Dumper;
# the pattern goes:
# td:CopySolidFirstColumn(a:StationURL,b:Title)
# td:CopySolidCell(Subtitle)
# td:CopySolidCell(bandwidth)
# td:CopySolidCell(a:StreamURL)
my $state=0; # global
my $thistext=""; # global
my $thisclass="";
my @thislist=(); # global
my $neartables=0; # global
my $thisTitle=""; # name of station
my $thisSubtitle=""; # name of station
my $thisURL="";
my $thisWebsite="";
my $thisBandwidth="";
my $suffix="m3u";
sub munge {
# make a filename vfat-compatible
my $fn=shift;
$fn =~ s/['"~^\/!():]/_/g;
$fn =~ /^(.*)$/;
return $1;
}
sub fetch {
my $url=shift;
my $basename;
($basename)=($url =~ /\/([^\/]*)$/);
my $file=$cachedir."/".$basename;
my $code=mirror($url,$file);
return undef if is_error($code);
open(FILE,"<$file") or die "open: $!: $file\n";
while() {
chomp;
return $_ if $_ =~ /^http/;
}
return undef;
}
sub store {
my($thisTitle, $thisSubtitle, $thisWebsite, $thisURL, $thisBandwidth)=@_;
return unless defined $thisURL and length $thisURL;
return unless defined $thisTitle and length $thisTitle;
my $filename=$thisTitle.".".$suffix;
$filename = munge($filename);
print "$filename";
my $fetch=fetch($thisURL);
if (!defined($fetch)) {
print " - failed\n";
return undef;
}
print "\n";
$filepath=$outputdir."/".$filename;
open(FILE,">$filepath") or die "open: $!: $filepath\n";
print FILE "#EXTM3U\n";
print FILE "#EXTINF:-1,$thisTitle\n";
#print FILE "#$thisSubtitle\n";
#print FILE "#$thisWebsite\n";
#print FILE "#$thisBandwidth\n";
print FILE "$fetch\n";
close(FILE) or die "close: $!: $filepath\n";
}
sub start {
return unless $neartables;
my ($tag,$attr,$text)=@_;
if ($tag eq "a") {
if ($state == 1) {
$thisWebsite=$$attr{'href'};
$state++;
} elsif ($state == 9) {
$thisURL=$$attr{'href'};
$state++;
}
} elsif ($tag eq "b") {
$state++ if $state==1;
} elsif ($tag eq "td") {
my $class=$$attr{'class'};
if (defined($class)) {
$state=1 if $class eq "CopySolidFirstColumn";
$state++ if $state>=1 and $class eq "CopySolidCell";
$thisclass=$class;
}
}
$thistext="";
}
sub end {
return unless $neartables;
my ($tag,$attr,$text)=@_;
if ($tag eq "td") {
if ($state == 5) {
$thisTitle =~ s/^\s+//;
$thisTitle =~ s/\s+$//;
chomp($thisTitle);
$thisSubtitle =~ s/^\s+//;
$thisSubtitle =~ s/\s+$//;
}
if ($state == 10) {
store($thisTitle, $thisSubtitle, $thisWebsite, $thisURL, $thisBandwidth);
$thisclass="";
$thisTitle="";
$thisSubtitle="";
$thisURL="";
$thisWebsite="";
$thisBandwidth="";
$state=0;
}
$state++ if $state >= 2;
}
$thistext="";
}
sub text {
my ($tag,$attr,$text)=@_;
$neartables++ if $text eq "Radio Station List";
if ($state == 2) {
$state++;
$thisTitle=$text;
} elsif ($state == 7) {
$text =~ s/^\s+//;
$text =~ s/\s+$//;
$thisBandwidth = $text;
} elsif ($state == 5) {
$thisSubtitle .= $text;
}
}
$code=mirror($URL,$cachefile);
die "Failed to fetch: $URL ($code)\n"
if is_error($code);
my $parser=HTML::Parser->new( api_version => 3,
start_h => [\&start, "tagname, attr, dtext"],
end_h => [\&end, "tagname, attr, dtext"],
text_h => [\&text, "tagname, attr, dtext"],
#marked_sections => 1,
);
$parser->report_tags(qw(table td a b));
$parser->parse_file($cachefile);