aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Wise <pabs3@bonedaddy.net>2013-01-26 16:29:23 +0800
committerPaul Wise <pabs3@bonedaddy.net>2013-01-26 16:30:42 +0800
commite2cffef5a2c018611ee18765f32c9e29e3033854 (patch)
tree639cf165e9d3662d19174aa0820b72eaaa7a3a1b
parent2dd911cee09c1778dce09dd2557c737118b865ce (diff)
parente3f319022b0b596e63c4778bb6cb79cf72ba7a0e (diff)
downloadget-flash-videos-e2cffef5a2c018611ee18765f32c9e29e3033854.tar.gz
Merge branch 'master' of git://github.com/monsieurvideo/get-flash-videos
-rw-r--r--lib/FlashVideo/Site/Daum.pm22
-rw-r--r--lib/FlashVideo/Site/Kanal5play.pm39
-rw-r--r--lib/FlashVideo/Site/Liveleak.pm45
-rw-r--r--lib/FlashVideo/Site/Motherless.pm22
-rw-r--r--lib/FlashVideo/Site/Putlocker.pm69
-rw-r--r--lib/FlashVideo/Site/Redtube.pm2
-rw-r--r--lib/FlashVideo/Site/Sockshare.pm7
-rw-r--r--lib/FlashVideo/Site/Tv3.pm89
-rw-r--r--lib/FlashVideo/Site/Tv4play.pm85
-rw-r--r--lib/FlashVideo/Site/Tvnz.pm268
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;