--- get_iplayer-2.41.orig 2009-10-02 13:04:23.000000000 +0100 +++ get_iplayer-2.41 2010-02-27 17:27:26.000000000 +0000 @@ -2494,6 +2494,87 @@ +sub get_playlist_url { + my $ua = shift; + my $url = shift; + my $filter = shift; + # Don't recurse more than 5 times + my $depth = 5; + + # Resolve the MMS url if it is an http ref + while ( $url =~ /^http/i && $depth ) { + my $content = main::request_url_retry($ua, $url, 2, '', ''); + # Reference list + if ( $content =~ m{\[reference\]}i ) { + my @urls; + # [Reference] + # Ref1=http://wm.bbc.co.uk/wms/england/radioberkshire/aod/andrewpeach_thu.wma?MSWMExt=.asf + # Ref2=http://wm.bbc.co.uk/wms/england/radioberkshire/aod/andrewpeach_thu.wma?MSWMExt=.asf + for ( split /ref\d*=/i, $content ) { + #main::logger "DEBUG: LINE: $_\n" if $opt->{debug}; + s/[\s]//g; + # Rename http:// to mms:// - don't really know why but this seems to be necessary with such playlists + s|http://|mms://|g; + push @urls, $_ if m{^(http|mms|rtsp)://}; + main::logger "DEBUG: Got Reference URL: $_\n" if $opt->{debug}; + } + # use first URL for now?? + $url = $urls[0]; + + # ASX XML based playlist + } elsif ( $content =~ m{ + # http://www.bbc.co.uk/ + # BBC support + # BBC + # (c) British Broadcasting Corporation + # + # + # + # + # + # + # + # BBC + # + # + for ( split /{debug}; + # Ignore anything except mms or http from this playlist + push @urls, $1 if m{ref\s+href=\"((http|$filter)://.+?)\"}i; + } + for ( @urls ) { + main::logger "DEBUG: Got ASX URL: $_\n" if $opt->{debug}; + } + # use first URL for now?? + $url = $urls[0]; + + # RAM format urls + } elsif ( $content =~ m{rtsp://}i ) { + my @urls; + for ( split /[\n\r\s]/i, $content ) { + main::logger "DEBUG: LINE: $_\n" if $opt->{debug}; + # Ignore anything except $filter or http from this playlist + push @urls, $1 if m{((http|$filter)://.+?)[\n\r\s]?$}i; + } + for ( @urls ) { + main::logger "DEBUG: Got RAM URL: $_\n" if $opt->{debug}; + } + # use first URL for now?? + $url = $urls[0]; + + } else { + chomp( $url = $content ); + } + $depth--; + } + + return $url; +} + + + ############## OO ################ ############## Options default class ################ @@ -3539,7 +3620,7 @@ my $retcode; # Use different number of retries for flash modes - $retries = $opt->{attempts} || 20 if $mode =~ /^flash/; + $retries = $opt->{attempts} || 50 if $mode =~ /^flash/; # Retry loop for ($count = 1; $count <= $retries; $count++) { @@ -4772,7 +4853,7 @@ # Common attributes # swfurl = Default iPlayer swf version my $conn = { - swfurl => "http://www.bbc.co.uk/emp/9player.swf?revision=10344_10753", + swfurl => "http://www.bbc.co.uk/emp/10player.swf?revision=15501_15796", ext => $ext, streamer => $streamer, bitrate => $mattribs->{bitrate}, @@ -4823,15 +4904,15 @@ # Level3 CDN } elsif ( $cattribs->{kind} eq 'level3' ) { $conn->{playpath} = $cattribs->{identifier}; - $conn->{application} = "$cattribs->{application}?$cattribs->{authstring}"; + $conn->{application} = "$cattribs->{application}?$cattribs->{authString}"; $conn->{tcurl} = "rtmp://$cattribs->{server}:1935/$conn->{application}"; $conn->{streamurl} = "rtmp://$cattribs->{server}:1935/ondemand?_fcs_vhost=$cattribs->{server}&auth=$cattribs->{authstring}&aifp=v001&slist=$cattribs->{identifier}"; # iplayertok CDN } elsif ( $cattribs->{kind} eq 'iplayertok' ) { $conn->{application} = $cattribs->{application}; - decode_entities($cattribs->{authstring}); - $conn->{playpath} = "$cattribs->{identifier}?$cattribs->{authstring}"; + decode_entities($cattribs->{authString}); + $conn->{playpath} = "$cattribs->{identifier}?$cattribs->{authString}"; $conn->{playpath} =~ s/^mp[34]://g; $conn->{streamurl} = "rtmp://$cattribs->{server}:1935/ondemand?_fcs_vhost=$cattribs->{server}&auth=$cattribs->{authstring}&aifp=v001&slist=$cattribs->{identifier}"; $conn->{tcurl} = "rtmp://$cattribs->{server}:1935/$conn->{application}"; @@ -5035,15 +5116,26 @@ # flashaac modes } elsif ( $mattribs->{kind} eq 'audio' && - $mattribs->{type} eq 'audio/mp4' && - $mattribs->{encoding} eq 'aac' + $mattribs->{type} eq 'audio/mp4' + # This also catches worldservice who happen not to set the encoding type + # && $mattribs->{encoding} eq 'aac' ) { - get_stream_data_cdn( \%data, $mattribs, 'flashaac', 'rtmp', 'aac' ); + # flashaachigh + if ( $mattribs->{bitrate} >= 192 ) { + get_stream_data_cdn( \%data, $mattribs, 'flashaachigh', 'rtmp', 'aac' ); + + # flashaacstd + } elsif ( $mattribs->{bitrate} >= 96 ) { + get_stream_data_cdn( \%data, $mattribs, 'flashaacstd', 'rtmp', 'aac' ); + + # flashaaclow + } else { + get_stream_data_cdn( \%data, $mattribs, 'flashaaclow', 'rtmp', 'aac' ); + } # flashaudio modes } elsif ( $mattribs->{kind} eq 'audio' && - $mattribs->{type} eq 'audio/mpeg' && - $mattribs->{encoding} eq 'mp3' + ( $mattribs->{type} eq 'audio/mpeg' || $mattribs->{type} eq 'audio/mp3' ) ) { get_stream_data_cdn( \%data, $mattribs, 'flashaudio', 'rtmp', 'mp3' ); @@ -5082,10 +5174,16 @@ # Do iphone redirect check regardless of an xml entry for iphone (except for EMP/Live) - sometimes the iphone streams exist regardless # Skip check if the modelist selected excludes iphone - if ( $prog->{pid} !~ /^http/i && $verpid !~ /^\?/ && grep /^iphone/, split ',', $prog->modelist() ) { - if ( my $streamurl = Streamer::iphone->get_url($ua, $verpid) ) { + if ( $prog->{pid} !~ /^http/i && $verpid !~ /^\?/ && $verpid !~ /^http:/ && grep /^iphone/, split ',', $prog->modelist() ) { + if ( my $streamurl = Streamer::iphone->get_url($ua, $prog->{pid}) ) { my $mode = 'iphone1'; - # Get iphone redirect + if ( $prog->{type} eq 'radio' ) { + $data{$mode}{bitrate} = 128; + $data{$mode}{type} = "(iplayer_streaming_http_mp3) http mp3 128kbps stream"; + } else { + $data{$mode}{bitrate} = 480; + $data{$mode}{type} = "(iplayer_streaming_http_mp4) http h264 480x272 480kbps stream"; + } $data{$mode}{streamurl} = $streamurl; $data{$mode}{streamer} = 'iphone'; $data{$mode}{ext} = 'mov'; @@ -5745,12 +5843,12 @@ 'bbc_radio_essex' => 'BBC Essex', 'bbc_london' => 'BBC London', 'bbc_radio_kent' => 'BBC Kent', - 'bbc_southern_counties_radio' => 'BBC Southern Counties', + 'bbc_radio_surrey' => 'BBC Surrey', + 'bbc_radio_sussex' => 'BBC Sussex', 'bbc_radio_oxford' => 'BBC Oxford', 'bbc_radio_berkshire' => 'BBC Berkshire', 'bbc_radio_solent' => 'BBC Solent', 'bbc_radio_gloucestershire' => 'BBC Gloucestershire', - 'bbc_radio_swindon' => 'BBC Swindon', 'bbc_radio_wiltshire' => 'BBC Wiltshire', 'bbc_radio_bristol' => 'BBC Bristol', 'bbc_radio_somerset_sound' => 'BBC Somerset', @@ -5767,7 +5865,7 @@ # Class cmdline Options sub opt_format { return { - radiomode => [ 1, "radiomode|amode=s", 'Recording', '--radiomode ,,...', "Radio Recording mode(s): iphone,flashaac,flashaudio,realaudio,wma (default: iphone,flashaac,flashaudio,realaudio)"], + radiomode => [ 1, "radiomode|amode=s", 'Recording', '--radiomode ,,...', "Radio Recording mode(s): iphone,flashaac,flashaachigh,flashaacstd,flashaaclow,flashaudio,realaudio,wma (default: iphone,flashaachigh,flashaacstd,flashaudio,realaudio,flashaaclow)"], bandwidth => [ 1, "bandwidth=n", 'Recording', '--bandwidth', "In radio realaudio mode specify the link bandwidth in bps for rtsp streaming (default 512000)"], lame => [ 0, "lame=s", 'External Program', '--lame ', "Location of lame binary"], outputradio => [ 1, "outputradio=s", 'Output', '--outputradio ', "Output directory for radio recordings"], @@ -5816,16 +5914,18 @@ main::logger "WARNING: Not using flash modes since flvstreamer/rtmpdump is not found\n" if $opt->{verbose}; $mlist = 'iphone,realaudio,wma'; } else { - $mlist = 'iphone,flashaudio,flashaac,realaudio,wma'; + $mlist = 'iphone,flashaachigh,flashaacstd,flashaudio,realaudio,flashaaclow,wma'; } } # Deal with BBC Radio fallback modes and expansions # Valid modes are iphone,rtmp,flashaac,flashaudio,realaudio,wmv # 'rtmp' or 'flash' => 'flashaudio,flashaac' - # flashaac => flashaac1,flashaac2 - $mlist = main::expand_list($mlist, 'best', 'flashaac,iphone,flashaudio,realaudio,wma'); + # flashaac => flashaachigh,flashaacstd,flashaaclow + # flashaachigh => flashaachigh1,flashaachigh2 + $mlist = main::expand_list($mlist, 'best', 'flashaachigh,flashaacstd,iphone,flashaudio,realaudio,flashaaclow,wma'); $mlist = main::expand_list($mlist, 'flash', 'flashaudio,flashaac'); $mlist = main::expand_list($mlist, 'rtmp', 'flashaudio,flashaac'); + $mlist = main::expand_list($mlist, 'flashaac', 'flashaachigh,flashaacstd,flashaaclow'); return $mlist; } @@ -6134,6 +6234,7 @@ 'bbc_radio_cambridge' => 'BBC Cambridgeshire', 'bbc_radio_norfolk' => 'BBC Norfolk', 'bbc_radio_suffolk' => 'BBC Suffolk', + 'bbc_radio_sussex' => 'BBC Sussex', 'bbc_radio_essex' => 'BBC Essex', 'bbc_london' => 'BBC London', 'bbc_radio_kent' => 'BBC Kent', @@ -6191,15 +6292,18 @@ main::logger "WARNING: Not using flash modes since flvstreamer/rtmpdump is not found\n" if $opt->{verbose}; $mlist = 'realaudio,wma'; } else { - $mlist = 'flashaac,realaudio,wma'; + $mlist = 'flashaachigh,flashaacstd,realaudio,flashaaclow,wma'; } } # Deal with BBC Radio fallback modes and expansions - # Valid modes are iphone,rtmp,flashaac,flashaudio,realaudio,wmv - # 'rtmp' or 'flash' => 'flashaudio,flashaac' - $mlist = main::expand_list($mlist, 'best', 'flashaac,realaudio,wma'); + # Valid modes are rtmp,flashaac,realaudio,wmv + # 'rtmp' or 'flash' => 'flashaac' + # flashaac => flashaachigh,flashaacstd,flashaaclow + # flashaachigh => flashaachigh1,flashaachigh2 + $mlist = main::expand_list($mlist, 'best', 'flashaachigh,flashaacstd,realaudio,flashaaclow,wma'); $mlist = main::expand_list($mlist, 'flash', 'flashaac'); $mlist = main::expand_list($mlist, 'rtmp', 'flashaac'); + $mlist = main::expand_list($mlist, 'flashaac', 'flashaachigh,flashaacstd,flashaaclow'); return $mlist; } @@ -6287,46 +6391,39 @@ my $ua = shift; my $pid = shift; - # Create url with appended 12 digit random number /mediaselector/3/auth/iplayer_streaming_http_mp4/b0067vmx?r=101477348958 - # http://www.bbc.co.uk/mediaselector/3/auth/iplayer_streaming_http_mp4 - my $iphone_download_prefix = 'http://www.bbc.co.uk/mediaselector/3/auth/iplayer_streaming_http_mp4'; - my $url_1 = ${iphone_download_prefix}.'/'.${pid}.'?r='.(sprintf "%012.0f", 999999999999*rand(0) ); - main::logger "INFO: iphone stream URL = $url_1\n" if $opt->{verbose}; - - # This doesn't work through url-prepend proxies - ## Use url prepend if required - #if ( $opt->{proxy} =~ /^prepend:/ ) { - # $url_1 = $opt->{proxy}.$url_1; - # $url_1 =~ s/^prepend://g; - #} - - # Stage 2: e.g. "Location: http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/121285241910131406.mp4?token=iVXexp1yQt4jalB2Hkl%2BMqI25nz2WKiSsqD7LzRmowrwXGe%2Bq94k8KPsm7pI8kDkLslodvHySUyU%0ApM76%2BxEGtoQTF20ZdFjuqo1%2B3b7Qmb2StOGniozptrHEVQl%2FYebFKVNINg%3D%3D%0A" - #main::logger "\rGetting iplayer iphone URL " if (! $opt->{verbose}) && ! $opt->{streaminfo}; + # Look for href="http://download.iplayer.bbc.co.uk/iplayer_streaming_http_mp4/5439950172312621205.mp4?token=iVX.lots.of.text.x9Z%2F2GNBdQKl0%3D%0A&pid=b00qhs36" + my $url; + my $iphone_download_prefix = 'http://www.bbc.co.uk/mobile/iplayer/episode'; + my $url_0 = ${iphone_download_prefix}.'/'.${pid}; + main::logger "INFO: iphone stream URL = $url_0\n" if $opt->{verbose}; + my $safari_ua = main::create_ua( 'safari' ); + my $html = main::request_url_retry( $safari_ua, $url_0, 3, undef, undef, 1 ); + $html =~ s/\n/ /g; + # Check for guidance warning + my $guidance_post; + $guidance_post = $1 if $html =~ m{(isOver\d+)}; + if ( $guidance_post ) { my $h = new HTTP::Headers( 'User-Agent' => $user_agent{coremedia}, 'Accept' => '*/*', - 'Range' => 'bytes=0-1', + 'Accept-Language' => 'en', + 'Connection' => 'keep-alive', + 'Pragma' => 'no-cache', ); - my $req = HTTP::Request->new ('GET', $url_1, $h); - # send request (use simple_request here because that will not allow redirects) - my $res = $ua->simple_request($req); - # Get resulting Location header (i.e. redirect URL) - my $url = $res->header("location"); - if ( ! $res->is_redirect ) { - main::logger "ERROR: Failed to get iphone redirect from iplayer site\n\n"; - return ''; - } - # Extract redirection Location URL - $url =~ s/^Location: (.*)$/$1/g; - # If we get a Redirection containing statuscode=404 then this prog is not yet ready - if ( $url =~ /statuscode=404/ ) { - main::logger "\rERROR: iphone stream is not yet ready\n" if $opt->{verbose}; - return ''; - } elsif ( $url =~ /statuscode=403/ ) { - main::logger "\rERROR: iphone stream is not permitted for recording\n" if $opt->{verbose}; - return ''; + main::logger "INFO: Guidance '$guidance_post' Warning Detected\n" if $opt->{verbose}; + # Now post this var and get html again + my $req = HTTP::Request->new('POST', $url_0, $h); + $req->content_type('application/x-www-form-urlencoded'); + $req->content('form=guidanceprompt&'.$guidance_post.'=1'); + my $res = $ua->request($req); + $html = $res->as_string; } + $url = decode_entities($1) if $html =~ m{href="(http.//download\.iplayer\.bbc\.co\.uk/iplayer_streaming_http_mp4.+?)"}; + main::logger "DEBUG: Got iphone mediaselector URL: $url\n" if $opt->{verbose}; + if ( ! $url ) { + main::logger "ERROR: Failed to get iphone URL from iplayer site\n\n"; + } return $url; } @@ -7262,24 +7359,8 @@ my $file_part_prefix = "$prog->{dir}/$prog->{fileprefix}_part"; for ( my $count = 0; $count <= $#url_list; $count++ ) { - # Resolve the MMS url if it is an http ref - if ( $url_list[$count] =~ /^http/ ) { - my $url = main::request_url_retry($ua, $url_list[$count], 2, '', ''); - chomp($url); - $url =~ s/[\s\n]//g; - # HREF="mms://a1899.v394403.c39440.g.vm.akamaistream.net/7/1899/39440/1/bbcworldservice.download.akamai.com/39440//worldservice/css/nb/410060838.wma" - # HREF = "http://www.bbc.co.uk/worldservice/meta/tx/nb/live/www15.asx" - $url =~ s/^.*href\s*=\s*\"(.+?)\".*$/$1/gi; - # Yet another recursion if required! - if ( $url =~ /^http/ ) { - # "http://www.bbc.co.uk/worldservice/meta/tx/nb/live/www15.asx" - $url = main::request_url_retry($ua, $url, 2, '', ''); - chomp($url); - $url =~ s/[\s\n]//g; - $url =~ s/^.*href\s*=\s*\"(.+?)\".*$/$1/gi; - } - $url_list[$count] = $url; - } + # Parse/recurse playlist if required to get mms url + $url_list[$count] = main::get_playlist_url( $ua, $url_list[$count], 'mms' ); # Create temp recording filename $file_tmp = sprintf( "%s%02d.".$prog->{ext}, $file_part_prefix, $count+1);