#!/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);