diff options
author | Paul Wise <pabs3@bonedaddy.net> | 2013-01-26 16:29:23 +0800 |
---|---|---|
committer | Paul Wise <pabs3@bonedaddy.net> | 2013-01-26 16:30:42 +0800 |
commit | e2cffef5a2c018611ee18765f32c9e29e3033854 (patch) | |
tree | 639cf165e9d3662d19174aa0820b72eaaa7a3a1b | |
parent | 2dd911cee09c1778dce09dd2557c737118b865ce (diff) | |
parent | e3f319022b0b596e63c4778bb6cb79cf72ba7a0e (diff) | |
download | get-flash-videos-e2cffef5a2c018611ee18765f32c9e29e3033854.tar.gz |
Merge branch 'master' of git://github.com/monsieurvideo/get-flash-videos
-rw-r--r-- | lib/FlashVideo/Site/Daum.pm | 22 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Kanal5play.pm | 39 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Liveleak.pm | 45 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Motherless.pm | 22 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Putlocker.pm | 69 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Redtube.pm | 2 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Sockshare.pm | 7 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Tv3.pm | 89 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Tv4play.pm | 85 | ||||
-rw-r--r-- | lib/FlashVideo/Site/Tvnz.pm | 268 |
10 files changed, 528 insertions, 120 deletions
diff --git a/lib/FlashVideo/Site/Daum.pm b/lib/FlashVideo/Site/Daum.pm index 7b10c6e..4a572be 100644 --- a/lib/FlashVideo/Site/Daum.pm +++ b/lib/FlashVideo/Site/Daum.pm @@ -50,17 +50,22 @@ sub get_video_id { die "Cannot fetch '$url'\n" if !$browser->success(); } + if ($browser->response->is_redirect()) { + my $url = $browser->response->header('Location'); + $browser->get($url); + die "Cannot fetch '$url'\n" if !$browser->success(); + } + my $document = $browser->content(); - # "http://flvs.daum.net/flvPlayer.swf?vid=FlVGvam5dPM$" - my $flv_player_url = quotemeta 'http://flvs.daum.net/flvPlayer.swf'; - my $video_id_pattern_1 = qr{['"] $flv_player_url [?] vid = ([^'"&]+)}xmsi; + # VodPlayer.swf?vid=3i5f_JquGsk$ + my $video_id_pattern_1 = qr{VodPlayer[.]swf [?] vid = (.+?) ["'&]}xmsi; my $func_name; # Story.UI.PlayerManager.createViewer('2oHFG_aR9uA$'); $func_name = quotemeta 'Story.UI.PlayerManager.createViewer'; - my $video_id_pattern_2 = qr{$func_name [(] ' (.+?) ' [)]}xms; + my $video_id_pattern_2 = qr{$func_name [(] ' (.+?) '}xms; # daum.Music.VideoPlayer.add("body_mv_player", "_nACjJ65nKg$", $func_name = quotemeta 'daum.Music.VideoPlayer.add'; @@ -69,17 +74,12 @@ sub get_video_id { # controller/video/viewer/VideoView.html?vid=90-m2tl87zM$&play_loc=... my $video_id_pattern_4 - = qr{/video/viewer/VideoView.html [?] vid = (.+?) &}xms; - - # DaumVodPlayer.swf?vid=vd247EUCULRUVVUQSVytEDS&... - my $video_id_pattern_5 - = qr{DaumVodPlayer[.]swf [?] vid = (.+?) &}xmsi; + = qr{/video/viewer/VideoView.html [?] vid = (.+?) &}xmsi; if ( $document !~ $video_id_pattern_1 && $document !~ $video_id_pattern_2 && $document !~ $video_id_pattern_3 - && $document !~ $video_id_pattern_4 - && $document !~ $video_id_pattern_5 ) + && $document !~ $video_id_pattern_4 ) { die "Cannot find video ID.\n"; } diff --git a/lib/FlashVideo/Site/Kanal5play.pm b/lib/FlashVideo/Site/Kanal5play.pm index b750efe..3f9f88c 100644 --- a/lib/FlashVideo/Site/Kanal5play.pm +++ b/lib/FlashVideo/Site/Kanal5play.pm @@ -8,21 +8,22 @@ use FlashVideo::JSON; my $bitrates = { - "low" => 250000, - "medium" => 450000, - "high" => 900000 }; + low => 250000, + medium => 450000, + high => 900000 +}; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; - if(!($browser->uri->as_string =~ m/video\/([0-9]*)/)){ - die "No video id found in url"; + if (!($browser->uri->as_string =~ m/video\/([0-9]*)/)) { + die "No video id found in url"; } my ($video_id) = $1; my $info_url = "http://www.kanal5play.se/api/getVideo?format=FLASH&videoId=$video_id"; $browser->get($info_url); - - if (!$browser->success){ - die "Couldn't download $info_url: " . $browser->response->status_line; + + if (!$browser->success) { + die "Couldn't download $info_url: " . $browser->response->status_line; } my $jsonstr = $browser->content; @@ -35,19 +36,19 @@ sub find_video { my ($rtmp) = "rtmp://fl1.c00608.cdn.qbrick.com:1935/00608"; my ($playpath) = $json->{streams}[0]->{source}; - my $i; - foreach $i (keys %{ $json->{streams} }) { - my ($rate) = int($json->{streams}[$i]->{bitrate}); - if($bitrates->{$prefs->{quality}} == $rate){ - $playpath = $json->{streams}[$i]->{source}; - } + foreach my $stream ($json->{streams}[0]) { + my ($rate) = int($stream->{bitrate}); + if ($bitrates->{$prefs->{quality}} eq $rate) { + $playpath = $stream->{source}; + last; + } } + return { - flv => title_to_filename($filename, "flv"), - rtmp => $rtmp, - playpath => $playpath, - swfVfy => "http://www.kanal5play.se/flash/StandardPlayer.swf" + flv => title_to_filename($filename, "flv"), + rtmp => $rtmp, + playpath => $playpath, + swfVfy => "http://www.kanal5play.se/flash/StandardPlayer.swf" }; - } 1; diff --git a/lib/FlashVideo/Site/Liveleak.pm b/lib/FlashVideo/Site/Liveleak.pm index 07c48e2..6465c21 100644 --- a/lib/FlashVideo/Site/Liveleak.pm +++ b/lib/FlashVideo/Site/Liveleak.pm @@ -7,47 +7,16 @@ use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; - # Get file embed tag - my $file_embed_tag; - if ($browser->content =~ /file_embed_tag(?:%3D|=)(\w+)\W/) { - $file_embed_tag = $1; - } - else { - die "Unable to get file_embed_tag"; - } - - $browser->get("http://www.liveleak.com/playlist_new.php?file_embed_tag=$file_embed_tag"); - - if (!$browser->success) { - die "Couldn't download LiveLeak playlist: " . $browser->response->status_line(); - } - - # Response is XML but using XML::Simple is overkill. - my $video_url; - if ($browser->content =~ m'<location>(http://.*?)</location>') { - $video_url = $1; - } - else { - die "Unable to extract LiveLeak video URL"; - } - - # URL might be a redirect - if (my $redirected_url = $browser->head($video_url)->header('Location')) { - $video_url = $redirected_url; + my $url; + if ($browser->content =~ /file: "([^"]+)"/) { + $url = $1; + } else { + die "Unable to extract video url"; } - $browser->back(); - - # Figure out title - my $title; - if ($browser->content =~ m'<h4 id="s_hd">(.*?)</h4>') { - $title = $1; - } - else { - $title = extract_title($browser); - } + (my $title = extract_title($browser)) =~ s/LiveLeak\.com - //; - return $video_url, title_to_filename($title); + return $url, title_to_filename($title, "mp4"); } 1; diff --git a/lib/FlashVideo/Site/Motherless.pm b/lib/FlashVideo/Site/Motherless.pm new file mode 100644 index 0000000..c576e45 --- /dev/null +++ b/lib/FlashVideo/Site/Motherless.pm @@ -0,0 +1,22 @@ +# Part of get-flash-videos. See get_flash_videos for copyright. +package FlashVideo::Site::Motherless; + +use strict; +use FlashVideo::Utils; + +sub find_video { + my ($self, $browser, $embed_url) = @_; + + my $url; + if ($browser->content =~ /file: '([^']+)'/) { + $url = $1."?start=0"; + } else { + die "Unable to extract video url"; + } + + (my $title) = extract_title($browser) =~ /:\s+(.*)/; + + return $url, title_to_filename($title, "flv"); +} + +1; diff --git a/lib/FlashVideo/Site/Putlocker.pm b/lib/FlashVideo/Site/Putlocker.pm index 476ca17..caf75b3 100644 --- a/lib/FlashVideo/Site/Putlocker.pm +++ b/lib/FlashVideo/Site/Putlocker.pm @@ -4,12 +4,28 @@ package FlashVideo::Site::Putlocker; use strict; use FlashVideo::Utils; use HTML::Tree; +use HTML::Entities qw(decode_entities); +use URI; sub find_video { - my ($self, $browser, $embed_url) = @_; + my ($self, $browser, $embed_url, $prefs) = @_; + + # change from /embed/video_id to /file/video_id + if($embed_url =~ s,/embed/,/file/,) { + info "Retrieving file page: $embed_url"; + $browser->get($embed_url); + } + + die 'Could not retrieve video' unless ($browser->success); + + + my ($id) = ($embed_url =~ m,file/([^/]*),); my ($filename) = title_to_filename(extract_title($browser)); - $filename =~ s/[\s\|_]*PutLocker[\s_]*//; + my $host = URI->new($embed_url)->host; # www.putlocker.com or www.sockshare.com + my $sitename = _host_to_sitename($host); + $filename =~ s/[\s\|_]*$sitename[\s_]*//; + my $url; # the final URL #get the "hash" value from the HTML my $tree = HTML::Tree->new(); @@ -18,7 +34,7 @@ sub find_video { info 'Found hash: ' . $hash; #Construct a POST request to get the tell the server to serve real page content - info "Confirming request to PutLocker."; + info "Confirming request to $sitename."; $browser->add_header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $browser->add_header( 'Accept-Encoding' => 'text/html' ); @@ -29,29 +45,60 @@ sub find_video { 'hash'=>$hash ]); - #we will get a redirect, this is the cue to re-request the same page - die if not - die 'Response code was ' . $response->code . '. Should be 302.' unless ($response->code == '302'); + # request is successful - die if not + die 'Request not successful' unless ($browser->success); - info "Re-fetching page, which will now have the video embedded."; - $browser->delete_header( 'Content-Type'); - my $page_html = $browser->get($embed_url)->content; + my $page_html = $response->content; #the stream ID is now embedded in the page. - my ($streamID) = ($page_html =~ /get_file\.php\?stream=([A-Za-z0-9]+)/); + my ($streamID) = ($page_html =~ /get_file\.php\?stream=([A-Za-z0-9=]+)/); info "Found the stream ID: " . $streamID; #request the url of the actual file - my $uri = URI->new( "http://www.putlocker.com/get_file.php" ); + my $uri = URI->new( "http://$host/get_file.php" ); $uri->query_form((stream=>$streamID)); #parse the url and title out of the response - much easier to regex it out, as the XML has dodgy &'s. + $browser->allow_redirects; my $contents = $browser->get($uri)->content; - my ($url) = ($contents =~ /url="(.*?)"/); + # this is necessary to download both high quality and streaming version + die 'Unable to download video information' unless ($browser->success); + my ($stream_url) = ($contents =~ /url="(.*?)"/); + $stream_url = decode_entities($stream_url); + if($stream_url =~ /expired_link/) { + # if link is unavailable + if( $page_html =~ m,"/(get_file\.php\?id=[^"]*)", ) { + # download original file if link available + my $download_page = $1; + $url = URI->new( "http://$host/$1" ); + # this URL should be equivalent to what is returned by _get_high_quality() + } + } elsif($prefs->{quality} eq 'high' and $host eq 'www.putlocker.com') { + # only works on PutLocker + $url = _get_high_quality($host, $id, $streamID); + } else { + # get streaming version + $url = $stream_url; + } info "Got the video URL: " . $url; return $url, $filename; } +sub _get_high_quality { + my ( $host, $id, $key ) = @_; + return "http://$host/get_file.php?id=$id&key=$key&original=1"; +} + +sub _host_to_sitename { + my ($host) = @_; + if($host eq 'www.putlocker.com') { + return "PutLocker"; + } elsif($host eq 'www.sockshare.com') { + return "SockShare"; + } +} + 1; diff --git a/lib/FlashVideo/Site/Redtube.pm b/lib/FlashVideo/Site/Redtube.pm index 1b54986..a748974 100644 --- a/lib/FlashVideo/Site/Redtube.pm +++ b/lib/FlashVideo/Site/Redtube.pm @@ -8,7 +8,7 @@ use URI::Escape; sub find_video { my($self, $browser, $embed_url) = @_; - my($title) = $browser->content =~ /<h1 class="videoTitle">([^<]+)</; + my($title) = extract_title($browser) =~ /(.*) \|/; my($url) = $browser->content =~ /mp4_url=([^&"]+)/; $url = uri_unescape($url); diff --git a/lib/FlashVideo/Site/Sockshare.pm b/lib/FlashVideo/Site/Sockshare.pm new file mode 100644 index 0000000..61a79c8 --- /dev/null +++ b/lib/FlashVideo/Site/Sockshare.pm @@ -0,0 +1,7 @@ +# Part of get-flash-videos. See get_flash_videos for copyright. +package FlashVideo::Site::Sockshare; + +# SockShare uses the same software as PutLocker +use base 'FlashVideo::Site::Putlocker'; + +1; diff --git a/lib/FlashVideo/Site/Tv3.pm b/lib/FlashVideo/Site/Tv3.pm new file mode 100644 index 0000000..35e8ae6 --- /dev/null +++ b/lib/FlashVideo/Site/Tv3.pm @@ -0,0 +1,89 @@ +# Part of get-flash-videos. See get_flash_videos for copyright. +package FlashVideo::Site::Tv3; + +use strict; +use FlashVideo::Utils; + +my $encode_rates = { + "low" => { + speed => 300, + flag => undef, + downgrade => undef + }, + "medium" => { + speed => 700, + flag => "sevenHundred", + downgrade => "low" + }, + "high" => { + speed => 1500, + flag => "fifteenHundred", + downgrade => "medium" + } + }; + +sub find_video { + my ($self, $browser, $embed_url, $prefs) = @_; + + if ($browser->content !~ m/var\s+video\s*=\"\*([^"]+)\"\s*;/s) { + die "Unable to extract file"; + } + my $replace = $1; + $replace =~ s/\*/\//sg; + + my $quality = $prefs->{quality}; + my $encodeRate = $encode_rates->{$quality}; + if (!defined($encodeRate)) { + foreach my $rate (values(%$encode_rates)) { + if ($rate->{speed} eq $quality) { + $encodeRate = $rate; + last; + } + } + } + + my $content = undef; + while (defined($encodeRate)) { + debug "Trying to use encoding rate " . $encodeRate->{speed}; + + my $flag = $encodeRate->{flag}; + if (defined($flag)) { + $content = $browser->content if !defined($content); + if ($content !~ m/flashvars\.$flag\s*=\s*"yes"/s) { + my $downgrade = $encodeRate->{downgrade}; + if (!defined($downgrade)) { + $encodeRate = undef; + last; + } + + debug "Rate " . $encodeRate->{speed} . + " isn't available, dowgrading to " . $downgrade; + + $encodeRate = $encode_rates->{$downgrade}; + next; + } + } + last; + } + + if (!defined($encodeRate)) { + die "Couldn't match the requested quality"; + } + + my $conSpeed = $encodeRate->{speed}; + + my $rtmp = "rtmpe://nzcontent.mediaworks.co.nz:80/tv3/_definst_/mp4:" . + $replace . "_" . $conSpeed . "K"; + + # Default title is perfect. + my $filename = title_to_filename(extract_title($browser)); + $filename ||= get_video_filename(); + + return { + rtmp => $rtmp, + swfVfy => "http://static.mediaworks.co.nz/video/6.9/videoPlayer6.9.83.swf?rnd=1932311212", + flv => $filename + }; +} + +1; diff --git a/lib/FlashVideo/Site/Tv4play.pm b/lib/FlashVideo/Site/Tv4play.pm index d175a62..f45458a 100644 --- a/lib/FlashVideo/Site/Tv4play.pm +++ b/lib/FlashVideo/Site/Tv4play.pm @@ -2,59 +2,64 @@ package FlashVideo::Site::Tv4play; use strict; use FlashVideo::Utils; +use List::Util qw(reduce); sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; - my $vid = ($embed_url =~ /videoid=([0-9]*)/)[0]; - my $smi_url = "http://premium.tv4play.se/api/web/asset/$vid/play"; - + my $video_id = ($embed_url =~ /video_id=([0-9]*)/)[0]; + my $smi_url = "http://premium.tv4play.se/api/web/asset/$video_id/play"; my $title = ($browser->content =~ /property="og:title" content="(.*?)"/)[0]; my $flv_filename = title_to_filename($title, "flv"); $browser->get($smi_url); my $content = from_xml($browser); my $i = 0; - my @dump; + my @streams; my $subtitle_url; - for ($i = 0; $i < 5; $i++){ - my $format = $content->{items}->{item}[$i]->{mediaFormat}; - my $bitrate = $content->{items}->{item}[$i]->{bitrate}; - my $rtmp = $content->{items}->{item}[$i]->{base}; - my $mp4 = $content->{items}->{item}[$i]->{url}; - @dump[$i] = { 'rtmp' => $rtmp, - 'bitrate' => $bitrate, - 'mp4' => $mp4, - 'format' => $format - }; - } - foreach (@dump) { - if($_->{format} eq 'smi'){ $subtitle_url = $_->{mp4};} + + foreach my $item (@{ $content->{items}->{item} || [] }) { + push @streams, { + rtmp => $item->{base}, + bitrate => $item->{bitrate}, + mp4 => $item->{url}, + format => $item->{mediaFormat} + }; + } + + foreach (@streams) { + if ($_->{format} eq 'smi') { + $subtitle_url = $_->{mp4}; + last; + } } - debug "Subtitle_url: $subtitle_url"; - # Subtitle not supported - # if ($prefs->{subtitles} == 1) { - # if (not $subtitle_url eq '') { - # info "Found subtitles: $subtitle_url"; - # $browser->get("$subtitle_url"); - # my $srt_filename = title_to_filename($title, "srt"); - # if(!eval { require XML::Simple && XML::Simple::XMLin("<foo/>") }) { - # die "Must have XML::Simple to download " . caller =~ /::([^:])+$/ . " videos\n"; - # } - # convert_sami_subtitles_to_srt($browser->content, $srt_filename); - # } else { - # info "No subtitles found!"; - # } - # } - - - + + if ($prefs->{subtitles} == 1) { + if (not $subtitle_url eq '') { + $browser->get("$subtitle_url"); + if (!$browser->success) { + info "Couldn't download subtitles: " . $browser->status_line; + } else { + my $srt_filename = title_to_filename($title, "srt"); + info "Saving subtitles as " . $srt_filename; + open my $srt_fh, '>', $srt_filename + or die "Can't open subtitles file $srt_filename: $!"; + binmode $srt_fh, ':utf8'; + print $srt_fh $browser->content; + close $srt_fh; + } + } else { + info "No subtitles found"; + } + } + + my $max_stream = reduce {$a->{bitrate} > $b->{bitrate} ? $a : $b} @streams; + return { - rtmp => $dump[0]->{rtmp}, - swfVfy => "http://www.tv4play.se/flash/tv4playflashlets.swf", - playpath => $dump[0]->{mp4}, - flv => $flv_filename + rtmp => $max_stream->{rtmp}, + swfVfy => "http://www.tv4play.se/flash/tv4playflashlets.swf", + playpath => $max_stream->{mp4}, + flv => $flv_filename }; - } 1; diff --git a/lib/FlashVideo/Site/Tvnz.pm b/lib/FlashVideo/Site/Tvnz.pm new file mode 100644 index 0000000..52f900e --- /dev/null +++ b/lib/FlashVideo/Site/Tvnz.pm @@ -0,0 +1,268 @@ +# Part of get-flash-videos. See get_flash_videos for copyright. +package FlashVideo::Site::Tvnz; + +use strict; + +use FlashVideo::Utils; +use URI; + +my $encode_rates = { + "low" => 250000, + "medium" => 700000, + "high" => 1500000 + }; + +sub find_video { + my ($self, $browser, $embed_url, $prefs) = @_; + + my $videoPlayer = ($browser->content =~ m/\<param\s+value=\"ref:(\d+)\"\s+name=\"\@videoPlayer\"\s*\/\>/s)[0]; + my $player_id = ($browser->content =~ /\<param value=\"(\d+)\" name=\"playerID\" \/\>/i)[0]; + + debug "Extracted playerId: $player_id, videoPlayer: $videoPlayer" + if $player_id or $videoPlayer; + + my $metadata = { + videoplayer => $videoPlayer + }; + + # The "session ID" appears to be constant. + my $sessionId = "f86d6617a68b38ee0f400e1f4dc603d6e3b4e4ed"; + $metadata->{sessionId} = $sessionId; + + debug "Extracted playerId: $player_id, sessionId: $metadata->{sessionId} videoplayer: $videoPlayer" + if $player_id or $videoPlayer; + + die "Unable to extract Brightcove IDs from page" + unless $player_id && $videoPlayer && $sessionId; + + return $self->amfgateway($browser, $player_id, $metadata, $prefs); +} + +sub amfrequest($$$$) { + my($self, $base_url, $player_id, $metadata) = @_; + + my $has_amf_packet = eval { require Data::AMF::Packet }; + if (!$has_amf_packet) { + die "Must have Data::AMF::Packet installed to download Brightcove videos"; + } + +# AMF3 incompatable between Data::AMF and Brightcove +# results in Brightcove rejecting message +# create message without deserialize/serialize. + + my $amf0_formatter = Data::AMF::Formatter->new(version =>0); + my $amf3_formatter = Data::AMF::Formatter->new(version =>3); + + my @amf_pkt = (); + + push(@amf_pkt, pack("H*", "0003000000010046636f6d2e627269676874636f76652e657870657269656e63652e457870657269656e636552756e74696d654661636164652e67657444617461466f72457870657269656e636500022f310000")); + + push(@amf_pkt, ""); + my $lengthIndex = $#amf_pkt; + + push(@amf_pkt, pack("H*", "0a00000002")); + + push(@amf_pkt, $amf0_formatter->format($metadata->{sessionId})); + + push(@amf_pkt, pack("H*", "110a6363636f6d2e627269676874636f76652e657870657269656e63652e566965776572457870657269656e63655265717565737413706c617965724b657921636f6e74656e744f76657272696465731154544c546f6b656e1964656c6976657279547970650755524c19657870657269656e6365496406010903010a810353636f6d2e627269676874636f76652e657870657269656e63652e436f6e74656e744f76657272696465156665617475726564496413636f6e74656e7449641b6665617475726564526566496415636f6e74656e7449647319636f6e74656e74526566496417636f6e74656e74547970651b636f6e74656e745265664964730d746172676574057fffffffe0000000057fffffffe00000000101")); + + sub amf3_string($$) { + my $self = $_[0]->new; + $self->io->write_u8($self->STRING_MARKER); + $self->write_string($_[1]); + return $self->io->data; + } + + push(@amf_pkt, amf3_string($amf3_formatter, $metadata->{videoplayer})); + + push(@amf_pkt, + pack("H*","0400010617766964656f506c617965720601057fffffffe0000000")); + + push(@amf_pkt, amf3_string($amf3_formatter, $base_url)); + + push(@amf_pkt, $amf3_formatter->format($player_id)); + + $amf_pkt[$lengthIndex] = pack('n', length( + join('',@amf_pkt[$lengthIndex .. $#amf_pkt]))); + + return join('', @amf_pkt); +} + +sub amfresponse($$$$$$) { + my ($self, $page_url, $player_id, $metadata, $prefs, $content) = @_; + + my $packet = Data::AMF::Packet->deserialize($content); + + if ($self->debug) { + require Data::Dumper; + debug Data::Dumper::Dumper($packet); + } + + #require Data::Dumper; + #print Data::Dumper::Dumper($packet); + + # renditions Array contains the rtmpe URL. + my $renditions = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions}; + if (ref($renditions) ne 'ARRAY') { + die "Unexpected data from AMF gateway"; + } + + # other information returned in message. + my $detail = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}; + + my $mediaId = $detail->{mediaId}; + + my $mediaDTO = $detail->{mediaDTO}; + + my $publisherId = $mediaDTO->{publisherId}; + die "Publisher ID not determined" if !defined($publisherId); + + my $customFields = $mediaDTO->{customFields}; + + my $programme = $customFields->{programme}; + if (!defined($programme)) { + # Fall back onto the display name if the video doesn't have + # programme/series/episode details (For example, a clip). + $programme = $mediaDTO->{displayName}; + } + die "Programme name not determined" if !defined($programme); + + my $seriesnumber = $customFields->{seriesnumber}; + my $episodenumber = $customFields->{episodenumber}; + + if (defined($seriesnumber) || defined($episodenumber)) { + $programme .= "_"; + $programme .= sprintf("S\%02d", $seriesnumber) if defined($seriesnumber); + $programme .= sprintf("E\%02d", $episodenumber) if defined($episodenumber); + } + + my $episodename = $customFields->{episodename}; + $programme .= "_" . $episodename if defined($episodename); + + my $encode_rate = $encode_rates->{$prefs->{quality}}; + if (!defined($encode_rate)) { + $encode_rate = $prefs->{quality}; + } + + my $bestMatch = undef; + foreach my $rendition (@{$renditions}) { + my $defaultURL = $rendition->{defaultURL}; + next if !defined($defaultURL); + + my $rate = $rendition->{encodingRate}; + + # The service returns encoding rates that are close to, but not + # exactly, the published rates of 250k, 700k, 1500k etc. For + # example, 1499998 instead 1500k. Round the rate to the nearest + # 1k. + { + use integer; + $rate = (($rate + 500) / 1000) * 1000; + } + + #print "Saw: " . $rendition->{defaultURL} . " @ " . $rate . "\n"; + + # If the selected rate is lower than this option's rate, discard + # this option. + next if $encode_rate < $rate; + + # If we have already found an option that is lower than the + # selected encoding rate, but higher than this rate, then discard + # this option. + next if (defined($bestMatch) && $bestMatch->{rate} > $rate); + + $bestMatch = { + rate => $rate, + rendition => $rendition + } + } + + return undef if !defined($bestMatch); + + my $d = $bestMatch->{rendition}; + my $rate = $bestMatch->{rate}; + + my $defaultURL = $d->{defaultURL}; + + if ($defaultURL !~ m!^(rtmpe?)://([^/]+)/([^&]+)/&(.*)$!s) { + die "Failed to parse URL: " . $defaultURL; + } + my $protocol = $1; + my $host = $2; + my $rtmpApp = $3; + my $file = $4; + + my $filenamePrefix = $programme . "_" . $rate; + + my $filename = title_to_filename($filenamePrefix); + $filename ||= get_video_filename(); + + my $app = $rtmpApp . "?videoId=" . $mediaId . + "&lineUpId=&pubId=" . $publisherId . + "&playerId=" . $player_id . "&affiliateId="; + + my $port = 1935; + + # + # Content reported with the "rtmp" protocol are actually delivered + # on port 80 via "rtmpt". + # + if ($protocol eq "rtmp") { + $port = 80; + $protocol = "rtmpt"; + } + + my $tcUrl = $protocol . "://" . $host . ":" . $port . "/" . $rtmpApp; + my $rtmpUrl = $protocol . "://" . $host . "/" . $rtmpApp . "/&" . $file; + + my $args = { + app => $app, + pageUrl => $page_url, + swfVfy => "http://admin.brightcove.com/viewer/us1.24.04.08.2011-01-14072625/connection/ExternalConnection_2.swf", + tcUrl => $tcUrl, + rtmp => $rtmpUrl, + playpath => $file, + flv => $filename, + }; + + return [ $args ]; +} + +sub amfgateway { + my($self, $browser, $player_id, $metadata, $prefs) = @_; + + my $page_url = $browser->uri; + my $base_url = "" . $page_url; + + my $data = $self->amfrequest($base_url, $player_id, $metadata); + + $browser->post( + "http://c.brightcove.com/services/messagebroker/amf?playerid=$player_id", + Content_Type => "application/x-amf", + Content => $data + ); + + die "Failed to post to Brightcove AMF gateway" + unless $browser->response->is_success; + + my $content = $browser->content; + + #open(F, "> response.data");print F $content;close(F); + + my $commands = $self->amfresponse($page_url, $player_id, $metadata, + $prefs, $content); + + if ($#$commands > 0) { + return $commands; + } else { + return ${$commands}[0]; + } +} + +sub can_handle { + my($self, $browser, $url) = @_; + + return $url && URI->new($url)->host =~ m/(?:^|\.)tvnz\.co\.nz$/; +} + +1; |