Tivo Hacks. 100 Industrial-strength Tips Tools 2003
Hack 60 Streaming Internet Audio Broadcasts to TiVo
Stream SHOUTcast Internet audio alongside your own MP3s to your HMO-enabled TiVo .
TiVo's Home Media Option (HMO) [Hack #63] allows you to stream MP3 music from your home PC through your TiVo to your television and home audio system speakers . But what of those online music broadcasts, streamed talk shows, and specials? The HMO can handle those too, thanks to Tobias Hoellrich's m3ugen.pl (http://www.kahunaburger.com/blog/archives/000054.html).
m3ugen.pl is a simple Perl (http://www.perl.com) script that generates .m3u files from SHOUTcast playlists. These .m3u files are what TiVo uses to stream music from PCs and Macs in your house to TiVo.
The Code
Save the following code to a file named m3ugen.pl somewhere on your PC or Mac's hard drive:
#!c:\perl\bin\perl.exe use strict; use HTML::LinkExtor; use LWP::Simple; use URI::URL; use constant PROVIDER => qq{http://www.shoutcast.com/}; use constant DIRECTORY => PROVIDER.qq{directory/}; my $genre=$ARGV[0]; my $results=$ARGV[1]; my $outfile=$ARGV[2]; unless (defined($genre) && defined($results) && $results && $results <= 25 && defined($outfile)) { die qq{Usage:\t
#!c:\perl\bin\perl.exe use strict; use HTML::LinkExtor; use LWP::Simple; use URI::URL; use constant PROVIDER => qq{http://www.shoutcast.com/}; use constant DIRECTORY => PROVIDER.qq{directory/}; my $genre=$ARGV[0]; my $results=$ARGV[1]; my $outfile=$ARGV[2]; unless (defined($genre) && defined($results) && $results && $results <= 25 && defined($outfile)) { die qq{Usage:\t$0 [genre] [numresults] [outfile]\n}. qq{\tgenre=TopTen,House,Blues,Punk,...\n}. qq{\tnumresults=1..25\n}. qq{\toutfile=m3u output file\n}; } my @playlists=getPlaylists(DIRECTORY. qq{?sgenre=$ genre &numresult=$results},PROVIDER); unless (scalar(@playlists)) { die "No results found - unable to create playlist\n"; exit(0); } @playlists=mapForTiVo(@playlists); open (OUT,">".$outfile) or die "Unable to create output file - $!"; print OUT qq{#EXTM3U }; foreach my $entry (@playlists) { my($url,$title)=%$entry; print OUT qq{#EXTINF:,$title $url }; } close(OUT); sub getPlaylists { my($url,$base)=@_; my(@results); my $content=get($url); unless (defined($content) && length($content)) { warn qq{Unable to fetch "$url" }; return @results; } my $parser=HTML::LinkExtor->new(sub { my($t,%a)=@_; return if $t ne 'a'; push(@results,$a{href}) if($a{href}=~/filename\.pls$/i); }); $parser->parse($content); @results = map {$_=url(/books/1/554/1/html/2/$_,$base)->abs;} @results; return @results; } sub mapForTiVo { my(@list)=@_; my(@results); foreach my $url (@list) { my $content=get($url); next unless(defined($content) && length($content)); my($file); foreach my $line (split(/[\n\r]/,$content)) { if ($line =~ /^File\d+=(.*)$/i) { my $u=URI::URL->new($1); $u->path(""),$file=$u->abs if($u->path eq '/' $u-> path eq ''); } elsif ($line =~ /^Title\d+\s*=(.*)$/i && defined($file)) { push(@results,{$file => $1}); last; } } } return @results; } [genre] [numresults] [outfile]\n}. qq{\tgenre=TopTen,House,Blues,Punk,...\n}. qq{\tnumresults=1..25\n}. qq{\toutfile=m3u output file\n}; } my @playlists=getPlaylists(DIRECTORY. qq{?sgenre=$genre&numresult=$results},PROVIDER); unless (scalar(@playlists)) { die "No results found - unable to create playlist\n"; exit(0); } @playlists=mapForTiVo(@playlists); open(OUT,">".$outfile) or die "Unable to create output file - $!"; print OUT qq{#EXTM3U\n}; foreach my $entry (@playlists) { my($url,$title)=%$entry; print OUT qq{#EXTINF:,$title\n$url\n}; } close(OUT); sub getPlaylists { my($url,$base)=@_; my(@results); my $content=get($url); unless (defined($content) && length($content)) { warn qq{Unable to fetch "$url"\n}; return @results; } my $parser=HTML::LinkExtor->new(sub { my($t,%a)=@_; return if $t ne 'a'; push(@results,$a{href}) if($a{href}=~/filename\.pls$/i); }); $parser->parse($content); @results = map {$_=url($_,$base)->abs;} @results; return @results; } sub mapForTiVo { my(@list)=@_; my(@results); foreach my $url (@list) { my $content=get($url); next unless(defined($content) && length($content)); my($file); foreach my $line (split(/[\n\r]/,$content)) { if ($line =~ /^File\d+=(.*)$/i) { my $u=URI::URL->new(); $u->path(""),$file=$u->abs if($u->path eq '/' $u->path eq ''); } elsif ($line =~ /^Title\d+\s*=(.*)$/i && defined($file)) { push(@results,{$file => }); last; } } } return @results; }
Mac OS X should alter the first line to point to the proper location of Perl:
#!/usr/bin/perl
Running the Hack
Let's say I share the path c:\tivo\mp3\ on my Windows PC with my TiVo's HMO Music option. Let's also say that I want the top 15 Punk stations from SHOUTcast (http://www.shoutcast.com), so I can listen to the music broadcasts of these stations through my TiVo. I'd invoke the m3ugen.pl at my PC's DOS prompt (Start
C:\> perl m3ugen.pl Punk 15 c:\tivo\mp3\Punk.m3u
|
On a Mac, sharing the path ~/tivo/mp3/Punk.m3u , I'd run m3ugen.pl from the Terminal (Applications
% perl m3ugen.pl Punk 15 ~/tivo/mp3/Punk.m3u
The script will visit www.shoutcast.com, look up the Punk category, extract the playlists of the 15 most popular Punk stations, download each individual playlist, find TiVo-compatible server entries, and generate a Punk.m3u file.
|
You'll then magically find a Punk.m3u section under Music and Photos
Figure 4-25. The top 15 Punk SHOUTcast stations brought to your TiVo
|
If Punk's not quite your cup of tea, visit http://www.shoutcast.com and choose a more appropriate genre from the "Choose a genre " pull-down list on the right side of the page. The page will refresh, and you'll end up on a page whose URL begins with http://www.shoutcast.com/directory/?sgenre=. The word after the = (equals sign) is what you should feed m3ugen.pl on the command line to find the most popular streams of that genre.
Tobias Hoellrich
|
Top |