#!/usr/bin/perl -w ### Written by qbxk for perlmonks ### It is provided as is with no warranties, express or implied, of any kind. Use posted code at your own risk. $|++; use warnings; use strict; use Net::HTTP; use Data::Dumper; use Carp::Assert; use constant USER_AGENT => 'WinampMPEG/5.33'; # I got refused by some public servers unlessen i done it thar way my %HOST = ( host => 'rc.vc', port => 8000, mount => '/' ); sub debug(@) { print STDERR "\n" . join("\n", @_) . "\n"; } sub debug_raw(@) { print STDERR @_; } sub open_connection { my %args = ( host => undef, port => 80, mount => '', user_agent => USER_AGENT, @_ ); die "Need a host name" unless defined($args{host}); $args{mount} =~ s/^\/+//g; my $sock = Net::HTTP->new(Host => $args{host}, PeerPort => $args{port} ) || die $@; $sock->write_request(GET => "/$args{mount}", 'User-Agent' => $args{user_agent}, 'Icy-MetaData' => 1) or die $@; # my ($code, $mess, %headers) = $sock->read_response_headers( laxed => 1 ) my ($code, $mess, %headers); while( <$sock> ) { s/\s*$//g; last if /^\s*$/; if( /^(?:HTTP\/1\.[01]|ICY) ([0-9]+) (.+)$/ ) { ($code, $mess) = ($1 +0, $2); } else { my ($h, $v) = split(/:/); $headers{$h} = $v; } } return ($sock,$code,$mess,%headers); } main: { my ($s,$code, $mess, %headers) = open_connection( %HOST ); # debug "$code|$mess\n" . Dumper(\%headers); # TODO: timeout on $s. exit if( $code != 200 ); # scream and shout my ($metaint) = map { (/^icy-metaint$/i && $headers{$_}) or () } keys %headers; assert( $metaint > 0 ); while( 1 ) { my $buf; $s->read($buf, $metaint); my ($metadata, $metalen, $metabyte); $s->read($metabyte, 1); $metalen = unpack("C",$metabyte) * 16; if( $metalen > 0) { #We have NEW metadata! JOY $s->read($metadata, $metalen); $metadata = unpack("A$metalen", $metadata); assert( $metadata =~ /Stream/, "Not good metadata!" ); #don't dump a lot of BS (binary *#$!), just die. #debug "$metalen - [$metadata]"; my ($title) = $metadata =~ /StreamTitle='(.*?)';StreamUrl/i; print "$title"; exit(0); } else { $metadata = ''; debug_raw "-"; } } }