1#!/usr/local/bin/perl
2#################################################
3#
4# This file was automatically generated by utils/combine-perl.pl
5# You should edit the original files, not this
6# combined version.
7#
8# The original files are available at:
9# http://github.com/monsieurvideo/get-flash-videos
10#
11#################################################
12#
13# get_flash_videos -- download all the Flash videos off a web page
14#
15#   http://code.google.com/p/get-flash-videos/
16#
17# Copyright 2009, zakflash and MonsieurVideo
18#
19# Licensed under the Apache License, Version 2.0 (the "License"); you may
20# not use this file except in compliance with the License. You may obtain a
21# copy of the License at
22#   http://www.apache.org/licenses/LICENSE-2.0
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26# License for the specific language governing permissions and limitations
27# under the License.
28#
29# Contributions are welcome and encouraged, but please take care to
30# maintain the JustWorks(tm) nature of the program.
31##{ utils/combine-header
32{
33package main;
34$::SCRIPT_NAME = 'get_flash_videos';
35}
36##} utils/combine-header
37BEGIN { $INC{'FlashVideo/Site/4od.pm'}++; }
38# Part of get-flash-videos. See get_flash_videos for copyright.
39BEGIN { $INC{'FlashVideo/Utils.pm'}++; }
40# Part of get-flash-videos. See get_flash_videos for copyright.
41##{ blib/lib/FlashVideo/Utils.pm
42{
43package FlashVideo::Utils;
44
45use strict;
46no warnings 'uninitialized';
47use Exporter;use base 'Exporter';
48use HTML::Entities;
49use HTML::TokeParser;
50use Encode;
51
52use constant FP_KEY => "Genuine Adobe Flash Player 001";
53use constant EXTENSIONS => qr/\.(?:flv|mp4|mov|wmv|avi|m4v)/i;
54use constant MAX_REDIRECTS => 5;
55
56our @EXPORT = qw(debug info error
57  extract_title extract_info title_to_filename get_video_filename url_exists
58  swfhash swfhash_data EXTENSIONS get_user_config_dir get_win_codepage
59  is_program_on_path get_terminal_width json_unescape
60  convert_sami_subtitles_to_srt from_xml);
61
62sub debug(@) {
63  my $string = "@_\n";
64  $string =~ s/\Q$ENV{HOME}\E/~/g;
65  print STDERR $string if $App::get_flash_videos::opt{debug};
66}
67
68sub info(@) {
69  print STDERR "@_\n" unless $App::get_flash_videos::opt{quiet};
70}
71
72sub error(@) {
73  print STDERR "@_\n";
74}
75
76sub extract_title {
77  my($browser) = @_;
78  return extract_info($browser)->{title};
79}
80
81sub extract_info {
82  my($browser) = @_;
83  my($title, $meta_title);
84
85  my $p = HTML::TokeParser->new(\$browser->content);
86  while(my $token = $p->get_tag("title", "meta")) {
87    my($tag, $attr) = @$token;
88
89    if($tag eq 'meta' && $attr->{name} =~ /title/i) {
90      $meta_title = $attr->{content};
91    } elsif($tag eq 'title') {
92      $title = $p->get_trimmed_text;
93    }
94  }
95
96  return {
97    title => $title,
98    meta_title => $meta_title,
99  };
100}
101
102sub swfhash {
103  my($browser, $url) = @_;
104
105  $browser->get($url);
106
107  return swfhash_data($browser->content, $url);
108}
109
110sub swfhash_data {
111  my ($data, $url) = @_;
112
113  die "Must have Compress::Zlib and Digest::SHA for this RTMP download\n"
114      unless eval {
115        require Compress::Zlib;
116        require Digest::SHA;
117      };
118
119  $data = "F" . substr($data, 1, 7)
120              . Compress::Zlib::uncompress(substr $data, 8);
121
122  return
123    swfsize => length $data,
124    swfhash => Digest::SHA::hmac_sha256_hex($data, FP_KEY),
125    swfUrl  => $url;
126}
127
128sub url_exists {
129  my($browser, $url) = @_;
130
131  $browser->head($url);
132  my $response = $browser->response;
133  debug "Exists on $url: " . $response->code;
134  return $url if $response->code == 200;
135
136  my $redirects = 0;
137  while ( ($response->code =~ /^30\d/) and ($response->header('Location'))
138      and ($redirects < MAX_REDIRECTS) ) {
139    $url = URI->new_abs($response->header('Location'), $url);
140    $response = $browser->head($url);
141    debug "Redirected to $url (" . $response->code . ")";
142    if ($response->code == 200) {
143      return $url;
144    }
145    $redirects++;
146  }
147
148  return '';
149}
150
151sub title_to_filename {
152  my($title, $type) = @_;
153
154  if($App::get_flash_videos::opt{filename} ne '') {
155    return $App::get_flash_videos::opt{filename};
156  }
157
158  if($title =~ s/(@{[EXTENSIONS]})$//) {
159    $type = substr $1, 1;
160  } elsif ($type && $type !~ /^\w+$/) {
161    $type = substr((URI->new($type)->path =~ /(@{[EXTENSIONS]})$/)[0], 1);
162  }
163
164  $type ||= "flv";
165
166  $title = decode_utf8($title);
167
168  utf8::upgrade($title);
169
170  if ($title =~ /&(?:\w+|#(?:\d+|x[A-F0-9]+));/) {
171    $title = decode_entities($title);
172  }
173
174  $title =~ s/\s+/_/g;
175  $title =~ s/[^\w\-,()&]/_/g;
176  $title =~ s/^_+|_+$//g;   # underscores at the start and end look bad
177
178  $title = encode_utf8($title);
179
180  return get_video_filename($type) unless $title;
181
182  return "$title.$type";
183}
184
185sub get_video_filename {
186  my($type) = @_;
187  $type ||= "flv";
188  return "video" . get_timestamp_in_iso8601_format() . "." . $type;
189}
190
191sub get_timestamp_in_iso8601_format {
192  use Time::localtime;
193  my $time = localtime;
194  return sprintf("%04d%02d%02d%02d%02d%02d",
195                 $time->year + 1900, $time->mon + 1,
196                 $time->mday, $time->hour, $time->min, $time->sec);
197}
198
199sub get_vlc_exe_from_registry {
200  if ($^O !~ /MSWin/i) {
201    die "Doesn't make sense to call this except on Windows";
202  }
203
204  my $HAS_WIN32_REGISTRY = eval { require Win32::Registry };
205
206  die "Win32::Registry required for JustWorks(tm) playing on Windows"
207    unless $HAS_WIN32_REGISTRY;
208
209  require Win32::Registry;
210
211  Win32::Registry->import();
212
213  my $local_machine;
214
215  {
216    no strict 'vars';
217    $local_machine = $::HKEY_LOCAL_MACHINE;
218  }
219
220  my $key = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall';
221
222  $local_machine->Open($key, my $reg);
223
224  my @applications;
225  $reg->GetKeys(\@applications);
226
227  my $vlc_binary;
228
229  foreach my $application (@applications) {
230    next unless $application =~ /VLC Media Player/i;
231
232    $reg->Open($application, my $details);
233
234    my %app_properties;
235    $details->GetValues(\%app_properties);
236
237    if ($app_properties{DisplayIcon}->[-1] =~ /\.exe$/i) {
238      $vlc_binary = $app_properties{DisplayIcon}->[-1];
239      last;
240    }
241  }
242
243  return $vlc_binary;
244}
245
246sub get_win_codepage {
247  require Win32::API;
248
249  if (! %Win32::API::Type::Known) {
250    %Win32::API::Type::Known = (int => 'i');
251  }
252
253  Win32::API->Import("kernel32", "int GetACP()");
254  return "cp" . GetACP();
255}
256
257sub get_user_config_dir {
258
259
260  return $^O =~ /MSWin/i ? ($ENV{APPDATA} || 'c:/windows/application data')
261                            . "/get_flash_videos"
262                         : "$ENV{HOME}/.get_flash_videos";
263}
264
265sub is_program_on_path {
266  my($program) = @_;
267  my $win = $^O =~ /MSWin/i;
268
269  for my $dir(split($win ? ";" : ":", $ENV{PATH})) {
270    return 1 if -f "$dir/$program" . ($win ? ".exe" : "");
271  }
272  return 0;
273}
274
275sub get_terminal_width {
276  if(eval { require Term::ReadKey } && (my($width) = Term::ReadKey::GetTerminalSize())) {
277    return $width - 1 if $^O =~ /MSWin|cygwin/i; # seems to be off by 1 on Windows
278    return $width;
279  } elsif($ENV{COLUMNS}) {
280    return $ENV{COLUMNS};
281  } else {
282    return 80;
283  }
284}
285
286sub json_unescape {
287  my($s) = @_;
288
289  $s =~ s/\\u([0-9a-f]{1,4})/chr hex $1/ge;
290  $s =~ s{(\\[\\/rnt"])}{"\"$1\""}gee;
291  return $s;
292}
293
294sub convert_sami_subtitles_to_srt {
295  my ($sami_subtitles, $filename, $decrypt_callback) = @_;
296
297  die "SAMI subtitles must be provided"      unless $sami_subtitles;
298  die "Output SRT filename must be provided" unless $filename;
299
300  $sami_subtitles =~ s/[\r\n]//g; # flatten
301
302  my @lines = split /<Sync\s/i, $sami_subtitles;
303  shift @lines; # Skip headers
304
305  my @subtitles;
306  my $count = 0;
307
308  my $last_proper_sub_end_time = '';
309
310  for (@lines) {
311    my ($begin, $sub);
312    s|<\/?span.*?>| |g;
313
314    s|&amp;|&|g;
315
316    s{&(?:nbsp|#160);}{ }g;
317
318
319    ($begin, $sub) = ($1, $2) if m{[^>]*Start="(.+?)"[^>]*>(.*?)<\/Sync>}i;
320
321    if (/^\s*Encrypted="true"\s*/i) {
322      if ($decrypt_callback and ref($decrypt_callback) eq 'CODE') {
323        $sub = $decrypt_callback->($sub);
324      }
325    }
326
327    $sub =~ s@&amp;@&@g;
328    $sub =~ s@(?:</?span[^>]*>|&nbsp;|&#160;)@ @g;
329
330    $sub =~ s{</?P[^>]*?>}{}g;  # remove <P Class="ENCC"> and similar
331
332    $sub =~ s{<(/)?([BI])>}{"<$1" . lc($2) . ">"}eg;
333
334    decode_entities($sub); # in void context, this works in place
335
336    if ($sub and ($begin or $begin == 0)) {
337      my $seconds = int( $begin / 1000.0 );
338      my $ms = $begin - ( $seconds * 1000.0 );
339      $begin = sprintf("%02d:%02d:%02d,%03d", (gmtime($seconds))[2,1,0], $ms );
340
341
342      $sub =~ s/^\s*(.*?)\s*$/$1/;
343
344      $sub =~ s/\s{2,}/ /g;
345
346      $sub =~ s|<br ?\/? ?>|\n|ig;
347
348      $sub =~ s/^\s*|\s*$//mg;
349
350      if ($count and !$subtitles[$count - 1]->{end}) {
351        $subtitles[$count - 1]->{end} = $begin;
352      }
353
354      if (!$sub or $sub =~ /^\s+$/) {
355        if ($count) {
356          $last_proper_sub_end_time = $subtitles[$count - 1]->{end};
357        }
358
359        next; # this is not a meaningful subtitle
360      }
361
362      push @subtitles, {
363        start => $begin,
364        text  => $sub,
365      };
366
367      $count++;
368    }
369  }
370
371  $subtitles[$count - 1]->{end} = $last_proper_sub_end_time;
372
373  open my $subtitle_fh, '>', $filename
374    or die "Can't open subtitles file $filename: $!";
375
376  binmode $subtitle_fh, ':utf8';
377
378  $count = 1;
379
380  foreach my $subtitle (@subtitles) {
381    print $subtitle_fh "$count\n$subtitle->{start} --> $subtitle->{end}\n" .
382                       "$subtitle->{text}\n\n";
383    $count++;
384  }
385
386  close $subtitle_fh;
387
388  return 1;
389}
390
391sub from_xml {
392  my($xml, @args) = @_;
393
394  if(!eval { require XML::Simple && XML::Simple::XMLin("<foo/>") }) {
395    die "Must have XML::Simple to download " . caller =~ /::([^:])+$/ . " videos\n";
396  }
397
398  $xml = eval {
399    XML::Simple::XMLin(ref $xml eq 'SCALAR' ? $xml
400      : ref $xml ? $xml->content
401      : $xml, @args);
402  };
403
404  if($@) {
405    die "$@ (from ", join("::", caller), ")\n";
406  }
407
408  return $xml;
409}
410
4111;
412}
413##} blib/lib/FlashVideo/Utils.pm
414##{ blib/lib/FlashVideo/Site/4od.pm
415{
416package FlashVideo::Site::4od;
417
418
419use strict;
420BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
421BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *from_xml = \&FlashVideo::Utils::from_xml; }
422use URI::Escape;
423
424sub search {
425  my ($self, $search, $type) = @_;
426
427  unless(eval { from_xml("<foo/>") }) {
428    if($type eq 'site') {
429      die $@;
430    } else {
431      debug $@;
432      return;
433    }
434  }
435
436  my $gdata_template_url =
437    "http://gdata.youtube.com/feeds/api/videos?q=%s&orderby=published&start-index=1&max-results=50&v=2";
438  my $search_url = sprintf $gdata_template_url, uri_escape($search);
439
440  my $browser = FlashVideo::Mechanize->new();
441
442  $browser->get($search_url);
443
444  if (!$browser->success) {
445    die "Couldn't get YouTube search Atom XML: " . $browser->response->status_line();
446  }
447
448  my $xml = from_xml($browser, KeyAttr => [], ForceArray => ['entry']);
449
450  my @matches = map { _process_4od_result($_) }
451                grep { $_->{author}->{name} =~ /^4oD\w+$/i } @{ $xml->{entry} };
452
453  return @matches;
454}
455
456sub _process_4od_result {
457  my $feed_entry = shift;
458
459  my $url = $feed_entry->{'media:group'}->{'media:player'}->{url};
460  $url =~ s/&feature=youtube_gdata//;
461
462  my $published_date = $feed_entry->{published};
463  $published_date =~ s/T.*$//; # only care about date, not time
464
465  my $title = $feed_entry->{'media:group'}->{'media:title'}->{content};
466  my $description = $feed_entry->{'media:group'}->{'media:description'}->{content};
467
468  my $result_name = "$title ($published_date)";
469
470  return { name => $result_name, url => $url, description => $description };
471}
472
4731;
474}
475##} blib/lib/FlashVideo/Site/4od.pm
476BEGIN { $INC{'FlashVideo/Site/5min.pm'}++; }
477# Part of get-flash-videos. See get_flash_videos for copyright.
478##{ blib/lib/FlashVideo/Site/5min.pm
479{
480package FlashVideo::Site::5min;
481
482use strict;
483BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
484BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
485
486sub find_video {
487  my ($self, $browser) = @_;
488
489  my $filename = title_to_filename(extract_info($browser)->{meta_title});
490
491  my $url = (FlashVideo::Generic->find_video($browser, $browser->uri))[0];
492
493  return $url, $filename;
494}
495
4961;
497}
498##} blib/lib/FlashVideo/Site/5min.pm
499BEGIN { $INC{'FlashVideo/Site/Abc.pm'}++; }
500# Part of get-flash-videos. See get_flash_videos for copyright.
501##{ blib/lib/FlashVideo/Site/Abc.pm
502{
503package FlashVideo::Site::Abc;
504
505use strict;
506BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
507BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
508
509sub find_video {
510  my ($self, $browser, $embed_url) = @_;
511
512  if ($browser->uri->as_string =~ m'/watch/clip/[\w\-]+/(\w+)/(\w+)/(\w+)') {
513    my $show_id     = $1;
514    my $playlist_id = $2;
515    my $video_id    = $3;
516
517    return handle_abc_clip($browser, $show_id, $playlist_id, $video_id);
518  }
519
520  my $playpath;
521  if ($browser->content =~ /http:\/\/cdn\.video\.abc\.com\/abcvideo\/video_fep\/thumbnails\/220x124\/([^"]*)220x124\.jpg/) {
522    $playpath = "mp4:/abcvideo/video_fep/mov/" . lc($1) . "768x432_700.mov";
523  }
524
525  $browser->content =~ /<h2 id="video_title">([^<]*)<\/h2>/;
526  my $title = $1;
527  my $rtmpurl = "rtmp://abcondemandfs.fplive.net:1935/abcondemand";
528
529  return {
530    rtmp => $rtmpurl,
531    playpath => $playpath,
532    flv => title_to_filename($title)
533  };
534}
535
536sub handle_abc_clip {
537  my ($browser, $show_id, $playlist_id, $video_id) = @_;
538
539
540  my $abc_clip_rss_url_template =
541    "http://ll.static.abc.com/vp2/ws/s/contents/1000/videomrss?" .
542    "brand=001&device=001&width=644&height=362&clipId=%s" .
543    "&start=0&limit=1&fk=CATEGORIES&fv=%s";
544
545  my $abc_clip_rss_url = sprintf $abc_clip_rss_url_template,
546                                 $video_id, $playlist_id;
547
548  $browser->get($abc_clip_rss_url);
549
550  if (!$browser->success) {
551    die "Couldn't download ABC clip RSS: " . $browser->response->status_line;
552  }
553
554  my $xml = from_xml($browser);
555
556  my $video_url = $xml->{channel}->{item}->{'media:content'}->{url};
557  my $type      = $video_url =~ /\.mp4$/ ? 'mp4' : 'flv';
558
559  if (!$video_url) {
560    die "Couldn't determine ABC clip URL";
561  }
562
563  my $episode_name;
564  if ($video_url =~ /FLF_\d+[A-Za-z]{0,5}_([^_]+)/) {
565    $episode_name = $1;
566  }
567
568  my $category    = $xml->{channel}->{item}->{category};
569  my $title       = $xml->{channel}->{item}->{'media:title'}->{content};
570
571  if (ref($category) eq 'HASH' and ! keys %$category) {
572    $category = '';
573  }
574
575  my $description = $xml->{channel}->{item}->{'media:description'}->{content};
576
577  for ($category, $description, $title) {
578    s/<\/?\w+>//g;
579  }
580
581  my $video_title = make_title($category, $episode_name, $title, $description);
582
583  return $video_url, title_to_filename($video_title, $type);
584}
585
586sub make_title {
587  return join " - ", grep /./, @_;
588}
589
590sub can_handle {
591  my($self, $browser, $url) = @_;
592
593  return $url && URI->new($url)->host =~ /\babc\.(?:go\.)?com$/;
594}
595
5961;
597}
598##} blib/lib/FlashVideo/Site/Abc.pm
599BEGIN { $INC{'FlashVideo/Site/Abclocal.pm'}++; }
600# Part of get-flash-videos. See get_flash_videos for copyright.
601##{ blib/lib/FlashVideo/Site/Abclocal.pm
602{
603package FlashVideo::Site::Abclocal;
604
605use strict;
606BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
607BEGIN { no strict 'refs'; }
608use Data::Dumper;
609use File::Basename;
610
611sub find_video {
612  my ($self, $browser, $embed_url, $prefs) = @_;
613
614  my($station,$id) = $browser->content =~ m{http://cdn.abclocal.go.com/[^"']*station=([^&;"']+)[^"']*mediaId=([^&;"']+)}s;
615
616  die "No media id and station found" unless $id;
617
618  $browser->get("http://cdn.abclocal.go.com/$station/playlistSyndicated?id=$id");
619
620  my @tmp = $browser->content =~ m{<video *videopath="([^"]*)"[^>]*width="([^"]*)"[^>]*height="([^"]*)"[^>]*>}s ;
621  my(@videos);
622  for (my $i = 0; $i < @tmp; $i+=3)
623  {
624    push @videos, { "playpath" => $tmp[$i], "resolution" => [$tmp[$i+1], $tmp[$i+2]] };
625  }
626
627  my $video = $prefs->quality->choose(@videos);
628
629  my $url = $video->{"playpath"};
630
631  return $url, File::Basename::basename($url);
632}
633
6341;
635}
636##} blib/lib/FlashVideo/Site/Abclocal.pm
637BEGIN { $INC{'FlashVideo/Site/About.pm'}++; }
638# Part of get-flash-videos. See get_flash_videos for copyright.
639BEGIN { $INC{'FlashVideo/Site/Brightcove.pm'}++; }
640# Part of get-flash-videos. See get_flash_videos for copyright.
641##{ blib/lib/FlashVideo/Site/Brightcove.pm
642{
643package FlashVideo::Site::Brightcove;
644
645use strict;
646BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
647BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
648use MIME::Base64;
649
650sub find_video {
651  my ($self, $browser, $embed_url) = @_;
652
653  my $metadata = { };
654  my ($video_id, $player_id);
655
656  $video_id  = ($browser->content =~ /(?:clip|video)Id["'\] ]*[:=]["' ]*(\d+)/i)[0];
657  $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0];
658
659  $player_id ||= ($browser->content =~ /<param name=["']?playerID["']? value=["'](\d+) ?["']/i)[0];
660  $video_id ||= ($browser->content =~ /<param name=["']?\@?video(?:Player|id)["']? value=["'](\d+)["']/i)[0];
661
662  $player_id ||= ($browser->content =~ /flashVars.*playerID=(\d+)/i)[0];
663  $video_id ||= ($browser->content =~ /flashVars.*video(?:Player|ID)=(\d+)/i)[0];
664
665  if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) {
666    $video_id = $1;
667    $player_id = $2;
668  }
669
670  for my $url($browser->uri->as_string, $embed_url) {
671    if($url =~ /(?:videoID|bctid)=?(\d+)/i) {
672      $video_id ||= $1;
673    }
674
675    if($url =~ /(?:playerID|bcpid)=?(\d+)/i) {
676      $player_id ||= $1;
677    }
678
679    if($url =~ /(?:lineupID|bclid)=?(\d+)/i) {
680      $metadata->{lineupId} ||= $1;
681    }
682  }
683
684  debug "Extracted playerId: $player_id, videoId: $video_id, lineupID: $metadata->{lineupId}"
685    if $player_id or $video_id;
686
687  die "Unable to extract Brightcove IDs from page" unless $player_id;
688
689  $metadata->{videoId} = $video_id;
690  return $self->amfgateway($browser, $player_id, $metadata);
691}
692
693sub amfgateway {
694  my($self, $browser, $player_id, $metadata) = @_;
695
696  my $has_amf_packet = eval { require Data::AMF::Packet };
697  if (!$has_amf_packet) {
698    die "Must have Data::AMF::Packet installed to download Brightcove videos";
699  }
700
701  my $page_url = $browser->uri;
702
703  my $packet = Data::AMF::Packet->deserialize(decode_base64(<<EOF));
704AAAAAAABAEhjb20uYnJpZ2h0Y292ZS50ZW1wbGF0aW5nLlRlbXBsYXRpbmdGYWNhZGUuZ2V0Q29u
705dGVudEZvclRlbXBsYXRlSW5zdGFuY2UAAi8yAAACNQoAAAACAEH4tP+1EAAAEAA1Y29tLmJyaWdo
706dGNvdmUudGVtcGxhdGluZy5Db250ZW50UmVxdWVzdENvbmZpZ3VyYXRpb24ACnZpZGVvUmVmSWQG
707AAd2aWRlb0lkBgAIbGluZXVwSWQGAAtsaW5ldXBSZWZJZAYAF29wdGltaXplRmVhdHVyZWRDb250
708ZW50AQEAF2ZlYXR1cmVkTGluZXVwRmV0Y2hJbmZvEAAkY29tLmJyaWdodGNvdmUucGVyc2lzdGVu
709Y2UuRmV0Y2hJbmZvAApjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRjaExldmVsRW51bQBAEAAAAAAA
710AAALY29udGVudFR5cGUCAAtWaWRlb0xpbmV1cAAACQAKZmV0Y2hJbmZvcwoAAAACEAAkY29tLmJy
711aWdodGNvdmUucGVyc2lzdGVuY2UuRmV0Y2hJbmZvAApjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRj
712aExldmVsRW51bQA/8AAAAAAAAAALY29udGVudFR5cGUCAAtWaWRlb0xpbmV1cAAACRAAJGNvbS5i
713cmlnaHRjb3ZlLnBlcnNpc3RlbmNlLkZldGNoSW5mbwAKY2hpbGRMaW1pdABAWQAAAAAAAAAPZ3Jh
714bmRjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRjaExldmVsRW51bQBACAAAAAAAAAALY29udGVudFR5
715cGUCAA9WaWRlb0xpbmV1cExpc3QAAAkAAAk=
716EOF
717
718  if (defined $player_id) {
719    $packet->messages->[0]->{value}->[0] = "$player_id";
720  }
721
722  if (ref $metadata) {
723    for(keys %$metadata) {
724      $packet->messages->[0]->{value}->[1]->{$_} = "$metadata->{$_}";
725    }
726  }
727
728  my $data = $packet->serialize;
729
730  $browser->post(
731    "http://c.brightcove.com/services/amfgateway",
732    Content_Type => "application/x-amf",
733    Content => $data
734  );
735
736  die "Failed to post to Brightcove AMF gateway"
737    unless $browser->response->is_success;
738
739  $packet = Data::AMF::Packet->deserialize($browser->content);
740
741  if($self->debug) {
742    require Data::Dumper;
743    debug Data::Dumper::Dumper($packet);
744  }
745
746  if(ref $packet->messages->[0]->{value} ne 'ARRAY') {
747    die "Unexpected data from AMF gateway";
748  }
749
750  my @found;
751  for (@{$packet->messages->[0]->{value}}) {
752    if ($_->{data}->{videoDTO}) {
753      push @found, $_->{data}->{videoDTO};
754    }
755    if ($_->{data}->{videoDTOs}) {
756      push @found, @{$_->{data}->{videoDTOs}};
757    }
758  }
759
760  my @rtmpdump_commands;
761
762  for my $d (@found) {
763    next if $metadata->{videoId} && $d->{id} != $metadata->{videoId};
764
765    my $host = ($d->{FLVFullLengthURL} =~ m!rtmp://(.*?)/!)[0];
766    my $file = ($d->{FLVFullLengthURL} =~ m!&([a-z0-9:]+/.*?)(?:&|$)!)[0];
767    my $app = ($d->{FLVFullLengthURL} =~ m!//.*?/(.*?)/&!)[0];
768    my $filename = ($d->{FLVFullLengthURL} =~ m!&.*?/([^/&]+)(?:&|$)!)[0];
769
770    $app .= "?videoId=$d->{id}&lineUpId=$d->{lineupId}&pubId=$d->{publisherId}&playerId=$player_id&playerTag=&affiliateId=";
771
772    my $args = {
773      app => $app,
774      pageUrl => $page_url,
775      swfUrl => "http://admin.brightcove.com/viewer/federated/f_012.swf?bn=590&pubId=$d->{publisherId}",
776      tcUrl => "rtmp://$host:1935/$app",
777      auth => ($d->{FLVFullLengthURL} =~ /^[^&]+&(.*)$/)[0],
778      rtmp => "rtmp://$host/$app",
779      playpath => $file,
780      flv => "$filename.flv",
781    };
782
783    if ($d->{publisherName} and $d->{displayName}) {
784      $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}");
785    }
786
787    if (!$d->{FLVFullLengthStreamed}) {
788      info "Brightcove HTTP download detected";
789      return ($d->{FLVFullLengthURL}, $args->{flv});
790    }
791
792    push @rtmpdump_commands, $args;
793  }
794
795  if (@rtmpdump_commands > 1) {
796    return \@rtmpdump_commands;
797  }
798  else {
799    return $rtmpdump_commands[-1];
800  }
801}
802
803sub can_handle {
804  my($self, $browser, $url) = @_;
805
806  return 1 if $url && URI->new($url)->host =~ /\.brightcove\.com$/;
807
808  return $browser->content =~ /(playerI[dD]|brightcove.player.create)/
809    && $browser->content =~ /brightcove/i;
810}
811
8121;
813}
814##} blib/lib/FlashVideo/Site/Brightcove.pm
815##{ blib/lib/FlashVideo/Site/About.pm
816{
817package FlashVideo::Site::About;
818
819use strict;
820BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
821BEGIN { no strict 'refs'; }
822BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
823use base 'FlashVideo::Site::Brightcove';
824
825my $JS_RE = qr/vdo_None\.js/;
826
827sub find_video {
828  my($self, $browser, $embed_url) = @_;
829
830  my($video_ref) = $browser->content =~ /zIvdoId=["']([^"']+)/;
831  die "Unable to extract video ref" unless $video_ref;
832
833  my($js_src) = $browser->content =~ /["']([^"']+$JS_RE)/;
834  $browser->get($js_src);
835  my($player_id) = $browser->content =~ /playerId.*?(\d+)/;
836  die "Unable to extract playerId" unless $player_id;
837
838  return $self->amfgateway($browser, $player_id, { videoRefId => $video_ref });
839}
840
841sub can_handle {
842  my($self, $browser, $url) = @_;
843
844  return $browser->content =~ $JS_RE;
845}
846
8471;
848}
849##} blib/lib/FlashVideo/Site/About.pm
850BEGIN { $INC{'FlashVideo/Site/Adultswim.pm'}++; }
851# Part of get-flash-videos. See get_flash_videos for copyright.
852##{ blib/lib/FlashVideo/Site/Adultswim.pm
853{
854package FlashVideo::Site::Adultswim;
855
856use strict;
857BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
858BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
859
860sub find_video {
861	my($self, $browser, $embed_url) = @_;
862
863	my $xml;
864	my $id;
865
866	my $segIds;
867	if($browser->{content} =~ m/(<meta[^>]* ?name=["']segIds["'] ?[^>]*>)/){
868		my $text = $1;
869		if($text =~ m/content=["']([^"']+)["']/){
870			$segIds = $1;
871		}
872	}
873
874	my $id1;
875	if($segIds =~ m/^([^#]*)#/){
876		$id1 = $1;
877	}
878
879	my $title;
880	if($browser->{content} =~ m/<meta property=["']og:title["'] content=["']([^"']+)["']\/>/){
881		$title = $1;
882	}
883
884	my $configURL = "/tools/swf/player_configs/watch_player.xml";
885
886		if($browser->content =~ /pageObj\.configURL = ["']([^"']+)["'];/) {
887			$configURL = $1;
888		}
889
890	$browser->get($configURL);
891
892	my $serviceConfigURL;
893
894	if($browser->response->code =~ /^30\d$/){
895
896		$xml = from_xml($browser);
897
898		if($xml->{serviceConfigURL} ne ""){
899			$serviceConfigURL = $1;
900		}
901	} else {
902		$serviceConfigURL = "http://asfix.adultswim.com/staged/AS.configuration.xml";
903	}
904
905	$browser->get($serviceConfigURL);
906
907	$xml = from_xml($browser);
908
909	my $getVideoPlayerURL;
910	if($xml->{config}->{services}->{getVideoPlaylist}->{url} ne ""){
911		$getVideoPlayerURL = $1;
912	} else {
913		$getVideoPlayerURL = "http://asfix.adultswim.com/asfix-svc/episodeservices/getVideoPlaylist?networkName=AS";
914	}
915
916	my $videoURL = "$getVideoPlayerURL&id=$id1";
917	$browser->get($videoURL);
918
919	$xml = from_xml($browser);
920
921
922
923	my $pick = $xml->{entry}[4];
924
925	my $file_url = $pick->{ref}->{href};
926
927
928	return $file_url, title_to_filename($title);
929}
930
9311;
932}
933##} blib/lib/FlashVideo/Site/Adultswim.pm
934BEGIN { $INC{'FlashVideo/Site/Amazon.pm'}++; }
935# Part of get-flash-videos. See get_flash_videos for copyright.
936##{ blib/lib/FlashVideo/Site/Amazon.pm
937{
938package FlashVideo::Site::Amazon;
939
940use strict;
941
942use Encode;
943BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
944BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
945use URI::Escape;
946
947my $playlist_url_template = 'http://%s/gp/mpd/getplaylist-v2/%s/%s';
948
949sub find_video {
950  my ($self, $browser) = @_;
951
952  my $amazon_host = $browser->uri()->host();
953
954  if ($browser->content =~ /swfParams\.xmlUrl = ["'](http:.*?)["']/) {
955    debug "Getting Amazon URL direct URL $1";
956    $browser->get($1);
957  }
958  else {
959    my ($video_id, $session_id);
960
961    if ($browser->content =~
962      /swfParams\.mediaObjectId = ["'](.*?)["']/) {
963      $video_id = $1;
964    }
965    else {
966      die "Couldn't find video ID / media object ID in Amazon page";
967    }
968
969    if ($browser->content =~
970      /swfParams\.sessionId = ["'](.*?)["']/) {
971      $session_id = $1;
972    }
973    else {
974      die "Couldn't find session ID in Amazon page";
975    }
976
977    my $playlist_url =
978      sprintf($playlist_url_template, $amazon_host, $video_id, $session_id);
979
980    $browser->get($playlist_url);
981  }
982
983  my ($title, @video_urls) = parse_smil_like_xml($browser->content);
984
985  my $filename = title_to_filename($title);
986
987  return $video_urls[0], $filename;
988}
989
990sub parse_smil_like_xml {
991  my $smil = shift;
992
993  my $parsed_smil = from_xml($smil);
994
995
996  my $title;
997
998  my $video_ref = $parsed_smil->{videoObject}->{smil}->{body}->{switch}->{video};
999  if (ref($video_ref) ne 'ARRAY') {
1000    my $id;
1001
1002    my %videos = %{ $parsed_smil->{videoObject} };
1003
1004    foreach my $video (keys %videos) {
1005      next unless ref $videos{$video};
1006
1007      if ($videos{$video}->{index} == 0) {
1008        $id = $video;
1009        $title = $videos{$video}->{title};
1010        last;
1011      }
1012    }
1013
1014    $video_ref = $parsed_smil->{videoObject}->{$id}->{smil}->{body}->{switch}->{video};
1015  }
1016
1017  my @different_quality_videos = map { $_->{src} }
1018                                 sort { $b->{'system-bitrate'} <=> $a->{'system-bitrate'} }
1019                                 @$video_ref;
1020
1021  $title ||= $parsed_smil->{videoObject}->{title};
1022
1023  if ($title !~ /\s/) {
1024    $title = uri_unescape($title);
1025  }
1026
1027  return ($title, @different_quality_videos);
1028}
1029
10301;
1031}
1032##} blib/lib/FlashVideo/Site/Amazon.pm
1033BEGIN { $INC{'FlashVideo/Site/Aniboom.pm'}++; }
1034# Part of get-flash-videos. See get_flash_videos for copyright.
1035##{ blib/lib/FlashVideo/Site/Aniboom.pm
1036{
1037package FlashVideo::Site::Aniboom;
1038
1039use strict;
1040BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1041BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
1042
1043sub find_video {
1044  my ($self, $browser, $embed_url) = @_;
1045
1046  my ($id, $url, $title);
1047
1048  if ($browser->uri->as_string =~ /\/animation-video\/(\d*)\/([^\/]*)/) {
1049    $id = $1;
1050    $title = $2;
1051    $title =~ s/-/ /g;
1052  } else {
1053    die "Could not detect video ID!";
1054  }
1055
1056  $browser->get("http://www.aniboom.com/animations/player/handlers/animationDetails.aspx?mode=&movieid=$id");
1057
1058  if ($browser->content =~ /(?:mp4|flv)=([^&]*)/) {
1059    $url = $1;
1060    $url =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
1061  } else {
1062    die "Could not get flv/mp4 location!";
1063  }
1064
1065  return $url, title_to_filename($title);
1066}
1067
10681;
1069
1070}
1071##} blib/lib/FlashVideo/Site/Aniboom.pm
1072BEGIN { $INC{'FlashVideo/Site/Apple.pm'}++; }
1073# Part of get-flash-videos. See get_flash_videos for copyright.
1074##{ blib/lib/FlashVideo/Site/Apple.pm
1075{
1076package FlashVideo::Site::Apple;
1077use strict;
1078BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1079BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
1080
1081sub find_video {
1082  my ($self, $browser, $embed_url, $prefs) = @_;
1083
1084  if(!FlashVideo::Downloader->check_file($browser->content)) {
1085    my @urls = $browser->content =~ /['"]([^'"]+\.mov)(?:\?[^'"]+)?['"]/g;
1086    die "No .mov URLs found on page" unless @urls;
1087    debug "Found URLs: @urls";
1088
1089    my $redirect_url = $prefs->quality->choose(map {
1090        /(\d+p?)\.mov/ && {
1091          url => $_,
1092          resolution => $prefs->quality->format_to_resolution($1)
1093        }
1094      } @urls
1095    )->{url};
1096
1097    $browser->get($redirect_url);
1098  }
1099
1100  my $url = $self->handle_mov($browser);
1101  my $filename = ($url->path =~ m{([^/]+)$})[0];
1102
1103  return $url, $filename;
1104}
1105
1106sub handle_mov {
1107  my ($self, $browser) = @_;
1108
1109  $browser->agent("Apple iPhone OS v2.0.1 CoreMedia v1.0.0.5B108");
1110
1111  if($browser->content =~ /url\s*\0+[\1-,]*(.*?)\0/) {
1112    return URI->new_abs($1, $browser->uri)
1113  } else {
1114    die "Cannot find link in .mov";
1115  }
1116}
1117
1118sub can_handle {
1119  my($self, $browser, $url) = @_;
1120
1121  return $url =~ m{apple\.com/trailers/} || $url =~ m{movies\.apple\.com};
1122}
1123
11241;
1125}
1126##} blib/lib/FlashVideo/Site/Apple.pm
1127BEGIN { $INC{'FlashVideo/Site/Arte.pm'}++; }
1128# Part of get-flash-videos. See get_flash_videos for copyright.
1129##{ blib/lib/FlashVideo/Site/Arte.pm
1130{
1131package FlashVideo::Site::Arte;
1132
1133use strict;
1134BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1135BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
1136
1137sub find_video {
1138  my ($self, $browser, $embed_url, $prefs) = @_;
1139  my ($lang, $xmlurl1, $xmlurl2, $filename, $videourl, $hash, $playerurl, $quality);
1140
1141  debug "Arte::find_video called, embed_url = \"$embed_url\"\n";
1142
1143  my $pageurl = $browser->uri() . "";
1144  if($pageurl =~ /videos\.arte\.tv\/(..)\//) {
1145    $lang = $1;
1146  } else {
1147    die "Unable to find language in original URL \"$pageurl\"\n";
1148  }
1149
1150  if($browser->content =~ /videorefFileUrl = "(.*)";/) {
1151    $xmlurl1 = $1;
1152    debug "found videorefFileUrl \"$xmlurl1\"\n";
1153    ($filename = $xmlurl1) =~ s/-.*$//;
1154    $filename =~ s/^.*\///g;
1155    $filename = title_to_filename($filename);
1156  } else {
1157    die "Unable to find 'videorefFileUrl' in page\n";
1158  }
1159
1160  if($browser->content =~ /<param name="movie" value="(http:\/\/videos\.arte\.tv\/[^\?]+)\?/) {
1161    $playerurl = $1;
1162    debug "found playerurl \"$playerurl\"\n";
1163  }
1164
1165  $browser->get($xmlurl1);
1166
1167  if($browser->content =~ /<video lang="$lang" ref="(.*)" \/>/) {
1168    $xmlurl2 = $1;
1169    debug "found <video ref=\"$xmlurl2\">\n";
1170  } else {
1171    die "Unable to find <video ref...> in XML $xmlurl1\n";
1172  }
1173
1174  $browser->get($xmlurl2);
1175  $quality = {high => 'hd', low => 'sd'}->{$prefs->{quality}};
1176
1177  if($browser->content =~ /<url quality="$quality">([^<]+)<\/url>/) {
1178    $videourl = { rtmp => $1,
1179		flv => $filename};
1180    if(defined $playerurl) {
1181      $videourl->{swfVfy} = $playerurl;
1182    }
1183  } else {
1184    die "Unable to find <url ...> in XML $xmlurl2\n";
1185  }
1186
1187  return $videourl, $filename;
1188}
1189
11901;
1191}
1192##} blib/lib/FlashVideo/Site/Arte.pm
1193BEGIN { $INC{'FlashVideo/Site/Bbc.pm'}++; }
1194# Part of get-flash-videos. See get_flash_videos for copyright.
1195##{ blib/lib/FlashVideo/Site/Bbc.pm
1196{
1197package FlashVideo::Site::Bbc;
1198
1199use strict;
1200BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1201BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1202use URI;
1203
1204sub find_video {
1205  my ($self, $browser, $page_url, $prefs) = @_;
1206
1207  my $count = 0;
1208  while((my $location = $browser->response->header("Location")) && $count++ < 5) {
1209    $browser->get($location);
1210  }
1211
1212  my $playlist_xml;
1213  if ($browser->content =~ /<param name="playlist" value="(http:.+?\.s?xml)"/) {
1214    $playlist_xml = $1;
1215  }
1216  elsif($browser->content =~ /empDivReady\s*\(([^)]+)/) {
1217    my @params = split /,\s*/, $1;
1218
1219    my $id   = $params[3];
1220    my $path = $params[4];
1221
1222    $id   =~ s/['"]//g;
1223    $path =~ s/['"]//g;
1224
1225    $playlist_xml = URI->new_abs($path, $browser->uri) . "/media/emp/playlists/$id.xml";
1226  }
1227  elsif($browser->content =~ /setPlaylist\s*\(([^)]+)/) {
1228    my $path = $1;
1229    $path =~ s/['"]//g;
1230    $playlist_xml = URI->new_abs($path, $browser->uri);
1231  }
1232  elsif($browser->content =~ /EmpEmbed.embed\s*\((.*?)\);/) {
1233    my $path = (split /,/, $1)[3];
1234    $path =~ s/"//g;
1235    $playlist_xml = URI->new_abs($path, $browser->uri);
1236  }
1237  elsif($browser->uri =~ m!/(b[0-9a-z]{7})(?:/|$)!) {
1238    my @gi_cmd = (qw(get_iplayer -g --pid), $1);
1239
1240    if($browser->content =~ /buildAudioPlayer/) {
1241      push @gi_cmd, "--type=radio";
1242    }
1243
1244    error "get_flash_videos does not support iplayer, but get_iplayer does..";
1245    info "Attempting to run '@gi_cmd'";
1246    exec @gi_cmd;
1247    error "Please download get_iplayer from http://linuxcentre.net/getiplayer/\n" .
1248      "and install in your PATH";
1249    exit 1;
1250  }
1251  else {
1252    die "Couldn't find BBC XML playlist URL in " . $browser->uri->as_string;
1253  }
1254
1255  $browser->get($playlist_xml);
1256  if (!$browser->success) {
1257    die "Couldn't download BBC XML playlist $playlist_xml: " .
1258      $browser->response->status_line;
1259  }
1260
1261  my $playlist = eval { from_xml($browser, KeyAttr => {item => 'kind'}) };
1262
1263  if ($@) {
1264    my $content = $browser->content;
1265    if ($content !~ m{</media>}) {
1266      $content .= "\n</media></item></playlist>\n";
1267    }
1268    $playlist = from_xml($$content, KeyAttr => {item => 'kind'})
1269  }
1270
1271  my $sound = ($playlist->{item}->{guidance} !~ /has no sound/);
1272
1273  my $info = ref $playlist->{item}->{media} eq 'ARRAY'
1274    ? $playlist->{item}->{media}->[0]->{connection}
1275    : $playlist->{item}->{media}->{connection};
1276
1277  $info = $playlist->{item}->{programme}->{media}->{connection} unless $info;
1278
1279  $info->{application} ||= "ondemand";
1280
1281  if (!$info->{server}) {
1282    my $id = $playlist->{item}->{mediator}->{identifier};
1283    if(!$id) { $id = $playlist->{item}->{programme}->{mediator}->{identifier}; }
1284
1285    my $stream_info_url = sprintf
1286      "http://open.live.bbc.co.uk/mediaselector/4/mtis/stream/%s", $id;
1287
1288    $browser->back();
1289    $browser->get($stream_info_url);
1290
1291    if (!$browser->success) {
1292      die "Couldn't get BBC stream info URL: " .
1293        $browser->response->status_line;
1294    }
1295
1296    my $stream_info = from_xml($browser->content);
1297
1298    if( ref $stream_info->{media} eq 'ARRAY' ){
1299      my $q = $prefs->{quality};
1300      my @media = sort { $a->{bitrate} <=> $b->{bitrate} } @{$stream_info->{media}};
1301      my @q_media = grep { $_->{bitrate} == $q || "$_->{height}x$_->{width}x$_->{bitrate}" == $q || "$_->{height}x$_->{width}" == $q } @media;
1302      if( @q_media ){ @media = @q_media; }
1303      my $cnt = @media;
1304      my $num = {high => int($cnt)-1, medium => int($cnt/2), low => 0}->{$q};
1305      $info = $media[$num]->{connection};
1306    } else {
1307      $info = $stream_info->{media}->{connection};
1308    }
1309  }
1310
1311  if( $info->{href} ){
1312    my $url = $info->{href};
1313    my @path = URI->new($url)->path_segments();
1314    return $url, @path[-1];
1315  }
1316
1317  my $data = {
1318    app      => $info->{application},
1319    tcUrl    => "rtmp://$info->{server}/$info->{application}",
1320    swfUrl   => "http://news.bbc.co.uk/player/emp/2.11.7978_8433/9player.swf",
1321    pageUrl  => $page_url,
1322    rtmp     => "rtmp://" .  $info->{server} . "/$info->{application}",
1323    playpath => $info->{identifier},
1324    flv      => title_to_filename('BBC - ' . $playlist->{title} .
1325                                ($sound ? '' : ' (no sound)'))
1326  };
1327
1328  if ($info->{authString}) {
1329    my $token = $info->{authString};
1330
1331    $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}" .
1332                   "&$token";
1333
1334    $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}"
1335            . "&$token";
1336
1337    $data->{playpath} .= "?$token";
1338  }
1339
1340  if ($info->{identifier} =~ /^secure/ or $info->{tokenIssuer}) {
1341    my $url = "http://www.bbc.co.uk/mediaselector/4/gtis?server=$info->{server}" .
1342              "&identifier=$info->{identifier}&kind=$info->{kind}" .
1343              "&application=$info->{application}&cb=123";
1344
1345    debug "Got BBC auth URL for 'secure' video: $url";
1346
1347    $browser->get($url);
1348
1349    if (my $redirect = $browser->response->header('Location')) {
1350      debug "BBC auth URL redirects to: $url";
1351      $browser->get($redirect);
1352    }
1353
1354    my $stream_auth = from_xml($browser);
1355
1356    my $token = $stream_auth->{token};
1357
1358    if (!$token) {
1359      die "Couldn't get token for 'secure' video download";
1360    }
1361
1362    $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}"
1363            . "&auth=$token"
1364            . "&aifp=v001&slist=" . $info->{identifier};
1365    $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}"
1366            . "&auth=$token"
1367            . "&aifp=v001&slist=" . $info->{identifier};
1368    $data->{playpath} .= "?auth=$token&aifp=v0001";
1369
1370    if($info->{application} eq 'live') {
1371      $data->{subscribe} = $data->{playpath};
1372      $data->{live} = 1;
1373    }
1374  }
1375
1376  return $data;
1377}
1378
13791;
1380}
1381##} blib/lib/FlashVideo/Site/Bbc.pm
1382BEGIN { $INC{'FlashVideo/Site/Bing.pm'}++; }
1383# Part of get-flash-videos. See get_flash_videos for copyright.
1384##{ blib/lib/FlashVideo/Site/Bing.pm
1385{
1386package FlashVideo::Site::Bing;
1387use strict;
1388BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1389BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
1390
1391sub find_video {
1392  my ($self, $browser, $embed_url, $prefs) = @_;
1393
1394  my $count = 0;
1395  while((my $location = $browser->response->header("Location")) && $count++ < 5) {
1396    $browser->get($location);
1397  }
1398
1399  my $title;
1400  if ($browser->content =~ /sourceFriendly:\s*'([^']+)'[\s\S]+?\s*title:\s*'([^']+)'/) {
1401    $title = "$1 - $2";
1402  }
1403
1404  my $url;
1405  if ($browser->content =~ /formatCode:\s*1003,\s*url:\s*'([^']+)'/) {
1406    $url = $1;
1407
1408    $url =~ s/\\x([0-9a-f]{2})/chr hex $1/egi;
1409  }
1410  die "Unable to extract video url" unless $url;
1411
1412  $browser->allow_redirects;
1413
1414  return $url, title_to_filename($title);
1415}
1416
14171;
1418}
1419##} blib/lib/FlashVideo/Site/Bing.pm
1420BEGIN { $INC{'FlashVideo/Site/Blip.pm'}++; }
1421# Part of get-flash-videos. See get_flash_videos for copyright.
1422##{ blib/lib/FlashVideo/Site/Blip.pm
1423{
1424package FlashVideo::Site::Blip;
1425
1426use strict;
1427BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1428BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1429
1430sub find_video {
1431  my ($self, $browser, $embed_url) = @_;
1432  my $base = "http://blip.tv";
1433
1434  my $id;
1435  if($embed_url =~ m{flash/(\d+)}) {
1436    $id = $1;
1437  } else {
1438    $browser->get($embed_url);
1439
1440    if($browser->response->is_redirect
1441        && $browser->response->header("Location") =~ m!(?:/|%2f)(\d+)!i) {
1442      $id = $1;
1443    } else {
1444      $id = ($browser->content =~ m!/rss/flash/(\d+)!)[0];
1445    }
1446  }
1447
1448  if (!$id) {
1449    if ($browser->content =~ /post_masthed_(\d+)/) {
1450      $id = $1;
1451    }
1452  }
1453
1454  if (!$id) { ($id) = ($browser->content =~ m{data-posts-id="(\d+)"}s); }
1455  if (!$id) { ($id) = ($browser->content =~ m{data-disqus-id="(\d+)"}s); }
1456  if (!$id) { ($id) = ($browser->content =~ m{content="http://[^"]-(\d+)"}s); }
1457
1458  die "No ID found\n" unless $id;
1459
1460  $browser->get("$base/rss/flash/$id");
1461
1462  my $xml = from_xml($browser);
1463
1464  my $content = $xml->{channel}->{item}->{"media:group"}->{"media:content"};
1465
1466  my $url = ref $content eq 'ARRAY' ? $content->[0]->{url} : $content->{url};
1467
1468  my $filename = title_to_filename($xml->{channel}->{item}->{title}, $url);
1469
1470  $browser->allow_redirects;
1471
1472  return $url, $filename;
1473}
1474
14751;
1476}
1477##} blib/lib/FlashVideo/Site/Blip.pm
1478BEGIN { $INC{'FlashVideo/Site/Break.pm'}++; }
1479# Part of get-flash-videos. See get_flash_videos for copyright.
1480##{ blib/lib/FlashVideo/Site/Break.pm
1481{
1482package FlashVideo::Site::Break;
1483
1484use strict;
1485BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1486BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
1487use URI::Escape;
1488
1489sub find_video {
1490  my($self, $browser, $embed_url) = @_;
1491
1492  my $video_id;
1493
1494  if ($browser->content =~ /flashVars\.icon = ["'](\w+)["']/) {
1495    $video_id = $1;
1496  }
1497  else {
1498    die "Couldn't get Break video ID";
1499  }
1500
1501  if($browser->content =~ /<meta name=['"]embed_video_url['"] content=["']([^'"]*)["']/) {
1502    $browser->get($1);
1503  }
1504
1505  if(URI->new($embed_url)->host eq "embed.break.com") {
1506    $browser->get($embed_url);
1507  }
1508
1509  if($browser->uri->host eq "embed.break.com") {
1510    if(!$browser->success && $browser->response->header('Location') !~ /sVidLoc/) {
1511      $browser->get($browser->response->header('Location'));
1512    }
1513
1514    if($browser->response->header("Location") =~ /sVidLoc=([^&]+)/) {
1515      my $url = uri_unescape($1).'?'.$video_id;
1516      my $filename = title_to_filename((split /\//, $url)[-1]);
1517
1518      return $url, $filename;
1519    }
1520  }
1521
1522  my $path = ($browser->content =~ /sGlobalContentFilePath='([^']+)'/)[0];
1523  my $filename = ($browser->content =~ /sGlobalFileName='([^']+)'/)[0];
1524
1525  die "Unable to extract path and filename" unless $path and $filename;
1526
1527  my $video_path = ($browser->content =~ /videoPath\s*(?:',|=)\s*['"]([^'"]+)/)[0];
1528
1529  $browser->allow_redirects;
1530
1531  return $video_path . $path . "/" . $filename . ".flv" . "?" . $video_id,
1532    title_to_filename($filename);
1533}
1534
15351;
1536}
1537##} blib/lib/FlashVideo/Site/Break.pm
1538BEGIN { $INC{'FlashVideo/Site/Canalvie.pm'}++; }
1539#############################################################################
1540#################################################
1541#
1542# This file was automatically generated by utils/combine-perl.pl
1543# You should edit the original files, not this
1544# combined version.
1545#
1546# The original files are available at:
1547# http://github.com/monsieurvideo/get-flash-videos
1548#
1549#################################################
1550#	Canalvie.pm												2010-11-25
1551#
1552#	Reverse-engineered using URLSnooper v2.28.01 & WinPcap 4.1.2
1553#
1554#	Stavr0
1555#
1556#
1557##{ blib/lib/FlashVideo/Site/Canalvie.pm
1558{
1559{
1560package FlashVideo::Site::Canalvie;
1561
1562use strict;
1563BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1564BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1565
1566sub find_video {
1567  my($self, $browser, $embed_url, $prefs) = @_;
1568
1569  my $check_response = sub {
1570    my ( $message ) = @_;
1571    return if $browser->success;
1572    die sprintf $message, $browser->response->code;
1573  };
1574
1575
1576  my $videoID = 0;
1577
1578  ( $videoID ) = ( $browser->content =~ /var\s+videoId\s*=\s*(\d+)\s*;/ );
1579  debug "VIDEOID = " . $videoID;
1580
1581  die "No Canalvie Video ID found" unless  $videoID;
1582
1583  my $title;
1584  ( $title ) = ( $browser->content =~ /NOM EPISODE\+LIEN ici --><a [^>]+>([^<]+)/ );
1585  debug "TITLE = " . $title . " " . title_to_filename($title, 'flv');
1586
1587  my $xmlurl = 'http://www.canalvie.com/webtele/_dyn/getVideoDataXml.jsp?videoId=' . $videoID;
1588  $browser->get($xmlurl);
1589  my $xml = from_xml($browser);
1590
1591  my $url;
1592  if ( $prefs->{quality} == "high" ) {
1593	$url = $xml->{video}->{highFlvUrl};
1594  } else {
1595  	$url = $xml->{video}->{lowFlvUrl};
1596  }
1597  debug "URL = " . $url;
1598
1599  my $ext;
1600  ( $ext ) = ( $url =~ /\.(.+)$/ );
1601
1602  die "No (high|low)FlvUrl found in XML ". $xmlurl unless $url;
1603
1604  return $url, title_to_filename($title, $ext);
1605
1606 }
1607
1608
16091;
1610}}
1611##} blib/lib/FlashVideo/Site/Canalvie.pm
1612BEGIN { $INC{'FlashVideo/Site/Canoe.pm'}++; }
1613# Part of get-flash-videos. See get_flash_videos for copyright.
1614##{ blib/lib/FlashVideo/Site/Canoe.pm
1615{
1616package FlashVideo::Site::Canoe;
1617
1618use strict;
1619BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1620BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
1621BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
1622use base 'FlashVideo::Site::Brightcove';
1623
1624sub find_video {
1625  my ($self, $browser, $embed_url) = @_;
1626
1627  my $video_id  = ($browser->content =~ /player.SetVideo.(\d+)/i)[0];
1628  my $player_id = ($browser->content =~ /player.SetPlayer.(\d+)/i)[0];
1629
1630  debug "Extracted playerId: $player_id, videoId: $video_id"
1631    if $player_id or $video_id;
1632
1633  if(!$video_id) {
1634    my $video_offset = ($browser->content =~ /player.SetVideo.\w+\[(\d+)/i)[0];
1635    $video_id = ($browser->content =~ /videos\[$video_offset\].+'(\d+)'\s*\]/)[0];
1636  }
1637
1638  die "Unable to extract Brightcove IDs from page"
1639    unless $player_id and $video_id;
1640
1641  return $self->amfgateway($browser, $player_id, { videoId => $video_id, } );
1642}
1643
1644sub can_handle {
1645  my($self, $browser, $url) = @_;
1646
1647  return $browser->content =~ /player = CanoeVideoStandalone\.create\(\);/i;
1648}
1649
16501;
1651}
1652##} blib/lib/FlashVideo/Site/Canoe.pm
1653BEGIN { $INC{'FlashVideo/Site/Cartoonnetwork.pm'}++; }
1654# Part of get-flash-videos. See get_flash_videos for copyright.
1655##{ blib/lib/FlashVideo/Site/Cartoonnetwork.pm
1656{
1657package FlashVideo::Site::Cartoonnetwork;
1658
1659use strict;
1660BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1661BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1662use POSIX();
1663
1664sub find_video {
1665  my ($self, $browser, $embed_url) = @_;
1666
1667  my $video_id;
1668  if ($browser->uri->as_string =~ /episodeID=([a-z0-9]*)/) {
1669    $video_id = $1;
1670  }
1671
1672  $browser->get("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeSearch/getEpisodesByIDs?ids=$video_id");
1673  my $xml = from_xml($browser);
1674  my $episodes = $xml->{episode};
1675  my $episode = ref $episodes eq 'ARRAY' ?
1676    (grep { $_->{id} eq $video_id } @$episodes)[0] :
1677    $episodes;
1678
1679  my $title = $episode->{title};
1680
1681  my @gmtime = gmtime;
1682  $gmtime[1] = 15 * int($gmtime[1] / 15);
1683  my $date = POSIX::strftime("%m%d%Y%H%M", @gmtime);
1684
1685  my $url;
1686  foreach my $key (keys (%{$episode->{segments}->{segment}})){
1687    my $content_id = $key;
1688    $browser->post("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeservices/getVideoPlaylist",
1689      Content  => "id=$content_id&r=$date"
1690    );
1691
1692    if ($browser->content =~ /<ref href="([^"]*)" \/>/){
1693      $url = $1;
1694    }
1695  }
1696
1697  return $url, title_to_filename($title);
1698}
1699
17001;
1701}
1702##} blib/lib/FlashVideo/Site/Cartoonnetwork.pm
1703BEGIN { $INC{'FlashVideo/Site/Cbs.pm'}++; }
1704# Part of get-flash-videos. See get_flash_videos for copyright.
1705##{ blib/lib/FlashVideo/Site/Cbs.pm
1706{
1707package FlashVideo::Site::Cbs;
1708
1709use strict;
1710BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1711BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1712
1713sub find_video {
1714  my ($self, $browser, $embed_url) = @_;
1715
1716  my $pid;
1717  if ($browser->uri->as_string =~ /pid=([^&]*)/) {
1718    $pid = $1;
1719  }
1720
1721  $browser->get("http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&MBR=true&pid=$pid");
1722
1723  my $xml = from_xml($browser->content);
1724
1725  my $items = $xml->{body}->{switch};
1726  my $item = ref $items eq 'ARRAY' ?
1727    (grep { $_->{video}->{src} =~ /^rtmp:\/\// } @$items)[0] :
1728    $items;
1729
1730  my $rtmpurl = $item->{video}->{src};
1731  $rtmpurl =~ s/<break>.*//;
1732  my $title = $item->{ref}->{title};
1733
1734  return {
1735    rtmp => $rtmpurl,
1736    flv => title_to_filename($title)
1737  };
1738}
1739
17401;
1741}
1742##} blib/lib/FlashVideo/Site/Cbs.pm
1743BEGIN { $INC{'FlashVideo/Site/Cbsnews.pm'}++; }
1744# Part of get-flash-videos. See get_flash_videos for copyright.
1745BEGIN { $INC{'FlashVideo/Site/Cnet.pm'}++; }
1746# Part of get-flash-videos. See get_flash_videos for copyright.
1747##{ blib/lib/FlashVideo/Site/Cnet.pm
1748{
1749package FlashVideo::Site::Cnet;
1750
1751use strict;
1752BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1753BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
1754
1755my $cnet_api_base = "http://api.cnet.com";
1756my $cnet_api_rest = $cnet_api_base . "/restApi/v1.0";
1757my $cnet_api_video_search = $cnet_api_rest . "/videoSearch";
1758
1759
1760sub find_video {
1761  my ($self, $browser, $embed_url) = @_;
1762
1763  my $video_id;
1764
1765  if($browser->content =~ /<param name="FlashVars" value="playerType=embedded&type=id&value=([0-9]+)" \/>/) {
1766    $video_id = $1;
1767  } elsif($browser->content =~ /assetId: '([0-9]+)',/) {
1768    $video_id = $1;
1769  } else {
1770    die "Could not find video ID; you may have to click the 'share' link on the flash player to get the permalink to the video.";
1771  }
1772
1773  return $self->get_video($browser, $video_id);
1774}
1775
1776sub get_video {
1777  my ($self, $browser, $video_id) = @_;
1778
1779  $browser->get($cnet_api_video_search . "?videoIds=" . $video_id . "&iod=videoMedia&players=RTMP");
1780
1781  my $xml = from_xml($browser->content, NoAttr => 1);
1782
1783  my $video = $xml->{"Videos"}->{"Video"};
1784
1785  my $medias = $video->{"VideoMedias"}->{"VideoMedia"};
1786
1787  my $max = 0;
1788  foreach (@{$video->{VideoMedias}->{VideoMedia}}) {
1789    if(int($_->{Width}) * int($_->{Height}) > $max){
1790      $max = int($_->{Width}) * int($_->{Height});
1791    }
1792  }
1793  my $media = (grep { (int($_->{Width}) * int($_->{Height})) eq $max } @$medias)[0];
1794  my $delivery_url = $media->{DeliveryUrl};
1795
1796  my $title = $video->{FranchiseName} . ' - ' . $video->{Title};
1797
1798  if($media->{Player} eq 'RTMP'){
1799    return {
1800      rtmp => $delivery_url,
1801      flv => title_to_filename($title)
1802    };
1803  } elsif($media->{Player} eq 'Download'){
1804    return $delivery_url, title_to_filename($title)
1805  }
1806}
1807
18081;
1809
1810}
1811##} blib/lib/FlashVideo/Site/Cnet.pm
1812##{ blib/lib/FlashVideo/Site/Cbsnews.pm
1813{
1814package FlashVideo::Site::Cbsnews;
1815
1816use strict;
1817BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1818BEGIN { no strict 'refs'; }
1819BEGIN { FlashVideo::Site::Cnet->import(); } # (added by utils/combine-perl.pl)
1820use base 'FlashVideo::Site::Cnet';
1821
1822sub find_video {
1823  my ($self, $browser, $embed_url) = @_;
1824
1825  my $video_id;
1826  if($browser->content =~ /CBSVideo\.setVideoId\(["']([0-9]+)["']\)/) {
1827    $video_id = $1;
1828  } else {
1829    die "Could not find video id. If this is a valid CBS News video, please file a bug report at http://code.google.com/p/get-flash-videos/issues";
1830  }
1831  return $self->get_video($browser, $video_id);
1832}
1833
18341;
1835}
1836##} blib/lib/FlashVideo/Site/Cbsnews.pm
1837BEGIN { $INC{'FlashVideo/Site/Channel4.pm'}++; }
1838# Part of get-flash-videos. See get_flash_videos for copyright.
1839#################################################
1840#
1841# This file was automatically generated by utils/combine-perl.pl
1842# You should edit the original files, not this
1843# combined version.
1844#
1845# The original files are available at:
1846# http://github.com/monsieurvideo/get-flash-videos
1847#
1848#################################################
1849# Thanks to Nibor for his XBMC 4od plugin - this is largely a Perl port of
1850# it.
1851##{ blib/lib/FlashVideo/Site/Channel4.pm
1852{
1853package FlashVideo::Site::Channel4;
1854
1855use strict;
1856
1857use Crypt::Blowfish_PP;
1858BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
1859BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *url_exists = \&FlashVideo::Utils::url_exists; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; *from_xml = \&FlashVideo::Utils::from_xml; }
1860use MIME::Base64;
1861
1862use constant TOKEN_DECRYPT_KEY => 'STINGMIMI';
1863
1864sub find_video {
1865  my ($self, $browser, $embed_url, $prefs) = @_;
1866
1867  my $page_url = $browser->uri->as_string;
1868
1869  my $series_and_episode;
1870  if ($browser->content =~ /<meta\ property="og:image"
1871                            \ content="\S+series-(\d+)\/episode-(\d+)/x) {
1872    $series_and_episode = sprintf "S%02dE%02d", $1, $2;
1873  }
1874
1875  my $swf_player;
1876  if ($browser->content =~ /fourodPlayerFile\s+=\s+\'(4od\S+\.swf)\'/i) {
1877    $swf_player = $1;
1878  }
1879  else {
1880     $swf_player = '4odplayer-11.21.2.swf';
1881  }
1882
1883  my $asset_id;
1884
1885  if ($page_url =~ m'(?:4od/player/|4od[^\/]*#)(\d+)') {
1886    $asset_id = $1;
1887  }
1888  else {
1889    die "Can't get asset ID";
1890  }
1891
1892  my $raw_xml = $browser->get("http://ais.channel4.com/asset/$asset_id");
1893
1894  if (!$browser->success) {
1895    die "Couldn't get asset XML: " . $browser->status_line;
1896  }
1897
1898  my $xml = from_xml($raw_xml);
1899
1900  my $stream_url = $xml->{assetInfo}->{uriData}->{streamUri};
1901  my $token      = $xml->{assetInfo}->{uriData}->{token};
1902  my $cdn        = $xml->{assetInfo}->{uriData}->{cdn};
1903
1904  my $decoded_token = decode_4od_token($token);
1905
1906  my $auth;
1907
1908  if ($cdn eq 'll') {
1909    my $ip = $xml->{assetInfo}->{uriData}->{ip};
1910    my $e  = $xml->{assetInfo}->{uriData}->{e};
1911
1912    if (defined $ip) {
1913      $auth = sprintf "e=%s&ip=%s&h=%s", $e, $ip, $decoded_token;
1914    }
1915    else {
1916      $auth = sprintf "e=%s&h=%s", $e, $decoded_token;
1917    }
1918  }
1919  else {
1920    my $fingerprint = $xml->{assetInfo}->{uriData}->{fingerprint};
1921    my $slist       = $xml->{assetInfo}->{uriData}->{slist};
1922
1923    $auth = sprintf "auth=%s&aifp=%s&slist=%s",
1924      $decoded_token, $fingerprint, $slist;
1925  }
1926
1927  my $title;
1928  my @title_components = grep defined,
1929                         map { $xml->{assetInfo}->{$_} }
1930                         qw(brandTitle episodeTitle);
1931
1932  if ($series_and_episode) {
1933    push @title_components, $series_and_episode;
1934  }
1935
1936  if (@title_components) {
1937    $title = join " - ", @title_components;
1938  }
1939
1940  my $filename = title_to_filename($title, "mp4");
1941
1942  if ($prefs->subtitles) {
1943    if (my $subtitles_url = $xml->{assetInfo}->{subtitlesFileUri}) {
1944      $subtitles_url = "http://ais.channel4.com$subtitles_url";
1945
1946      $browser->get($subtitles_url);
1947
1948      if (!$browser->success) {
1949        info "Couldn't download 4od subtitles: " . $browser->status_line;
1950      }
1951
1952      my $subtitles_file = title_to_filename($title, "srt");
1953      convert_sami_subtitles_to_srt($browser->content, $subtitles_file);
1954
1955      info "Saved subtitles to $subtitles_file";
1956    }
1957    else {
1958      debug("Subtitles requested for '$title' but none available.");
1959    }
1960  }
1961
1962  my $rtmp_url;
1963
1964  if ($stream_url =~ /(.*?)mp4:/) {
1965    $rtmp_url = $1;
1966  }
1967
1968  $rtmp_url =~ s{\.com/}{.com:1935/};
1969  $rtmp_url .= "?ovpfv=1.1&$auth";
1970
1971  my $app;
1972  if ($stream_url =~ /.com\/(.*?)mp4:/) {
1973    $app = $1;
1974    $app .= "?ovpfv=1.1&$auth";
1975  }
1976
1977  my $playpath;
1978  if ($stream_url =~ /.*?(mp4:.*)/) {
1979    $playpath = $1;
1980    $playpath .= "?$auth";
1981  }
1982
1983  my $swf_player_url = url_exists($browser, "http://www.channel4.com/static/programmes/asset/flash/swf/$swf_player");
1984
1985  if (!$swf_player_url) {
1986     die "swf url not found";
1987  }
1988
1989  return {
1990    flv      => $filename,
1991    rtmp     => $rtmp_url,
1992    flashVer => '"WIN 11,0,1,152"',
1993    swfVfy   => "$swf_player_url",
1994    conn     => 'Z:',
1995    playpath => $playpath,
1996    pageUrl  => $page_url,
1997    app      => $app,
1998  };
1999}
2000
2001sub decode_4od_token {
2002  my $encrypted_token = shift;
2003
2004  $encrypted_token = decode_base64($encrypted_token);
2005
2006  my $blowfish = Crypt::Blowfish_PP->new(TOKEN_DECRYPT_KEY);
2007
2008  my $decrypted_token = '';
2009
2010  my $position = 0;
2011
2012  while ( $position < length $encrypted_token) {
2013    $decrypted_token .= $blowfish->decrypt(substr $encrypted_token, $position, 8);
2014    $position += 8;
2015  }
2016
2017  my $npad = unpack("c", substr($decrypted_token, -1));
2018  if ($npad > 0 && $npad < 9) {
2019    $decrypted_token = substr($decrypted_token, 0, length($decrypted_token)-$npad);
2020  }
2021  return $decrypted_token;
2022}
2023
20241;
2025}
2026##} blib/lib/FlashVideo/Site/Channel4.pm
2027BEGIN { $INC{'FlashVideo/Site/Channel5.pm'}++; }
2028# Part of get-flash-videos. See get_flash_videos for copyright.
2029##{ blib/lib/FlashVideo/Site/Channel5.pm
2030{
2031package FlashVideo::Site::Channel5;
2032
2033use strict;
2034BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2035BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2036use MIME::Base64;
2037
2038my $encode_rates = {
2039     "low" => 480,
2040     "medium" => 800,
2041     "medium2" => 1200,
2042     "high" => 1500 };
2043
2044sub find_video {
2045  my ($self, $browser, $embed_url, $prefs) = @_;
2046
2047  my $metadata = { };
2048  my ($video_id, $player_id);
2049
2050  $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0];
2051  $metadata->{videoplayer} = ($browser->content =~ /videoPlayer=ref:(C\d+)/i)[0];
2052  $metadata->{publisherId} = ($browser->content =~ /publisherID=(\d+)/i)[0];
2053
2054  $player_id ||= ($browser->content =~ /<param name=["']?playerID["']? value=["'](\d+) ?["']/i)[0];
2055  $metadata->{videoplayer} ||= ($browser->content =~ /param name=["']?\@videoPlayer["']? value=["']?(\d+)["']?/i)[0];
2056  $metadata->{publisherId} ||= ($browser->content =~ /param name=["']?publisherID["']? value=["']?(\d+)["']?/i)[0];
2057
2058  $player_id ||= ($browser->content =~ /flashVars.*playerID=(\d+)/i)[0];
2059
2060  if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) {
2061    $player_id = $2;
2062  }
2063
2064  $metadata->{sessionId} = ($browser->cookie_jar->as_string =~ /session=([0-9a-f]*);/)[0];
2065
2066  for my $url($browser->uri->as_string, $embed_url) {
2067
2068    if($url =~ /(?:playerID|bcpid)=?(\d+)/i) {
2069      $player_id ||= $1;
2070    }
2071  }
2072
2073  debug "Extracted playerId: $player_id, sessionId: $metadata->{sessionId} videoplayer: $metadata->{videoplayer} publisherId: $metadata->{publisherId} "
2074    if $player_id or $video_id;
2075
2076  die "Unable to extract Brightcove IDs from page" unless $player_id;
2077
2078  return $self->amfgateway($browser, $player_id, $metadata, $prefs);
2079}
2080
2081sub amfgateway {
2082  my($self, $browser, $player_id, $metadata, $prefs) = @_;
2083
2084  my $has_amf_packet = eval { require Data::AMF::Packet };
2085  if (!$has_amf_packet) {
2086    die "Must have Data::AMF::Packet installed to download Brightcove videos";
2087  }
2088
2089  my $page_url = $browser->uri;
2090  my $base_url = "" . $page_url;
2091
2092
2093  my $amf0_formatter = Data::AMF::Formatter->new(version =>0);
2094  my $amf3_formatter = Data::AMF::Formatter->new(version =>3);
2095  my @amf_pkt;
2096
2097
2098  $amf_pkt[0] = decode_base64(<<EOF1);
2099AAMAAAABAEZjb20uYnJpZ2h0Y292ZS5leHBlcmllbmNlLkV4cGVyaWVuY2VSdW50aW1lRmFjYWRl
2100LmdldERhdGFGb3JFeHBlcmllbmNlAAIvMQAA
2101EOF1
2102
2103  $amf_pkt[2] = decode_base64(<<EOF2);
2104CgAAAAI=
2105EOF2
2106
2107  $amf_pkt[3] = $amf0_formatter->format($metadata->{sessionId});
2108
2109  $amf_pkt[4] = decode_base64(<<EOF3);
2110EQpjY2NvbS5icmlnaHRjb3ZlLmV4cGVyaWVuY2UuVmlld2VyRXhwZXJpZW5jZVJlcXVlc3QhY29u
2111dGVudE92ZXJyaWRlcwdVUkwZZXhwZXJpZW5jZUlkEVRUTFRva2VuE3BsYXllcktleRlkZWxpdmVy
2112eVR5cGUJAwEKgQNTY29tLmJyaWdodGNvdmUuZXhwZXJpZW5jZS5Db250ZW50T3ZlcnJpZGUXY29u
2113dGVudFR5cGUTY29udGVudElkGWNvbnRlbnRSZWZJZBtmZWF0dXJlZFJlZklkG2NvbnRlbnRSZWZJ
2114ZHMVZmVhdHVyZWRJZBVjb250ZW50SWRzDXRhcmdldAQABX/////gAAAA
2115EOF3
2116
2117  $amf_pkt[5] = $amf3_formatter->format($metadata->{videoplayer});
2118
2119  $amf_pkt[6] = decode_base64(<<EOF4);
2120AQEFf////+AAAAABBhd2aWRlb1BsYXllcg==
2121EOF4
2122
2123  $amf_pkt[7] = $amf3_formatter->format($base_url);
2124
2125  $amf_pkt[8] = decode_base64(<<EOF5);
2126BUI4gZvSwQAABgEGAQV/////4AAAAA==
2127EOF5
2128  my $experianceid = $amf3_formatter->format($player_id);
2129  $amf_pkt[8] = $experianceid . substr($amf_pkt[8], 7);
2130
2131
2132  $amf_pkt[1] = pack('n', length(join('',@amf_pkt[2..8])));
2133
2134  my $data = join('',@amf_pkt[0..8]);
2135
2136
2137
2138
2139
2140  $browser->post(
2141    "http://c.brightcove.com/services/messagebroker/amf?playerid=$player_id",
2142    Content_Type => "application/x-amf",
2143    Content => $data
2144  );
2145
2146  die "Failed to post to Brightcove AMF gateway"
2147    unless $browser->response->is_success;
2148
2149  my $packet = Data::AMF::Packet->deserialize($browser->content);
2150
2151  if($self->debug) {
2152    require Data::Dumper;
2153    debug Data::Dumper::Dumper($packet);
2154  }
2155
2156  if ( ref  $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions} ne 'ARRAY') {
2157    die "Unexpected data from AMF gateway";
2158  }
2159
2160  my @found;
2161  for (@{$packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions}}) {
2162    if ($_->{defaultURL}) {
2163      push @found, $_;
2164    }
2165  }
2166
2167  my $mediaId = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaId};
2168  my $seasonnumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{seasonnumber};
2169  my $episodenumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{episodenumber};
2170  my $show = ($page_url =~ m!/shows/([^/]+)/!i)[0];
2171  my $episode = ($page_url =~ m!/episodes/([^/]+)!i)[0];
2172  my $filehead = $show . "_Series" . $seasonnumber;
2173  if ( $show ne $episode ) {
2174    $filehead = $filehead . "_Episode" . $episodenumber . "_" . $episode;
2175  }
2176  my $encode_rate = $encode_rates->{$prefs->{quality}};
2177  if (! defined $encode_rate ) {
2178    $encode_rate = $prefs->{quality};
2179  }
2180
2181  my @rtmpdump_commands;
2182
2183  for my $d (@found) {
2184
2185    my $rate = ($d->{defaultURL} =~ /H264-(\d+)-16x9/i)[0];
2186    next if $encode_rate != $rate;
2187    my $host = ($d->{defaultURL} =~ m!rtmpe://(.*?)/!)[0];
2188    my $file = ($d->{defaultURL} =~ /^[^&]+&(.*)$/)[0];
2189    my $app = ($d->{defaultURL} =~ m!//.*?/(.*?)/&!)[0];
2190    my $filename = $filehead . "_" . $rate;
2191
2192    $app .= "?videoId=$mediaId&lineUpId=&pubId=$metadata->{publisherId}&playerId=$player_id&affiliateId=";
2193
2194    my $args = {
2195      app => $app,
2196      pageUrl => $page_url,
2197      swfVfy => "http://admin.brightcove.com/viewer/us1.24.04.08.2011-01-14072625/connection/ExternalConnection_2.swf",
2198      tcUrl => "rtmpe://$host:1935/$app",
2199      rtmp => "$d->{defaultURL}",
2200      playpath => $file,
2201      flv => "$filename.flv",
2202    };
2203
2204    if ($d->{publisherName} and $d->{displayName}) {
2205      $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}");
2206    }
2207
2208
2209    push @rtmpdump_commands, $args;
2210  }
2211
2212  if (@rtmpdump_commands > 1) {
2213    return \@rtmpdump_commands;
2214  }
2215  else {
2216    return $rtmpdump_commands[-1];
2217  }
2218}
2219
2220sub can_handle {
2221  my($self, $browser, $url) = @_;
2222
2223  return 1 if $url && URI->new($url)->host =~ /\.channel5\.com$/;
2224
2225  return $browser->content =~ /(playerI[dD]|brightcove.player.create)/
2226    && $browser->content =~ /brightcove/i;
2227}
2228
22291;
2230}
2231##} blib/lib/FlashVideo/Site/Channel5.pm
2232BEGIN { $INC{'FlashVideo/Site/Collegehumor.pm'}++; }
2233# Part of get-flash-videos. See get_flash_videos for copyright.
2234##{ blib/lib/FlashVideo/Site/Collegehumor.pm
2235{
2236package FlashVideo::Site::Collegehumor;
2237
2238use strict;
2239BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2240BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
2241
2242sub find_video {
2243  my ($self, $browser, $embed_url) = @_;
2244  my $base = "http://www.collegehumor.com/moogaloop";
2245
2246  my $id;
2247  if($browser->content =~ /video:(\d+)/) {
2248    $id = $1;
2249  } elsif($embed_url =~ m![/:](\d+)!) {
2250    $id = $1;
2251  }
2252  die "No ID found\n" unless $id;
2253
2254  $browser->get("$base/video:$id");
2255
2256  my $xml = from_xml($browser);
2257
2258  my $title = $xml->{video}->{caption};
2259  $title = extract_title($browser) if ref $title;
2260
2261  return $xml->{video}->{file}, title_to_filename($title);
2262}
2263
22641;
2265}
2266##} blib/lib/FlashVideo/Site/Collegehumor.pm
2267BEGIN { $INC{'FlashVideo/Site/Ctv.pm'}++; }
2268# Part of get-flash-videos. See get_flash_videos for copyright.
2269#################################################
2270#
2271# This file was automatically generated by utils/combine-perl.pl
2272# You should edit the original files, not this
2273# combined version.
2274#
2275# The original files are available at:
2276# http://github.com/monsieurvideo/get-flash-videos
2277#
2278#################################################
2279#
2280#	Handler module for CTV Canadian broadcaster
2281#	- Requires RTMPDUMP
2282#	- Expects an URL in the form of: http://watch.ctv.ca/ $show / $season / $episode /
2283#	- Each show is split in clips intersected with commercial breaks, so there will be several calls to RTMPDUMP
2284#	- Streams are restricted to Canadian ISPs
2285#
2286#	Stavr0
2287#
2288##{ blib/lib/FlashVideo/Site/Ctv.pm
2289{
2290package FlashVideo::Site::Ctv;
2291
2292use strict;
2293BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2294BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
2295
2296sub find_video {
2297  my($self, $browser, $page_url) = @_;
2298
2299  my $entityid = ($browser->content =~ /<meta name="EntityId" content="(\d+)"/i)[0];
2300  debug "EntityID = " . $entityid;
2301
2302  die "Couldn't find EntityId in <meta> tags" unless $entityid;
2303
2304  $browser->get("http://watch.ctv.ca/AJAX/ClipLookup.aspx?callfunction=Playlist.GetInstance.AddEpisodeClipsAfter&episodeid=$entityid&maxResults=99");
2305  die "Couldn't download playlist: " . $browser->response->status_line
2306    if !$browser->success;
2307
2308  my $plist = $browser->content;
2309  my @found;
2310  while ($plist =~ /(videoArray\.push[^}]+} \) \);)/gi) {
2311    push @found, ($1 =~ /Format\:'FLV', ClipId\:'(\d+)'/i);
2312  }
2313
2314  my @rtmpdump_commands;
2315
2316  for my $clipid (@found) {
2317    debug "clipID = $clipid";
2318    my $rand =  int rand 999999;
2319    $browser->get("http://esi.ctv.ca/datafeed/flv/urlgenjs.aspx?vid=$clipid&timeZone=-4&random=$rand");
2320
2321    if ($browser->content =~ /(rtmpe\:\/\/[^\']+)/) {
2322      my $rtmp = $1;
2323      my $tcurl = ($rtmp =~ /\?(auth=.+)/ )[0];
2324      my $filename =  ($rtmp =~ /([^\?\/]+)\?/ )[0];
2325      $filename =~ s/\.mp4/\.flv/;
2326
2327      debug "$rtmp, $tcurl, $filename";
2328
2329      push @rtmpdump_commands, {
2330        app => "ondemand?$tcurl",
2331        pageUrl => $page_url,
2332        swfUrl => "http://watch.ctv.ca/Flash/player.swf?themeURL=http://watch.ctv.ca/themes/CTV/player/theme.aspx",
2333        tcUrl => "rtmpe://cp45924.edgefcs.net/ondemand?$tcurl",
2334        auth => ($rtmp =~ /auth=([^&]+)/)[0],
2335        rtmp => $rtmp,
2336        playpath => "mp4:" . ($rtmp =~ /ondemand\/(.+)/)[0],
2337        flv => $filename,
2338      };
2339    } elsif($browser->content =~ /geoblock/) {
2340      die "CTV returned geoblock (content not available in your country)\n";
2341    }
2342  }
2343
2344  return \@rtmpdump_commands;
2345}
2346
2347sub can_handle {
2348  my($self, $browser, $url) = @_;
2349  return $url =~ m{watch\.ctv\.ca};
2350}
2351
23521;
2353}
2354##} blib/lib/FlashVideo/Site/Ctv.pm
2355BEGIN { $INC{'FlashVideo/Site/Dailymotion.pm'}++; }
2356# Part of get-flash-videos. See get_flash_videos for copyright.
2357##{ blib/lib/FlashVideo/Site/Dailymotion.pm
2358{
2359package FlashVideo::Site::Dailymotion;
2360
2361use strict;
2362BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2363BEGIN { no strict 'refs'; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
2364use URI::Escape;
2365
2366sub find_video {
2367  my ($self, $browser, $embed_url, $prefs) = @_;
2368
2369  if ($browser->content =~ /content.is.not.available.for.your.country/i) {
2370    error "Can't (yet) download this video because it's not available " .
2371          "in your area";
2372    exit 1;
2373  }
2374
2375  $browser->allow_redirects;
2376
2377  $browser->content =~ /<h1[^>]*>(.*?)<\//;
2378  my $filename = title_to_filename($1);
2379
2380  my $video;
2381  if ($browser->content =~ /"video", "([^"]+)/) {
2382    $video = uri_unescape($1);
2383  }
2384  if (!$video && $browser->content =~ /"sequence", *"([^"]+)/) {
2385    my $data = json_unescape(uri_unescape($1));
2386    my ($low) = $data =~ /"sdURL" *: *"([^"]+)"/i;
2387    my ($high) = $data =~ /"hqURL" *: *"([^"]+)"/i;
2388    if($data =~ /"videoTitle" *: *"([^"]+)"/i){
2389      my $title = uri_unescape($1);
2390      $title =~ s/\+/ /g;
2391      $filename = title_to_filename($title);
2392    }
2393    if( $prefs->{quality} == 'high' && $high ){ $video = $high; }
2394    elsif( $low ){ $video = $low; }
2395  }
2396  if(!$video) {
2397    if ($embed_url !~ m!/swf/!) {
2398      $browser->uri =~ m!video(?:%2F|/)([^_]+)!;
2399      $embed_url = "http://www.dailymotion.com/swf/$1";
2400    }
2401
2402    $browser->get($embed_url);
2403
2404    die "Must have Compress::Zlib for embedded Dailymotion videos\n"
2405      unless eval { require Compress::Zlib; };
2406
2407    my $data = Compress::Zlib::uncompress(substr $browser->content, 8);
2408
2409    $data =~ /\{\{video\}\}\{\{(.*?)\}\}/;
2410    $video = $1;
2411
2412    if($data =~ /videotitle=([^&]+)/) {
2413      $filename = title_to_filename(uri_unescape($1));
2414    }
2415  }
2416
2417  if(!$video) {
2418    my($package, $possible_url) = FlashVideo::URLFinder->find_package($browser->uri, $browser);
2419
2420    if($package ne __PACKAGE__) {
2421      return $package->find_video($browser, $possible_url, $prefs);
2422    }
2423  }
2424
2425  die "Couldn't find video parameter." unless $video;
2426
2427  my @streams;
2428  for(split /\|\|/, $video) {
2429    my($path, $type) = split /@@/;
2430
2431    my($width, $height) = $path =~ /(\d+)x(\d+)/;
2432
2433    push @streams, {
2434      width  => $width,
2435      height => $height,
2436      url    => URI->new_abs($path, $browser->uri)->as_string
2437    };
2438  }
2439
2440  my $url = (sort { $b->{width} <=> $a->{width} } @streams)[0]->{url};
2441
2442  return $url, $filename;
2443}
2444
24451;
2446}
2447##} blib/lib/FlashVideo/Site/Dailymotion.pm
2448BEGIN { $INC{'FlashVideo/Site/Daum.pm'}++; }
2449# Part of get-flash-videos. See get_flash_videos for copyright.
2450##{ blib/lib/FlashVideo/Site/Daum.pm
2451{
2452package FlashVideo::Site::Daum;
2453
2454use strict;
2455BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2456BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2457use HTML::Entities qw(decode_entities);
2458
2459sub find_video {
2460  my ($self, $browser) = @_;
2461
2462  my $video_id = get_video_id($browser);
2463  debug "Video ID: $video_id";
2464
2465  my $video_title = get_video_title($browser, $video_id);
2466  debug "Video title: $video_title";
2467
2468  my $video_url = get_video_url($browser, $video_id);
2469  debug "Video URL: $video_url";
2470
2471  return $video_url, title_to_filename($video_title);
2472}
2473
2474
2475sub is_valid_video_id {
2476  my ($video_id) = @_;
2477
2478  return if !defined $video_id;
2479
2480  return if length $video_id != 12;
2481
2482  return if $video_id !~ /\$$/xms;
2483
2484  return 1;
2485}
2486
2487sub get_video_id {
2488  my ($browser) = @_;
2489
2490  my $singer_url
2491    = quotemeta 'http://media.daum.net/entertain/showcase/singer/';
2492  my $singer_url_pattern = qr{^ $singer_url .* [#] (\d+) $}xmsi;
2493  if ( $browser->uri()->as_string() =~ $singer_url_pattern ) {
2494    my $id = $1;
2495    return get_video_id_for_singer($browser, $id);
2496  }
2497
2498  if ( $browser->uri()->as_string() =~ /[#] clipid = (\d+)/xmsi ) {
2499    my $url = 'http://tvpot.daum.net/clip/ClipView.do?clipid=' . $1;
2500    $browser->get($url);
2501    if ( !$browser->success() ) {
2502      die "Cannot fetch the document identified by the given URL: $url\n";
2503    }
2504  }
2505
2506  my $document = $browser->content();
2507
2508  my $flv_player_url = quotemeta 'http://flvs.daum.net/flvPlayer.swf';
2509  my $video_id_pattern_1 = qr{['"] $flv_player_url [?] vid = ([^'"&]+)}xmsi;
2510
2511  my $function_name      = quotemeta 'Story.UI.PlayerManager.createViewer';
2512  my $video_id_pattern_2 = qr{$function_name [(] '(.+?)' [)]}xms;
2513
2514  if (    $document !~ $video_id_pattern_1
2515       && $document !~ $video_id_pattern_2 )
2516  {
2517    die "Cannot find video ID from the document.\n";
2518  }
2519  my $video_id = $1;
2520
2521  $video_id =~ s/\s+//xmsg;
2522
2523  die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id);
2524
2525  return $video_id;
2526}
2527
2528sub get_video_id_for_singer {
2529  my ($browser, $id) = @_;
2530
2531  my $document = $browser->content();
2532
2533  my $video_id_pattern = qr{id:'$id', \s* vid:'(.+?)'}xms;
2534  if ( $document !~ $video_id_pattern ) {
2535    die "Cannot find video ID from the document.\n";
2536  }
2537  my $video_id = $1;
2538
2539  $video_id =~ s/\s+//xmsg;
2540
2541  die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id);
2542
2543  return $video_id;
2544}
2545
2546sub get_video_title {
2547  my ($browser, $video_id) = @_;
2548
2549  my $query_url = "http://tvpot.daum.net/clip/ClipInfoXml.do?vid=$video_id";
2550
2551  $browser->get($query_url);
2552  if ( !$browser->success() ) {
2553    die "Cannot fetch the document identified by the given URL: $query_url\n";
2554  }
2555
2556  my $document = $browser->content();
2557
2558  my $video_title_pattern
2559    = qr{<TITLE> <!\[CDATA \[ (.+?) \] \]> </TITLE>}xmsi;
2560  if ( $document !~ $video_title_pattern ) {
2561    die "Cannot find video title from the document.\n";
2562  }
2563  my $video_title = $1;
2564
2565  $video_title = decode_entities($video_title);
2566
2567  return $video_title;
2568}
2569
2570sub get_video_url {
2571  my ($browser, $video_id) = @_;
2572
2573  my $query_url
2574    = 'http://stream.tvpot.daum.net/fms/pos_query2.php'
2575    . '?service_id=1001&protocol=http&out_type=xml'
2576    . "&s_idx=$video_id";
2577
2578  $browser->get($query_url);
2579  if ( !$browser->success() ) {
2580    die "Cannot fetch the document identified by the given URL: $query_url\n";
2581  }
2582
2583  my $document = $browser->content();
2584
2585  my $video_url_pattern = qr{movieURL = "(.+?)"}xmsi;
2586  if ( $document !~ $video_url_pattern ) {
2587    die "Cannot find video URL from the document.\n";
2588  }
2589  my $video_url = $1;
2590
2591  return $video_url;
2592}
2593
25941;
2595}
2596##} blib/lib/FlashVideo/Site/Daum.pm
2597BEGIN { $INC{'FlashVideo/Site/Divxstage.pm'}++; }
2598# Part of get-flash-videos. See get_flash_videos for copyright.
2599##{ blib/lib/FlashVideo/Site/Divxstage.pm
2600{
2601package FlashVideo::Site::Divxstage;
2602
2603use strict;
2604BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2605BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; }
2606use URI;
2607
2608sub find_video {
2609  my ($self, $browser, $embed_url) = @_;
2610
2611  my ($file) = ($browser->content =~ /flashvars.file\s*=\s*"([a-f0-9]+)"/);
2612  my ($filekey) = ($browser->content =~ /flashvars.filekey\s*=\s*"([.\-a-f0-9]+)"/);
2613
2614  my ($filename) = title_to_filename(extract_title($browser));
2615  $filename =~ s/_-_DivxStage//i;
2616
2617  my %query_params = (
2618    'codes'=>'1',
2619    'file'=>$file,
2620    'key'=>$filekey,
2621    'pass'=>'undefined',
2622    'user'=>'undefined',);
2623
2624  info "Sending query to DivxStage Player API.";
2625
2626  my $uri = URI->new( "http://www.divxstage.eu/api/player.api.php" );
2627  $uri->query_form(%query_params);
2628
2629  my $contents = $browser->get($uri)->content;
2630  my ($url) = ($contents =~ /url=(.*?)&/);
2631
2632  die "Couldn't find video URL from the player API." unless $url;
2633
2634  info "Got the real video URL: ".$url;
2635  $filename ||= ($contents =~ /title=(.*?)&/)[0]; #probably the most reliable source of title
2636  $filename ||= get_video_filename();
2637
2638  return $url, $filename;
2639}
2640
26411;
2642}
2643##} blib/lib/FlashVideo/Site/Divxstage.pm
2644BEGIN { $INC{'FlashVideo/Site/Ehow.pm'}++; }
2645# Part of get-flash-videos. See get_flash_videos for copyright.
2646##{ blib/lib/FlashVideo/Site/Ehow.pm
2647{
2648package FlashVideo::Site::Ehow;
2649
2650use strict;
2651BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2652BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2653use URI::Escape;
2654
2655sub find_video {
2656  my ($self, $browser) = @_;
2657
2658  my $uri;
2659  if ($browser->content =~ /source=(.*?)[ &]/) {
2660    $uri = $1;
2661  }
2662  else {
2663    die "Couldn't extract video location from page";
2664  }
2665
2666  my $title;
2667  if ($browser->content =~ /<h1[^>]* class="[^"]*articleTitle[^"]*"[^>]*>(.*?)<\/h1>/x) {
2668    $title = $1;
2669  }
2670
2671  if($uri =~ /^http:/) {
2672    return $uri, title_to_filename($title);
2673  }
2674	elsif($uri =~ /http:%3A/) {
2675		$uri = uri_unescape($1);
2676		if ($browser->content =~ /<a[^>]*>(.*?)<\/a>/) {
2677			$title = $1;
2678		}
2679		return $uri, title_to_filename($title);
2680	}
2681	else {
2682		die "Couldn't extract Flash video URL from embed page";
2683	}
2684}
2685
2686
26871;
2688}
2689##} blib/lib/FlashVideo/Site/Ehow.pm
2690BEGIN { $INC{'FlashVideo/Site/Escapistmagazine.pm'}++; }
2691# Part of get-flash-videos. See get_flash_videos for copyright.
2692BEGIN { $INC{'FlashVideo/JSON.pm'}++; }
2693##{ blib/lib/FlashVideo/JSON.pm
2694{
2695package FlashVideo::JSON;
2696
2697use strict;
2698use Exporter;use base 'Exporter';
2699our @EXPORT = qw(from_json);
2700
2701my $number = qr{(?:-?\b(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b)};
2702my $oneChar = qr{(?:[^\0-\x08\x0a-\x1f\"\\]|\\(?:["/\\bfnrt]|u[0-9A-Fa-f]{4}))};
2703my $string = qr{(?:"$oneChar*")};
2704my $jsonToken = qr{(?:false|true|null|[\{\}\[\]]|$number|$string)};
2705my $escapeSequence = qr{\\(?:([^u])|u(.{4}))};
2706
2707my %escapes = (
2708  '\\' => '\\',
2709  '"' => '"',
2710  '/' => '/',
2711  'b' => "\b",
2712  'f' => "\f",
2713  'n' => "\xA",
2714  'r' => "\xD",
2715  't' => "\t"
2716);
2717
2718sub from_json {
2719  my($in) = @_;
2720
2721  my @tokens = $in =~ /$jsonToken/go;
2722  my $result = $tokens[0] eq '{' ? {} : [];
2723  shift @tokens if $tokens[0] =~ /^[\[\{]/;
2724
2725  my $key; # key to use for next value
2726  my @stack = $result;
2727  for my $t(@tokens) {
2728    my $ft = substr $t, 0, 1;
2729    my $cont = $stack[0];
2730
2731    if($ft eq '"') {
2732      my $s = substr $t, 1, length($t) - 2;
2733      $s =~ s/$escapeSequence/$1 ? $escapes{$1} : chr hex $2/geo;
2734      if(!defined $key) {
2735        if(ref $cont eq 'ARRAY') {
2736          $cont->[@$cont] = $s;
2737        } else {
2738          $key = $s;
2739          next; # need to save $key
2740        }
2741      } else {
2742        $cont->{$key} = $s;
2743      }
2744    } elsif($ft eq '[' || $ft eq '{') {
2745      unshift @stack,
2746        (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) = $ft eq '[' ? [] : {};
2747    } elsif($ft eq ']' || $ft eq '}') {
2748      shift @stack;
2749    } else {
2750      (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) =
2751          $ft eq 'f' ? 0 # false
2752        : $ft eq 'n' ? undef # null
2753        : $ft eq 't' ? 1 # true
2754        : $t; # sign or digit
2755    }
2756    undef $key;
2757  }
2758
2759  return $result;
2760}
2761
27621;
2763}
2764##} blib/lib/FlashVideo/JSON.pm
2765##{ blib/lib/FlashVideo/Site/Escapistmagazine.pm
2766{
2767package FlashVideo::Site::Escapistmagazine;
2768
2769use strict;
2770BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2771BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2772BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
2773BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
2774
2775sub find_video {
2776  my ($self, $browser, $embed_url) = @_;
2777  my $title;
2778	my $url;
2779	if ($browser->content =~ /<div[^>]*class=['"]name['"]>(.*?)<\/div>/) {
2780		$title = $1;
2781		$title =~ s/<[^>]*>//g;
2782	} else {
2783		$title = extract_title($browser);
2784	}
2785
2786	my $config_url;
2787	if ($browser->content =~ /<param name=['"]flashvars['"] value=['"]config=([^'"]*)['"]/) {
2788		$config_url = $1;
2789	} else {
2790		die "No Video Info URL Found\n";
2791	}
2792
2793	$browser->add_header(Accept => '*/*');
2794	$browser->get("$config_url");
2795	my $replaced = $browser->content;
2796	$replaced =~ s/'/"/g;
2797	my $json = from_json($replaced);
2798
2799	my $item;
2800	for $item (@{$json->{playlist}}) {
2801		if ($item->{eventCategory} eq "Video") {
2802			$url = $item->{url};
2803		}
2804	}
2805	return $url, title_to_filename($title);
2806}
2807}
2808##} blib/lib/FlashVideo/Site/Escapistmagazine.pm
2809BEGIN { $INC{'FlashVideo/Site/Expertvillage.pm'}++; }
2810# Part of get-flash-videos. See get_flash_videos for copyright.
2811##{ blib/lib/FlashVideo/Site/Expertvillage.pm
2812{
2813package FlashVideo::Site::Expertvillage;
2814
2815use strict;
2816BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2817BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2818use URI::Escape;
2819
2820sub find_video {
2821  my ($self, $browser) = @_;
2822
2823  my($fn) = $browser->content =~ /SWFObject\(['"][^'"]+flv=([^'"]+)/;
2824  my $embedvars = uri_unescape($browser->content =~ /embedvars['"],\s*['"]([^'"]+)/);
2825  die "Unable to find video info" unless $fn and $embedvars;
2826
2827  my($title) = $browser->content =~ m{<h1[^>]*>(.*)</h1>}s;
2828  my $filename = title_to_filename($title);
2829
2830  $browser->get("$embedvars?fn=$fn");
2831  die "Unable to get emebdding info" if $browser->response->is_error;
2832
2833  my $url = uri_unescape($browser->content =~ /source=([^&]+)/);
2834  die "Unable to find video URL" unless $url;
2835
2836  return $url, $filename;
2837}
2838
28391;
2840}
2841##} blib/lib/FlashVideo/Site/Expertvillage.pm
2842BEGIN { $INC{'FlashVideo/Site/Filebox.pm'}++; }
2843# Part of get-flash-videos. See get_flash_videos for copyright.
2844#################################################
2845#
2846# This file was automatically generated by utils/combine-perl.pl
2847# You should edit the original files, not this
2848# combined version.
2849#
2850# The original files are available at:
2851# http://github.com/monsieurvideo/get-flash-videos
2852#
2853#################################################
2854
2855##{ blib/lib/FlashVideo/Site/Filebox.pm
2856{
2857package FlashVideo::Site::Filebox;
2858
2859use strict;
2860BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2861BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; }
2862
2863sub find_video {
2864  my ($self, $browser, $embed_url) = @_;
2865
2866  my $pause = 5; #if we don't pause, we don't get the proper video page
2867  info 'Pausing for '.$pause.' seconds (or the server won\'t respond)...';
2868  sleep($pause);
2869
2870  my $btn_id = 'btn_download'; #the ID of the button to submit the form
2871  for my $form ($browser->forms) {
2872    if ($form->find_input('#'.$btn_id)){
2873      info 'Submitting form to get real video page.';
2874      $browser->request($form->click('#'.$btn_id)); #submit to get the real page
2875    }
2876  }
2877
2878  my ($filename) = ($browser->content =~ /product_file_name=(.*?)[&'"]/);
2879  my ($url) = ($browser->content =~ /product_download_url=(.*?)[&'"]/);
2880
2881  return $url, $filename;
2882}
2883
28841;
2885}
2886##} blib/lib/FlashVideo/Site/Filebox.pm
2887BEGIN { $INC{'FlashVideo/Site/Flickr.pm'}++; }
2888# Part of get-flash-videos. See get_flash_videos for copyright.
2889##{ blib/lib/FlashVideo/Site/Flickr.pm
2890{
2891package FlashVideo::Site::Flickr;
2892
2893use strict;
2894BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2895BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
2896use URI::Escape;
2897
2898my $get_mtl = "http://www.flickr.com/apps/video/video_mtl_xml.gne?v=x";
2899
2900sub find_video {
2901  my ($self, $browser, $embed_url) = @_;
2902
2903  my($id) = $browser->content =~ /photo_id=(\d+)/;
2904  my($secret) = $browser->content =~ /photo_secret=(\w+)/;
2905
2906  die "No video ID found\n" unless $id;
2907
2908  $browser->get($get_mtl . "&photo_id=$id&secret=$secret&olang=en-us&noBuffer=null&bitrate=700&target=_self");
2909
2910  my $xml = from_xml($browser);
2911
2912  my $guid = $self->make_guid;
2913  my $video_id = $xml->{Data}->{Item}->{id}->{content};
2914  my $playlist_url = $xml->{Playlist}->{TimelineTemplates}->{Timeline}
2915    ->{Metadata}->{Item}->{playlistUrl}->{content};
2916
2917  die "No video ID or playlist found" unless $video_id and $playlist_url;
2918
2919  $browser->get($playlist_url
2920    . "?node_id=$video_id&secret=$secret&tech=flash&mode=playlist"
2921    . "&lq=$guid&bitrate=700&rd=video.yahoo.com&noad=1");
2922
2923  $xml = eval { XML::Simple::XMLin($browser->content) };
2924  die "Failed parsing XML: $@" if $@;
2925
2926  $xml = $xml->{"SEQUENCE-ITEM"};
2927  die "XML not as expected" unless $xml;
2928
2929  my $filename = title_to_filename($xml->{META}->{TITLE});
2930  my $url = $xml->{STREAM}->{APP} . $xml->{STREAM}->{FULLPATH};
2931
2932  return $url, $filename;
2933}
2934
2935sub make_guid {
2936  my($self) = @_;
2937
2938  my @chars = ('A' .. 'Z', 'a' .. 'z', 0 .. 9, '.', '_');
2939  return join "", map { $chars[rand @chars] } 1 .. 22;
2940}
2941
29421;
2943}
2944##} blib/lib/FlashVideo/Site/Flickr.pm
2945BEGIN { $INC{'FlashVideo/Site/Fliqz.pm'}++; }
2946# Part of get-flash-videos. See get_flash_videos for copyright.
2947##{ blib/lib/FlashVideo/Site/Fliqz.pm
2948{
2949package FlashVideo::Site::Fliqz;
2950
2951use strict;
2952BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
2953BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
2954
2955sub find_video {
2956  my ($self, $browser, $embed_url) = @_;
2957
2958  my $id;
2959  if ($browser->content =~ /<param name=["']flashvars["'] value=["']file=([a-f0-9]{32})/) {
2960    $id = $1;
2961  }
2962
2963  if (!$id and $browser->content =~ /\Q$embed_url\E.*?([a-f0-9]{32})/) {
2964    $id = $1;
2965  }
2966
2967  $browser->post("http://services.fliqz.com/mediaassetcomponentservice/20071201/service.svc",
2968    Content_Type => "text/xml; charset=utf-8",
2969    SOAPAction   => '"urn:fliqz.s.mac.20071201/IMediaAssetComponentService/ad"',
2970    Referer      => $embed_url,
2971    Content      => _get_soap_xml($id)
2972  );
2973
2974  my $flv_url  = ($browser->content =~ />(http:[^<]+\.flv)</)[0];
2975
2976  if (!$flv_url) {
2977    $browser->post("http://services.fliqz.com/LegacyServices/Services/MediaAsset/Component/R20071201/service.svc",
2978      Content_Type => "text/xml; charset=utf-8",
2979      SOAPAction   => '"urn:fliqz.s.mac.20071201/IMediaAssetComponentService/ad"',
2980
2981      Referer      => $embed_url,
2982
2983      Content      => _get_soap_xml($id)
2984    );
2985
2986    $flv_url = ($browser->content =~ />(http:[^<]+\.flv)</)[0];
2987  }
2988
2989  my $filename = ($browser->content =~ /<t [^>]+>([^<]+)/)[0];
2990  $filename = title_to_filename($filename);
2991
2992  $browser->allow_redirects;
2993
2994  return $flv_url, $filename;
2995}
2996
2997sub _get_soap_xml {
2998  my $id = shift;
2999
3000  return <<EOF
3001<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3002<SOAP-ENV:Body>
3003  <i0:ad xmlns:i0="urn:fliqz.s.mac.20071201">
3004  <i0:rq>
3005    <i0:a>$id</i0:a>
3006    <i0:pu></i0:pu>
3007    <i0:pid>1F866AF1-1DB0-4864-BCA1-6236377B518F</i0:pid>
3008  </i0:rq>
3009</i0:ad>
3010</SOAP-ENV:Body>
3011</SOAP-ENV:Envelope>
3012EOF
3013}
3014
30151;
3016}
3017##} blib/lib/FlashVideo/Site/Fliqz.pm
3018BEGIN { $INC{'FlashVideo/Site/Fora.pm'}++; }
3019# Part of get-flash-videos. See get_flash_videos for copyright.
3020##{ blib/lib/FlashVideo/Site/Fora.pm
3021{
3022package FlashVideo::Site::Fora;
3023
3024use strict;
3025BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3026BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
3027
3028sub find_video {
3029  my ($self, $browser, $embed_url) = @_;
3030
3031  my($clip_id) = $browser->content =~ /clipid=(\d+)/;
3032  die "Unable to extract clipid" unless $clip_id;
3033
3034  $browser->get("http://fora.tv/fora/fora_player_full?cid=$clip_id&h=1&b=0");
3035
3036  my $xml = from_xml($browser);
3037
3038  my $filename = title_to_filename($xml->{clipinfo}->{clip_title});
3039
3040  my $playpath = $xml->{encodeinfo}->{encode_url};
3041  $playpath =~ s/\.flv$//;
3042
3043  return {
3044    flv => $filename,
3045    app => "a953/o10",
3046    rtmp => "rtmp://foratv.fcod.llnwd.net",
3047    playpath => $playpath,
3048  };
3049}
3050
30511;
3052}
3053##} blib/lib/FlashVideo/Site/Fora.pm
3054BEGIN { $INC{'FlashVideo/Site/Freevideo.pm'}++; }
3055# Part of get-flash-videos. See get_flash_videos for copyright.
3056##{ blib/lib/FlashVideo/Site/Freevideo.pm
3057{
3058package FlashVideo::Site::Freevideo; # .ru
3059
3060use strict;
3061use Encode;
3062BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3063BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
3064use URI::Escape;
3065
3066sub find_video {
3067  my ($self, $browser) = @_;
3068
3069  my $ticket;
3070  if ($browser->uri->as_string =~ /\?id=(.*?)$/) {
3071    $ticket = $1;
3072  }
3073
3074  $browser->post(
3075    "http://freevideo.ru/video/view/url/-/" . int(rand 100_000),
3076    [
3077      onLoad       => '[type Function]',
3078      highquality  => 0,
3079      getvideoinfo => 1,
3080      devid        => 'LoadupFlashPlayer',
3081      after_adv    => 0,
3082      before_adv   => 1,
3083      frame_url    => 1,
3084      'ref'        => $browser->uri->as_string,
3085      video_url    => 1,
3086      ticket       => $ticket,
3087    ]
3088  );
3089
3090  if (!$browser->success) {
3091    die "Posting to Freevideo failed: " . $browser->response->status_line();
3092  }
3093
3094  my $video_data = uri_unescape($browser->content);
3095
3096  my $url;
3097
3098  if ($video_data =~ m'vidURL=(http://.*?\.flv)') {
3099    $url = $1;
3100  }
3101  else {
3102    die "Couldn't find Freevideo URL";
3103  }
3104
3105  my $title;
3106
3107  if ($video_data =~ /title=(.*?)&userNick/) {
3108    $title = $1;
3109  }
3110
3111  $title = decode('utf-8', $title);
3112
3113  return $url, title_to_filename($title);
3114}
3115
31161;
3117}
3118##} blib/lib/FlashVideo/Site/Freevideo.pm
3119BEGIN { $INC{'FlashVideo/Site/Gamespot.pm'}++; }
3120# Part of get-flash-videos. See get_flash_videos for copyright.
3121##{ blib/lib/FlashVideo/Site/Gamespot.pm
3122{
3123package FlashVideo::Site::Gamespot;
3124
3125use strict;
3126BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3127BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
3128
3129sub find_video {
3130  my ($self, $browser, $embed_url) = @_;
3131
3132  my($params) = $browser->content =~ /xml.php\?(id=[0-9]+.*?)&quot/;
3133  ($params) = $embed_url =~ /xml.php%3F(id%3D[^"&]+)/ unless $params;
3134  die "No params found\n" unless $params;
3135
3136  $browser->get("http://www.gamespot.com/pages/video_player/xml.php?" . $params);
3137
3138  my $xml = from_xml($browser);
3139
3140  my $title = $xml->{playList}->{clip}->{title};
3141  my $url = $xml->{playList}->{clip}->{URI};
3142
3143  $browser->allow_redirects;
3144  return $url, title_to_filename($title);
3145}
3146
31471;
3148
3149}
3150##} blib/lib/FlashVideo/Site/Gamespot.pm
3151BEGIN { $INC{'FlashVideo/Site/Gawker.pm'}++; }
3152# Part of get-flash-videos. See get_flash_videos for copyright.
3153##{ blib/lib/FlashVideo/Site/Gawker.pm
3154{
3155package FlashVideo::Site::Gawker;
3156
3157use strict;
3158BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3159BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
3160
3161sub find_video {
3162  my ($self, $browser) = @_;
3163
3164  my $title = extract_title($browser);
3165  $title =~ s/^\w+\s+-\s*//;
3166  $title =~ s/\s*-\s+\w+$//;
3167  my $filename = title_to_filename($title);
3168
3169  my $url = "http://cache." . $browser->uri->host . "/assets/video/" .
3170    ($browser->content =~ /newVideoPlayer\("([^"]+)/)[0];
3171
3172  return $url, $filename;
3173}
3174
3175sub can_handle {
3176  my($self, $browser, $url) = @_;
3177
3178  return $browser->content =~ /newVideoPlayer/;
3179}
3180
31811;
3182}
3183##} blib/lib/FlashVideo/Site/Gawker.pm
3184BEGIN { $INC{'FlashVideo/Site/Globaltv.pm'}++; }
3185#################################
3186#################################################
3187#
3188# This file was automatically generated by utils/combine-perl.pl
3189# You should edit the original files, not this
3190# combined version.
3191#
3192# The original files are available at:
3193# http://github.com/monsieurvideo/get-flash-videos
3194#
3195#################################################
3196#	GlobalTV Canada
3197#
3198#	first alpha plugin version
3199#
3200#	Input URL should be
3201#		http://www.globaltv.com/$show/video/full+episodes/$clip/video.html?v=$contentID
3202#	where
3203#		$show		show name
3204#		$clip		section
3205#		$contentID 	numeric ID
3206#	Stavr00
3207#
3208#	TODO:	fetch all clips for a show
3209#
3210
3211##{ blib/lib/FlashVideo/Site/Globaltv.pm
3212{
3213package FlashVideo::Site::Globaltv;
3214
3215use strict;
3216BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3217BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
3218use strict 'refs';
3219
3220sub find_video {
3221	my ($self, $browser, $embed_url, $prefs) = @_;
3222
3223	my $pid;
3224	if ( $browser->content =~ /pid:\s+"([^"]+?)"/ ) {
3225		$pid = $1;
3226	}
3227
3228	debug "PID = " . $pid;
3229
3230	die "PID not found." unless $pid;
3231
3232	$browser->get("http://release.theplatform.com/content.select?pid=$pid&mbr=true&Embedded=True&Portal=GlobalTV&Site=global_prg.com&TrackBrowser=True&Tracking=True&TrackLocation=True&format=SMIL");
3233
3234	my $xml = from_xml($browser->content);
3235
3236	my $maxres = $prefs->quality->quality_to_resolution($prefs->{quality});
3237	my $sw;
3238	my $vid;
3239	my $title;
3240	my $url;
3241	my $rate = 0;
3242	my $res;
3243	debug "Enumerating all streams ...";
3244	foreach $sw (@{ $xml->{body}->{switch} }) {
3245		if ($sw->{ref}->{src} =~  /^rtmp\:\/\// ) {
3246			$title = $sw->{ref}->{title};
3247			debug "TITLE = " . $title; # short title, not very useful
3248		}
3249		if ( ref($sw->{video}) eq "ARRAY" ) {
3250			foreach $vid (@{ $sw->{video} }) {
3251				my $t = $vid->{src};
3252				if ( $t =~ /^rtmp\:\/\// ) {
3253					my $w  = $vid->{width};
3254					my $h  = $vid->{height};
3255					my $br = $vid->{'system-bitrate'};
3256					debug ' '. $t ." ". $w . 'x' . $h ."/". $br;
3257					if ( ( $br > $rate ) && ( $h <= @$maxres[1] ) )	{
3258						$rate = $br;
3259						$url = $t;
3260						$res = $w .'x'. $h .' '. int($br/1024) . 'kb/s';
3261					}
3262				}
3263			}
3264		}
3265	}
3266
3267	info 'Stream selected: ' .  $url . ' ' . $res;
3268
3269
3270	$url =~ /([^\/]+\.mp4$)/;
3271	$title = $1;
3272
3273	return	{
3274	rtmp => $url,
3275	    flv => title_to_filename($title)
3276	};
3277
3278
3279}
3280
32811;
3282
3283}
3284##} blib/lib/FlashVideo/Site/Globaltv.pm
3285BEGIN { $INC{'FlashVideo/Site/Google.pm'}++; }
3286# Part of get-flash-videos. See get_flash_videos for copyright.
3287##{ blib/lib/FlashVideo/Site/Google.pm
3288{
3289package FlashVideo::Site::Google;
3290
3291use strict;
3292BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3293BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
3294use URI::Escape;
3295
3296sub find_video {
3297  my ($self, $browser) = @_;
3298
3299  if ($browser->content =~ /googleplayer\.swf\?doc[iI]d=([^&;'"]+)/) {
3300    $browser->get("http://video.google.com/videoplay?docid=$1");
3301  }
3302
3303  if (!$browser->success) {
3304    $browser->get($browser->response->header('Location'));
3305    die "Couldn't download URL: " . $browser->response->status_line
3306      unless $browser->success;
3307  }
3308
3309  my $url;
3310  if ($browser->content =~ /googleplayer\.swf\?&?videoUrl(.+?)\\x26/) {
3311    $url = uri_unescape($1);
3312
3313    $url =~ s/\\x([A-F0-9]{2})/chr(hex $1)/egi;
3314    $url =~ s/^=//;
3315  }
3316
3317  my $filename = title_to_filename(extract_title($browser));
3318
3319  $browser->allow_redirects;
3320
3321  return $url, $filename;
3322}
3323
3324sub can_handle {
3325  my($self, $browser, $url) = @_;
3326
3327  return $browser->response->header('Location') =~ /google/i
3328    || $browser->content =~ /googleplayer\.swf/;
3329}
3330
33311;
3332}
3333##} blib/lib/FlashVideo/Site/Google.pm
3334BEGIN { $INC{'FlashVideo/Site/Googlevideosearch.pm'}++; }
3335# Part of get-flash-videos. See get_flash_videos for copyright.
3336BEGIN { $INC{'FlashVideo/Mechanize.pm'}++; }
3337# Part of get-flash-videos. See get_flash_videos for copyright.
3338BEGIN { $INC{'FlashVideo/Downloader.pm'}++; }
3339# Part of get-flash-videos. See get_flash_videos for copyright.
3340BEGIN { $INC{'FlashVideo/Site.pm'}++; }
3341# Part of get-flash-videos. See get_flash_videos for copyright.
3342##{ blib/lib/FlashVideo/Site.pm
3343{
3344package FlashVideo::Site;
3345
3346use strict;
3347
3348
3349sub debug {
3350  $App::get_flash_videos::opt{debug};
3351}
3352
3353sub action {
3354  $App::get_flash_videos::opt{play} ? "play" : "download";
3355}
3356
3357sub player {
3358  $App::get_flash_videos::opt{player};
3359}
3360
3361sub yes {
3362  $App::get_flash_videos::opt{yes};
3363}
3364
3365sub quiet {
3366  $App::get_flash_videos::opt{quiet};
3367}
3368
33691;
3370}
3371##} blib/lib/FlashVideo/Site.pm
3372##{ blib/lib/FlashVideo/Downloader.pm
3373{
3374package FlashVideo::Downloader;
3375
3376use strict;
3377BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3378BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *get_terminal_width = \&FlashVideo::Utils::get_terminal_width; }
3379
3380BEGIN { FlashVideo::Site->import(); } # (added by utils/combine-perl.pl)
3381use base "FlashVideo::Site";
3382
3383sub new {
3384  my $class = shift;
3385
3386  my $self = {
3387    has_readkey => scalar eval { require Term::ReadKey }
3388  };
3389
3390  bless $self, $class;
3391  return $self;
3392}
3393
3394sub play {
3395  my ($self, $url, $file, $browser) = @_;
3396
3397  $self->{stream} = sub {
3398    $self->{stream} = undef;
3399
3400    if ($^O =~ /MSWin/i and $self->player eq "VLC") {
3401      if (my $vlc_binary = FlashVideo::Utils::get_vlc_exe_from_registry()) {
3402        require Win32::Process;
3403        require File::Basename;
3404        require File::Spec;
3405        $file = File::Spec->rel2abs($file);
3406
3407        my $binary_no_path = File::Basename::basename $vlc_binary;
3408
3409        my $binary_just_path = File::Basename::dirname $vlc_binary;
3410
3411        my $process;
3412        Win32::Process::Create(
3413          $process,
3414          $vlc_binary,
3415          "$binary_no_path $file",
3416          1,
3417          32, # NORMAL_PRIORITY_CLASS
3418          $binary_just_path,
3419        ) or info "Couldn't launch VLC ($vlc_binary): " . Win32::GetLastError();
3420      }
3421    }
3422    else {
3423      my $pid = fork;
3424      die "Fork failed" unless defined $pid;
3425      if(!$pid) {
3426        exec $self->replace_filename($self->player, $file);
3427        die "Exec failed\n";
3428      }
3429    }
3430  };
3431
3432  $self->download($url, $file, $browser);
3433}
3434
3435sub download {
3436  my ($self, $url, $file, $browser) = @_;
3437
3438  $self->{printable_filename} = $file;
3439
3440  $file = $self->get_filename($file);
3441
3442  my $mode = (-e $file) ? '>>' : '>';
3443  my $offset;
3444  if ($file ne '-' && -e $file) {
3445    $offset = -s $file;
3446
3447    my $response = $browser->head($url);
3448
3449    if ($offset == $response->header('Content-Length')) {
3450      error "File $self->{printable_filename} has been fully downloaded.";
3451      $self->{stream}->() if defined $self->{stream};
3452      return;
3453    }
3454
3455    info "File $self->{printable_filename} already exists, seeing if resuming is supported.";
3456    if (!$response->header('Accept-Ranges')) {
3457      if(!$self->yes) {
3458        error "This server doesn't explicitly support resuming.\n" .
3459                   "Do you want to try resuming anyway (y/n)?";
3460        chomp(my $answer = <STDIN>);
3461        if (!$answer or lc($answer) eq 'n') {
3462          undef $offset;
3463          $mode = '>';
3464        }
3465      }
3466    }
3467    else {
3468      info "Server supports resuming, attempting to resume.";
3469    }
3470  }
3471
3472  my $video_fh;
3473  if($file eq '-') {
3474    $video_fh = \*STDOUT;
3475  } else {
3476    open $video_fh, $mode, $file or die $!;
3477  }
3478
3479  binmode $video_fh;
3480  $self->{fh} = $video_fh;
3481
3482  info "Downloading $url...";
3483  if ($offset) {
3484    $browser->add_header("Range", "bytes=$offset-");
3485  }
3486  my $response = $browser->get($url,
3487    ':content_cb' => sub {
3488        my ($data, $response) = @_;
3489
3490        if (!$self->{content_length}) {
3491          $self->{content_length} = $response->header('Content-Length')
3492                                    + $offset;
3493
3494          if($response->header('Content-encoding') =~ /gzip/i) {
3495            eval { require Compress::Zlib; } or do {
3496              error "Must have Compress::Zlib installed to download from this site.\n";
3497              exit 1;
3498            };
3499
3500            my($inflate, $status) = Compress::Zlib::inflateInit(
3501              -WindowBits => -Compress::Zlib::MAX_WBITS());
3502            error "inflateInit failed: $status" if $status;
3503
3504            $self->{filter} = sub {
3505              my($data) = @_;
3506
3507              if(!$self->{downloaded}) {
3508                Compress::Zlib::_removeGzipHeader(\$data);
3509              }
3510
3511              my($output, $status) = $inflate->inflate($data);
3512              return $output;
3513            }
3514          }
3515        }
3516
3517        if ($offset and !$response->header('Content-Range')) {
3518          error "Resuming failed - please delete $self->{printable_filename} and restart.";
3519          exit 1;
3520        }
3521        else {
3522          $self->{downloaded} = $offset unless $self->{downloaded};
3523        }
3524
3525        my $len = length $data;
3526
3527        if($self->{filter}) {
3528          $data = $self->{filter}->($data);
3529        }
3530
3531        return unless $data;
3532
3533        my $fh = $self->{fh};
3534        print $fh $data || die "Unable to write to '$self->{printable_filename}': $!\n";
3535
3536        if(defined $self->{stream}) {
3537          if($self->{downloaded} > 300_000) {
3538            $self->{stream}->();
3539          }
3540        }
3541
3542        if(!$self->{downloaded} && length $data > 16) {
3543          if(!$self->check_magic($data)) {
3544            error "Sorry, file does not look like a media file, aborting.";
3545            exit 1;
3546          }
3547        }
3548
3549        $self->{downloaded} += $len;
3550        $self->progress;
3551    }, ':read_size_hint' => 16384);
3552
3553  if($browser->response->header("X-Died")) {
3554    error $browser->response->header("X-Died");
3555  }
3556
3557  close $self->{fh} || die "Unable to write to '$self->{printable_filename}': $!";
3558
3559  if ($browser->success) {
3560    return $self->{downloaded} - $offset;
3561  } else {
3562    unlink $file unless -s $file;
3563    error "Couldn't download $url: " .  $browser->response->status_line;
3564    return 0;
3565  }
3566}
3567
3568sub progress {
3569  my($self) = @_;
3570
3571  return unless -t STDERR;
3572  return if $self->quiet;
3573
3574  my $progress_text;
3575
3576  if ($self->{content_length}) {
3577    my $percent = int(
3578      ($self->{downloaded} / $self->{content_length}) * 100
3579    );
3580    if ($percent != $self->{percent} || time != $self->{last_time}) {
3581      my $downloaded_kib = _bytes_to_kib($self->{downloaded});
3582      my $total_kib      = _bytes_to_kib($self->{content_length});
3583      $progress_text = ": $percent% ($downloaded_kib / $total_kib KiB)";
3584      $self->{last_time} = time;
3585      $self->{percent} = $percent;
3586    }
3587  } else {
3588    my $data_transferred = _bytes_to_kib($self->{downloaded});
3589    if ($data_transferred != $self->{data_transferred}) {
3590      $progress_text = ": $data_transferred KiB";
3591    }
3592  }
3593
3594  if($progress_text) {
3595    my $width = get_terminal_width();
3596
3597    my $filename = $self->{printable_filename};
3598    my $filename_len = $width - length($progress_text);
3599
3600    if($filename_len < length $filename) {
3601      my $rem = 3 + length($filename) - $filename_len;
3602      my $pos = length($filename) - $rem - 12;
3603      $pos = 0 if $pos < 0;
3604      substr($filename, $pos, $rem) = "...";
3605    }
3606
3607    syswrite STDERR, "\r$filename$progress_text";
3608  }
3609}
3610
3611sub _bytes_to_kib {
3612  return sprintf '%0.2f', ($_[0] / 1024)
3613}
3614
3615sub replace_filename {
3616  my($self, $string, $filename) = @_;
3617  $string .= " %s" unless $string =~ /%s/;
3618  my $esc = $self->shell_escape($filename);
3619  $string =~ s/['"]?%s['"]?/$esc/g;
3620  return $string;
3621}
3622
3623sub shell_escape {
3624  my($self, $file) = @_;
3625
3626  $file =~ s/'/'\\''/g;
3627  return "'$file'";
3628}
3629
3630sub check_file {
3631  my($self, $file) = @_;
3632
3633  open my $fh, "<", $file;
3634  binmode $fh;
3635  my $data;
3636  read $fh, $data, 16;
3637
3638  return $self->check_magic($data);
3639}
3640
3641sub check_magic {
3642  my($self, $data) = @_;
3643
3644
3645  if(substr($data, 0, 3) eq 'FLV') {
3646    return 1;
3647  } elsif(substr($data, 0, 3) eq 'ID3') {
3648    return 1;
3649  } elsif (substr($data, 0, 2) eq "\xff\xfb") {
3650    return 1;
3651  } elsif(substr($data, 0, 4) eq "\x30\x26\xb2\x75") {
3652    return 1;
3653  } elsif(substr($data, 4, 4) eq 'ftyp') {
3654    return 1;
3655  } elsif(substr($data, 4, 4) =~ /moov|mdat|wide|free|pnot|skip/) {
3656    return 1;
3657  } elsif(substr($data, 0, 4) eq 'OggS') {
3658    return 1;
3659  } elsif(substr($data, 0x1F, 4) eq 'webm') {
3660    return 1;
3661  } elsif(substr($data, 0, 4) eq 'RIFF') {
3662    return 1;
3663  }
3664
3665  return 0;
3666}
3667
3668sub get_filename {
3669  my($self, $file) = @_;
3670
3671  if($^O =~ /MSWin/i) {
3672    $file = Encode::encode(get_win_codepage(), $file);
3673    $file =~ s/\?/_/g;
3674  }
3675
3676  return $file;
3677}
3678
36791;
3680
3681}
3682##} blib/lib/FlashVideo/Downloader.pm
3683##{ blib/lib/FlashVideo/Mechanize.pm
3684{
3685package FlashVideo::Mechanize;
3686use WWW::Mechanize;
3687BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl)
3688use Encode ();
3689
3690use strict;
3691use WWW::Mechanize;use base "WWW::Mechanize";
3692
3693sub new {
3694  my $class = shift;
3695  my $browser = $class->SUPER::new(autocheck => 0);
3696  $browser->agent_alias("Windows Mozilla");
3697
3698  my $proxy = $App::get_flash_videos::opt{proxy};
3699
3700  if ($proxy) {
3701    if ($proxy =~ /^(\w+):?(\d+)?$/) {
3702      my ($host, $port) = ($1, $2);
3703
3704      $port ||= 1080; # socks by default
3705
3706      $proxy = "socks://$host:$port";
3707
3708      print STDERR "Using proxy server $proxy\n"
3709        if $App::get_flash_videos::opt{debug};
3710
3711      $browser->proxy([qw[http https]] => $proxy);
3712    }
3713  }
3714
3715  if($browser->get_socks_proxy) {
3716    if(!eval { require LWP::Protocol::socks }) {
3717      die "LWP::Protocol::socks is required for SOCKS support, please install it\n";
3718    }
3719  }
3720
3721  return $browser;
3722}
3723
3724sub redirect_ok {
3725  my($self) = @_;
3726
3727  return $self->{redirects_ok};
3728}
3729
3730sub allow_redirects {
3731  my($self) = @_;
3732  $self->{redirects_ok} = 1;
3733}
3734
3735sub get {
3736  my($self, @rest) = @_;
3737
3738  print STDERR "-> GET $rest[0]\n" if $App::get_flash_videos::opt{debug};
3739
3740  my $r = $self->SUPER::get(@rest);
3741
3742  if($App::get_flash_videos::opt{debug}) {
3743    my $text = join " ", $self->response->code,
3744      $self->response->header("Content-type"), "(" . length($self->content) . ")";
3745    $text .= ": " . DBI::data_string_desc($self->content) if eval { require DBI };
3746
3747    print STDERR "<- $text\n";
3748  }
3749
3750  return $r;
3751}
3752
3753sub update_html {
3754  my($self, $html) = @_;
3755
3756  my $charset = _parse_charset($self->response->header("Content-type"));
3757
3758  if($LWP::UserAgent::VERSION < 5.827
3759    && (!$charset || !Encode::is_utf8($html))) {
3760
3761    $html = Encode::encode("iso-8859-1", $html) if Encode::is_utf8($html);
3762
3763    if(!FlashVideo::Downloader->check_magic($html)) {
3764      my $p = HTML::TokeParser->new(\$html);
3765      while(my $token = $p->get_tag("meta")) {
3766        my($tag, $attr) = @$token;
3767        if($tag eq 'meta' && $attr->{"http-equiv"} =~ /Content-type/i) {
3768          $charset ||= _parse_charset($attr->{content});
3769        }
3770      }
3771
3772      if($charset) {
3773        eval { $html = Encode::decode($charset, $html) };
3774        FlashVideo::Utils::error("Failed decoding as $charset: $@") if $@;
3775      }
3776    }
3777  }
3778
3779  return $self->SUPER::update_html($html);
3780}
3781
3782sub _parse_charset {
3783  my($field) = @_;
3784  return(($field =~ /;\s*charset=([-_.:a-z0-9]+)/i)[0]);
3785}
3786
3787sub get_socks_proxy {
3788  my $self = shift;
3789  my $proxy = $self->proxy("http");
3790
3791  if(defined $proxy && $proxy =~ m!^socks://(.*?):(\d+)!) {
3792    return "$1:$2";
3793  }
3794
3795  return "";
3796}
3797
37981;
3799}
3800##} blib/lib/FlashVideo/Mechanize.pm
3801##{ blib/lib/FlashVideo/Site/Googlevideosearch.pm
3802{
3803package FlashVideo::Site::Googlevideosearch;
3804
3805use strict;
3806no warnings 'uninitialized';
3807BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl)
3808use URI::Escape;
3809
3810sub search {
3811  my($self, $search, $type) = @_;
3812
3813  my $browser = FlashVideo::Mechanize->new;
3814
3815  $browser->get('http://video.google.com/videoadvancedsearch');
3816
3817  $browser->submit_form(
3818    with_fields => {
3819      q => $search,
3820    }
3821  );
3822
3823  return unless $browser->success;
3824
3825  my @links = map  {
3826                     chomp(my $name = $_->text);
3827                     my $url = $_->url_abs->as_string;
3828                     $url =~ /q=([^&]*)/;
3829                     $url = uri_unescape($1);
3830                     { name => $name, url => $url }
3831              }
3832              $browser->find_all_links(text_regex => qr/.+/, url_regex => qr/\/url/);
3833
3834  return @links;
3835}
3836
38371;
3838}
3839##} blib/lib/FlashVideo/Site/Googlevideosearch.pm
3840BEGIN { $INC{'FlashVideo/Site/Gorillavid.pm'}++; }
3841# Part of get-flash-videos. See get_flash_videos for copyright.
3842#################################################
3843#
3844# This file was automatically generated by utils/combine-perl.pl
3845# You should edit the original files, not this
3846# combined version.
3847#
3848# The original files are available at:
3849# http://github.com/monsieurvideo/get-flash-videos
3850#
3851#################################################
3852
3853#This package handles sites such as GorillaVid.in, DaClips.in and
3854# MovPod.in
3855##{ blib/lib/FlashVideo/Site/Gorillavid.pm
3856{
3857package FlashVideo::Site::Gorillavid;
3858
3859use strict;
3860BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3861BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; }
3862
3863sub find_video {
3864  my ($self, $browser, $embed_url) = @_;
3865  my $filename;
3866
3867  for my $form ($browser->forms) {
3868    if ($form->find_input('#btn_download')){
3869      $filename = $form->value('fname'); #extract the filename from the form
3870
3871      info 'Submitting form to get real video page.';
3872      $browser->request($form->click()); #submit to get the real page
3873    }
3874  }
3875
3876  my ($url) = ($browser->content =~ /file: *"(https?:\/\/.*?)"/);
3877
3878  my ($ext) =  ($url =~ /(\.[a-z0-9]{2,4})$/);
3879
3880  return $url, $filename.$ext;
3881}
3882
3883sub can_handle {
3884  my($self, $browser, $url) = @_;
3885
3886  return 1 if $url && URI->new($url)->host =~ /(gorillavid|daclips|movpod)\.in$/;
3887}
3888
38891;
3890}
3891##} blib/lib/FlashVideo/Site/Gorillavid.pm
3892BEGIN { $INC{'FlashVideo/Site/Grindtv.pm'}++; }
3893# Part of get-flash-videos. See get_flash_videos for copyright.
3894##{ blib/lib/FlashVideo/Site/Grindtv.pm
3895{
3896package FlashVideo::Site::Grindtv;
3897
3898use strict;
3899BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3900BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
3901
3902my %sites = (
3903  Grindtv => "http://videos.grindtv.com/1/",
3904  Stupidvideos => "http://videos.stupidvideos.com/2/",
3905  Ringtv => "http://videos.ringtv.com/7/"
3906);
3907
3908sub find_video {
3909  my ($self, $browser, $embed_url) = @_;
3910
3911  my $site = ($self =~ /::([^:]+)$/)[0];
3912  my $base = $sites{$site};
3913
3914  my $id;
3915  if($browser->content =~ /(?:baseID|video(?:ID)?)\s*=\s*['"]?(\d+)/) {
3916    $id = $1;
3917  }
3918  die "No ID found\n" unless $id;
3919
3920  my $title = ($browser->content =~ /name="title" content="([^"]+)/i)[0];
3921  $title = extract_title($browser) unless $title;
3922
3923  my $filename = title_to_filename($title);
3924
3925  $browser->allow_redirects;
3926
3927  my $str = sprintf "%08d", $id;
3928  my $url = $base . join("/", map { substr $str, $_*2, 2 } 0 .. 3) . "/$id.flv";
3929
3930  return $url, $filename;
3931}
3932
39331;
3934}
3935##} blib/lib/FlashVideo/Site/Grindtv.pm
3936BEGIN { $INC{'FlashVideo/Site/Ima.pm'}++; }
3937# Part of get-flash-videos. See get_flash_videos for copyright.
3938##{ blib/lib/FlashVideo/Site/Ima.pm
3939{
3940package FlashVideo::Site::Ima;
3941
3942use strict;
3943BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3944BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
3945
3946sub find_video {
3947  my ($self, $browser) = @_;
3948
3949  my($id) = $browser->uri =~ /id=(\d+)/;
3950  die "ID not found" unless $id;
3951
3952  my $rpc = "http://www.ima.umn.edu/videos/video_rpc.php?id=$id";
3953  $browser->get($rpc);
3954
3955  my($title) = $browser->content =~ m{<video_title>(.*)</video_title>};
3956  my($instance) = $browser->content =~ m{<video_instance>(.*)</video_instance>};
3957  my($file) = $browser->content =~ m{<video_file>(.*)</video_file>};
3958
3959  return {
3960    rtmp => "rtmp://reel.ima.umn.edu/ima/$instance/$file",
3961    flv  => title_to_filename($title)
3962  };
3963}
3964
3965sub can_handle {
3966  my($self, $browser) = @_;
3967
3968  return $browser->uri->host =~ /ima\.umn\.edu/i;
3969}
3970
39711;
3972}
3973##} blib/lib/FlashVideo/Site/Ima.pm
3974BEGIN { $INC{'FlashVideo/Site/Itv.pm'}++; }
3975# Part of get-flash-videos. See get_flash_videos for copyright.
3976##{ blib/lib/FlashVideo/Site/Itv.pm
3977{
3978package FlashVideo::Site::Itv;
3979
3980use strict;
3981BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
3982BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *swfhash = \&FlashVideo::Utils::swfhash; }
3983use HTML::Entities;
3984
3985sub find_video {
3986  my ($self, $browser, $page_url, $prefs) = @_;
3987
3988  my($id) = $browser->uri =~ /Filter=(\d+)/;
3989  die "No id (filter) found in URL\n" unless $id;
3990
3991  $browser->post("http://mercury.itv.com/PlaylistService.svc",
3992    Content_Type => "text/xml; charset=utf-8",
3993    Referer      => "http://www.itv.com/mercury/Mercury_VideoPlayer.swf?v=1.5.309/[[DYNAMIC]]/2",
3994    SOAPAction   => '"http://tempuri.org/PlaylistService/GetPlaylist"',
3995    Content      => <<EOF);
3996<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3997  <SOAP-ENV:Body>
3998    <tem:GetPlaylist xmlns:tem="http://tempuri.org/" xmlns:itv="http://schemas.datacontract.org/2004/07/Itv.BB.Mercury.Common.Types" xmlns:com="http://schemas.itv.com/2009/05/Common">
3999      <tem:request>
4000        <itv:RequestGuid>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</itv:RequestGuid>
4001        <itv:Vodcrid>
4002          <com:Id>$id</com:Id>
4003          <com:Partition>itv.com</com:Partition>
4004        </itv:Vodcrid>
4005      </tem:request>
4006      <tem:userInfo>
4007        <itv:GeoLocationToken>
4008          <itv:Token/>
4009        </itv:GeoLocationToken>
4010        <itv:RevenueScienceValue>scc=true; svisit=1; sc4=Other</itv:RevenueScienceValue>
4011      </tem:userInfo>
4012      <tem:siteInfo>
4013        <itv:AdvertisingRestriction>None</itv:AdvertisingRestriction>
4014        <itv:AdvertisingSite>ITV</itv:AdvertisingSite>
4015        <itv:Area>ITVPLAYER.VIDEO</itv:Area>
4016        <itv:Platform>DotCom</itv:Platform>
4017        <itv:Site>ItvCom</itv:Site>
4018      </tem:siteInfo>
4019    </tem:GetPlaylist>
4020  </SOAP-ENV:Body>
4021</SOAP-ENV:Envelope>
4022EOF
4023
4024  debug $browser->content;
4025  die "Unable to find <Video> in XML" unless $browser->content =~ m{<Video timecode[^>]+>(.*?)</Video>}s;
4026  my $video = $1;
4027
4028
4029  my %formats;
4030
4031  while ($video =~ m/(mp4:[^\]]+_[A-Z]+([0-9]{3,4})_(16|4)[-x](9|3)[^\]]*.mp4)/gi)
4032  {
4033    $formats{$2} = { video => $video, playpath => $1, ratio => "$3x$4" };
4034  }
4035
4036  while ($video =~ m/(mp4:[^\]]+-([0-9]{3,4})kbps.mp4)/gi)
4037  {
4038    $formats{$2} = { video => $video, playpath => $1, ratio => "16x9" };
4039  }
4040  while ($video =~ m/(mp4:[^\]]+-([0-9]{3,4})kbps.\d+.mp4)/gi)
4041  {
4042    $formats{$2} = { video => $video, playpath => $1, ratio => "16x9" };
4043  }
4044
4045  my @rates = sort { $a <=> $b } keys(%formats);
4046  my $cnt = $#rates;
4047
4048  die "Unable to find video in XML" unless $cnt >= 0;
4049
4050  my $q = $prefs->{quality};
4051  if ( $q =~ /^\s*\d+\s*$/) {
4052     my $rate = $rates[0];
4053     foreach (@rates) {
4054        if ( $q >= $_ )
4055        { $rate = $_;}
4056     }
4057     $q = $rate;
4058  }
4059  else {
4060    my $num = {high =>int($cnt), medium => int(($cnt+1)/2), low => 0}->{$q};
4061    if (! defined $num ) {
4062      $num = int($cnt);
4063    }
4064    $q = $rates[$num];
4065  }
4066
4067  my $format = $formats{$q};
4068  if ( ! defined($format)) {
4069    $format = $formats{$rates[int($cnt)]};
4070  }
4071
4072  $video = $format->{"video"};
4073  my $rtmp = decode_entities($video =~ /base="(rtmp[^"]+)/);
4074  my($playpath) = $format->{"playpath"};
4075  my($flv) = $playpath =~ m{/([^/]+)$};
4076
4077  return {
4078    rtmp => $rtmp,
4079    playpath => $playpath,
4080    flv => $flv,
4081    swfhash($browser, "http://www.itv.com/mercury/Mercury_VideoPlayer.swf")
4082  };
4083}
4084
40851;
4086}
4087##} blib/lib/FlashVideo/Site/Itv.pm
4088BEGIN { $INC{'FlashVideo/Site/Joemonster.pm'}++; }
4089# Author: paczesiowa@gmail.com
4090#################################################
4091#
4092# This file was automatically generated by utils/combine-perl.pl
4093# You should edit the original files, not this
4094# combined version.
4095#
4096# The original files are available at:
4097# http://github.com/monsieurvideo/get-flash-videos
4098#
4099#################################################
4100#
4101# This plugin works for videos from www.joemonster.org using 'Monster Player'
4102#
4103# Most (~70%) of them are single embedded youtube videos:
4104# http://www.joemonster.org/filmy/28773/Sposob_na_Euro_2012
4105# This plugin doesn't directly support them,
4106# so get_flash_videos fallbacks to youtube method, which works just fine.
4107# Pages with multiple youtube videos are also supported by youtube method,
4108# but only the first embedded video is downloaded:
4109# http://www.joemonster.org/filmy/4551/Terapia_masazem
4110#
4111# This plugin claims to support a page when it contains at least one video
4112# embedded with Monster Player.
4113# Pages with mixed providers, like this (Monster Player+youtube):
4114# http://www.joemonster.org/filmy/5496/Kolo_Smierci
4115# only downloads Monster Player movies, the rest is discarded,
4116# because I don't know how to provide links AND fallback to a different method.
4117#
4118# There are two versions of Monster Player:
4119# * old/fat
4120# http://www.joemonster.org/filmy/28784/Genialny_wystep_mlodego_iluzjonisty_w_Mam_talent (single video)
4121# http://www.joemonster.org/filmy/28693/Dave_Chappelle_w_San_Francisco_ (multi videos)
4122#
4123# * new/slim
4124# http://www.joemonster.org/filmy/28372/Wszyscy_kochamy_Polske_czesc_ (single video)
4125#
4126# Currently multiple videos are unsupported, only the first one is downloaded,
4127# I have no idea how to return multiple links
4128#
4129# About 5% of videos are embedded from external providers (different than youtube),
4130# they should work if get_flash_videos has appropriate method.
4131
4132##{ blib/lib/FlashVideo/Site/Joemonster.pm
4133{
4134package FlashVideo::Site::Joemonster;
4135
4136use strict;
4137BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4138BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4139use URI::Escape;
4140use URI::QueryParam;
4141
4142
4143my $new_monster_player_regex = "<\\s*embed\\s*src\\s*=\\s*\"\\s*(http:\\/\\/www\\.joemonster\\.org\\/flvplayer\\.swf\\?file=.*?)\\s*\"";
4144
4145sub is_new_monster_player {
4146    my($self, $browser) = @_;
4147    return $browser->content =~ m/$new_monster_player_regex/;
4148}
4149
4150sub get_new_monster_player_url {
4151    my($self, $browser) = @_;
4152    $browser->content =~ m/$new_monster_player_regex/;
4153    return URI->new($1)->query_param('file') or die "no file key in player link";
4154}
4155
4156my $old_monster_player_regex = "<\\s*embed\\s*src\\s*=\\s*\"\\s*(http:\\/\\/www\\.joemonster\\.org\\/emb\\/.*?)\\s*\"";
4157
4158sub is_old_monster_player {
4159    my($self, $browser) = @_;
4160    return $browser->content =~ m/$old_monster_player_regex/;
4161}
4162
4163
4164sub get_old_monster_player_url {
4165    my($self, $browser) = @_;
4166    $browser->content =~ m/$old_monster_player_regex/;
4167    my $embedded_url = $1;
4168    $browser->get($embedded_url);
4169    my $url = $browser->uri;
4170    return URI->new($url)->query_param('file') or die "no file key in player link";
4171}
4172
4173sub can_handle {
4174    my($self, $browser, $url) = @_;
4175    return $self->is_new_monster_player($browser) || $self->is_old_monster_player($browser);
4176}
4177
4178sub find_video {
4179    my($self, $browser, $url) = @_;
4180    my $real_url;
4181
4182    if ($self->is_new_monster_player($browser)) {
4183	$real_url = $self->get_new_monster_player_url($browser);
4184    }
4185    else {
4186	$real_url = $self->get_old_monster_player_url($browser);
4187    }
4188
4189    my $title;
4190    if ($browser->title =~ m/(.*) - Joe Monster/ ) {
4191	$title = $1;
4192    } else {
4193	$title = $browser->title;
4194    }
4195
4196    return $real_url, title_to_filename($title);
4197}
4198
41991;
4200}
4201##} blib/lib/FlashVideo/Site/Joemonster.pm
4202BEGIN { $INC{'FlashVideo/Site/Kanal5play.pm'}++; }
4203# Part of get-flash-videos. See get_flash_videos for copyright.
4204##{ blib/lib/FlashVideo/Site/Kanal5play.pm
4205{
4206package FlashVideo::Site::Kanal5play;
4207
4208use strict;
4209use warnings;
4210BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4211BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4212BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
4213BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
4214
4215
4216my $bitrates = {
4217     "low" => 250000,
4218     "medium" => 450000,
4219     "high" => 900000 };
4220
4221sub find_video {
4222  my ($self, $browser, $embed_url, $prefs) = @_;
4223  if(!($browser->uri->as_string =~ m/video\/([0-9]*)/)){
4224      die "No video id found in url";
4225  }
4226  my ($video_id) = $1;
4227  my $info_url = "http://www.kanal5play.se/api/getVideo?format=FLASH&videoId=$video_id";
4228  $browser->get($info_url);
4229
4230  if (!$browser->success){
4231      die "Couldn't download $info_url: " . $browser->response->status_line;
4232  }
4233
4234  my $jsonstr = $browser->content;
4235  my $json = from_json($jsonstr);
4236
4237  my $name = $json->{program}->{name};
4238  my $episode = $json->{episodeNumber};
4239  my $season = $json->{seasonNumber};
4240  my $filename = sprintf "%s - S%02dE%02d", $name, $season, $episode;
4241  my ($rtmp) = "rtmp://fl1.c00608.cdn.qbrick.com:1935/00608";
4242  my ($playpath) = $json->{streams}[0]->{source};
4243
4244  my  $i;
4245  foreach $i (keys $json->{streams}) {
4246      my ($rate) = int($json->{streams}[$i]->{bitrate});
4247      if($bitrates->{$prefs->{quality}} == $rate){
4248	  $playpath = $json->{streams}[$i]->{source};
4249      }
4250  }
4251  return {
4252      flv => title_to_filename($filename, "flv"),
4253      rtmp => $rtmp,
4254      playpath => $playpath,
4255      swfVfy => "http://www.kanal5play.se/flash/StandardPlayer.swf"
4256  };
4257
4258}
42591;
4260}
4261##} blib/lib/FlashVideo/Site/Kanal5play.pm
4262BEGIN { $INC{'FlashVideo/Site/Kidswb.pm'}++; }
4263# Part of get-flash-videos. See get_flash_videos for copyright.
4264##{ blib/lib/FlashVideo/Site/Kidswb.pm
4265{
4266package FlashVideo::Site::Kidswb;
4267
4268use strict;
4269BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4270BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
4271BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
4272BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
4273
4274sub find_video {
4275  my($self, $browser, $embed_url, $prefs) = @_;
4276
4277  my $config_url = "http://staticswf.kidswb.com/franchise/digitalsmiths/wbkidsvideoplayer.xml";
4278  my $mediaKey;
4279  if ($browser->uri->as_string =~ /\/video#.*\/([^\/]*)$/) {
4280    $mediaKey = $1;
4281  } else {
4282    die "Couldn't find flashvars param in " . $browser->uri->as_string;
4283  }
4284
4285  $browser->allow_redirects;
4286  $browser->get($config_url);
4287  if (!$browser->success) {
4288    die "Couldn't download config.xml $config_url: " . $browser->response->status_line;
4289  }
4290
4291  my $xml = from_xml($browser);
4292  my $domain = $xml->{mfs}->{url};
4293  my $version = "v2";
4294  my $account = $xml->{mfs}->{account};
4295  my $partner = $xml->{mfs}->{partnerid};
4296
4297  my $asset_url = "$domain/$version/$account/assets/$mediaKey/partner/$partner?format=json";
4298  $browser->get($asset_url);
4299  if (!$browser->success) {
4300    die "Couldn't download asset file $asset_url: " . $browser->response->status_line;
4301  }
4302
4303  my $asset_data = from_json($browser->content);
4304  my $videos = $asset_data->{videos};
4305
4306  my $title = title_to_filename($asset_data->{assetFields}->{seriesName} . " - " . $asset_data->{assetFields}->{title});
4307
4308  my $video = $videos->{limelight700};
4309
4310  my $rtmp = $video->{uri};
4311
4312  return {
4313    flv => $title,
4314    rtmp => $rtmp,
4315  };
4316}
4317
43181;
4319}
4320##} blib/lib/FlashVideo/Site/Kidswb.pm
4321BEGIN { $INC{'FlashVideo/Site/Last.pm'}++; }
4322# Part of get-flash-videos. See get_flash_videos for copyright.
4323##{ blib/lib/FlashVideo/Site/Last.pm
4324{
4325package FlashVideo::Site::Last;
4326
4327use strict;
4328BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4329BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4330use URI::Escape;
4331
4332sub find_video {
4333  my ($self, $browser, $embed_url) = @_;
4334
4335  my($artist, $id) = $embed_url =~ m{/([^/]+)/\+videos/(\d+)};
4336  my($title) = $browser->content =~ /<h1>([^<]+)/;
4337
4338  die "No video ID found" unless $id;
4339
4340  $browser->get("http://ext.last.fm/1.0/video/getplaylist.php?&vid=$id&artist=$artist");
4341
4342  return $browser->content =~ /<location>([^<]+)/, title_to_filename($title);
4343}
4344
4345sub can_handle {
4346  my($self, $browser, $url) = @_;
4347
4348  return $url =~ /last\.fm/ && $url =~ m{\+video/\d{2,}};
4349}
4350
43511;
4352}
4353##} blib/lib/FlashVideo/Site/Last.pm
4354BEGIN { $INC{'FlashVideo/Site/Liveleak.pm'}++; }
4355# Part of get-flash-videos. See get_flash_videos for copyright.
4356##{ blib/lib/FlashVideo/Site/Liveleak.pm
4357{
4358package FlashVideo::Site::Liveleak;
4359
4360use strict;
4361BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4362BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4363
4364sub find_video {
4365  my ($self, $browser, $embed_url) = @_;
4366
4367  my $file_embed_tag;
4368  if ($browser->content =~ /file_embed_tag(?:%3D|=)(\w+)\W/) {
4369    $file_embed_tag = $1;
4370  }
4371  else {
4372    die "Unable to get file_embed_tag";
4373  }
4374
4375  $browser->get("http://www.liveleak.com/playlist_new.php?file_embed_tag=$file_embed_tag");
4376
4377  if (!$browser->success) {
4378    die "Couldn't download LiveLeak playlist: " . $browser->response->status_line();
4379  }
4380
4381  my $video_url;
4382  if ($browser->content =~ m'<location>(http://.*?)</location>') {
4383    $video_url = $1;
4384  }
4385  else {
4386    die "Unable to extract LiveLeak video URL";
4387  }
4388
4389  if (my $redirected_url = $browser->head($video_url)->header('Location')) {
4390    $video_url = $redirected_url;
4391  }
4392
4393  $browser->back();
4394
4395  my $title;
4396  if ($browser->content =~ m'<h4 id="s_hd">(.*?)</h4>') {
4397    $title = $1;
4398  }
4399  else {
4400    $title = extract_title($browser);
4401  }
4402
4403  return $video_url, title_to_filename($title);
4404}
4405
44061;
4407}
4408##} blib/lib/FlashVideo/Site/Liveleak.pm
4409BEGIN { $INC{'FlashVideo/Site/Megaporn.pm'}++; }
4410# Part of get-flash-videos. See get_flash_videos for copyright.
4411BEGIN { $INC{'FlashVideo/Site/Megavideo.pm'}++; }
4412# Part of get-flash-videos. See get_flash_videos for copyright.
4413##{ blib/lib/FlashVideo/Site/Megavideo.pm
4414{
4415package FlashVideo::Site::Megavideo;
4416
4417use strict;
4418BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4419BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4420use URI::Escape;
4421
4422my %sites = (
4423  Megavideo => "megavideo.com",
4424  Megaporn  => "megaporn.com/video",
4425);
4426
4427sub find_video {
4428  my ($self, $browser) = @_;
4429
4430  my $site = $sites{($self =~ /::([^:]+)$/)[0]};
4431
4432  my $v;
4433  if ($browser->content =~ /\.v\s*=\s*['"]([^"']+)/
4434      || $browser->uri =~ /v=([^&]+)/
4435      || $browser->response->header("Location") =~ /v=([^&]+)/) {
4436    $v = $1;
4437  } else {
4438    die "Couldn't extract video ID from page";
4439  }
4440
4441  my $xml = "http://www.$site/xml/videolink.php?v=$v";
4442  $browser->get($xml);
4443
4444  die "Unable to get video infomation" unless $browser->response->is_success;
4445
4446  my $k1 = ($browser->content =~ /k1="(\d+)/)[0];
4447  my $k2 = ($browser->content =~ /k2="(\d+)/)[0];
4448  my $un = ($browser->content =~ /un="([^"]+)/)[0];
4449  my $s  = ($browser->content =~ /\ss="(\d+)/)[0];
4450
4451  my $title = uri_unescape(($browser->content =~ /title="([^"]+)/)[0]);
4452  my $filename = title_to_filename($title);
4453
4454  my $url = "http://www$s.$site/files/" . _decrypt($un, $k1, $k2) . "/";
4455
4456  return $url, $filename;
4457}
4458
4459sub _decrypt {
4460  my($un, $k1, $k2) = @_;
4461
4462  my @c = split //, join "",
4463    map { substr unpack("B8", pack "h", $_), 4 } split //, $un;
4464
4465  my @iv;
4466  my $i = 0;
4467  while($i < 384) {
4468    $k1 = ($k1 * 11 + 77213) % 81371;
4469    $k2 = ($k2 * 17 + 92717) % 192811;
4470    $iv[$i] = ($k1 + $k2) % 128;
4471    $i++;
4472  }
4473
4474  $i = 256;
4475  while($i >= 0) {
4476    my $a = $iv[$i];
4477    my $b = $i-- % 128;
4478
4479    ($c[$a], $c[$b]) = ($c[$b], $c[$a]);
4480  }
4481
4482  $i = 0;
4483  while($i < 128) {
4484    $c[$i] ^= $iv[$i + 256] & 1;
4485    $i++;
4486  }
4487
4488  $i = 0;
4489  my $c = "";
4490  while($i < @c) {
4491    $c .= unpack "h", pack "B8", "0000" . join "", @c[$i .. ($i + 4)];
4492    $i += 4;
4493  }
4494
4495  return $c;
4496}
4497
44981;
4499}
4500##} blib/lib/FlashVideo/Site/Megavideo.pm
4501##{ blib/lib/FlashVideo/Site/Megaporn.pm
4502{
4503package FlashVideo::Site::Megaporn;
4504
4505use strict;
4506BEGIN { FlashVideo::Site::Megavideo->import(); } # (added by utils/combine-perl.pl)
4507use base 'FlashVideo::Site::Megavideo';
4508
45091;
4510}
4511##} blib/lib/FlashVideo/Site/Megaporn.pm
4512BEGIN { $INC{'FlashVideo/Site/Metacafe.pm'}++; }
4513# Part of get-flash-videos. See get_flash_videos for copyright.
4514##{ blib/lib/FlashVideo/Site/Metacafe.pm
4515{
4516package FlashVideo::Site::Metacafe;
4517
4518use strict;
4519BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4520BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4521use URI::Escape;
4522
4523sub find_video {
4524  my ($self, $browser) = @_;
4525
4526  if ($browser->response->header("Location") =~ /Openx/) {
4527    my $filter = "http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user&filters=0&prevURL=" . $browser->uri->path;
4528    debug "Disabling family filter by getting $filter";
4529
4530    $browser->allow_redirects;
4531    $browser->get($filter);
4532  }
4533
4534  my $url;
4535  if ($browser->content =~ m'mediaURL=(http.+?)&') {
4536    $url = uri_unescape($1);
4537  } else {
4538    die "Couldn't find mediaURL parameter.";
4539  }
4540
4541  if ($browser->content =~ m'gdaKey=(.+?)&') {
4542    $url .= "?__gda__=" . uri_unescape($1);
4543  } else {
4544  }
4545
4546  my $filename = title_to_filename(extract_title($browser));
4547
4548  return ($url, $filename);
4549}
4550
45511;
4552}
4553##} blib/lib/FlashVideo/Site/Metacafe.pm
4554BEGIN { $INC{'FlashVideo/Site/Mitworld.pm'}++; }
4555# Part of get-flash-videos. See get_flash_videos for copyright.
4556##{ blib/lib/FlashVideo/Site/Mitworld.pm
4557{
4558package FlashVideo::Site::Mitworld;
4559
4560use strict;
4561BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4562BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4563
4564sub find_video {
4565  my ($self, $browser) = @_;
4566
4567  my($title) = $browser->content =~ m{id="video-meta">\s*<h2>(.*?)</h2>}s;
4568  if(!$title) {
4569    $title = extract_title($browser);
4570    $title =~ s/\|.*//;
4571  }
4572
4573  my($host) = $browser->content =~ m{host:\s*"(.*?)"};
4574  my($flv) = $browser->content =~ m{flv:\s*"(.*?)"};
4575
4576  return {
4577    rtmp => "rtmp://$host/ondemand/ampsflash/$flv?_fcs_vhost=$host",
4578    flv  => title_to_filename($title)
4579  };
4580}
4581
45821;
4583}
4584##} blib/lib/FlashVideo/Site/Mitworld.pm
4585BEGIN { $INC{'FlashVideo/Site/Mofosex.pm'}++; }
4586# Part of get-flash-videos. See get_flash_videos for copyright.
4587##{ blib/lib/FlashVideo/Site/Mofosex.pm
4588{
4589package FlashVideo::Site::Mofosex;
4590
4591use strict;
4592BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4593BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4594
4595sub find_video {
4596  my ($self, $browser, $embed_url) = @_;
4597
4598  my $filename = title_to_filename($browser->content =~ /<title>(.*?)<\//);
4599
4600  $browser->allow_redirects;
4601
4602  my $playlist = ($browser->content =~ /videoPath=(.+?)%26page/)[0];
4603  $browser->get($playlist);
4604
4605  my $url = ($browser->content =~ /<url>(.+?)<\/url>/)[0];
4606
4607  return $url, $filename;
4608}
4609
46101;
4611}
4612##} blib/lib/FlashVideo/Site/Mofosex.pm
4613BEGIN { $INC{'FlashVideo/Site/Msn.pm'}++; }
4614# Part of get-flash-videos. See get_flash_videos for copyright.
4615##{ blib/lib/FlashVideo/Site/Msn.pm
4616{
4617package FlashVideo::Site::Msn;
4618
4619use strict;
4620BEGIN { FlashVideo::Site::Bing->import(); } # (added by utils/combine-perl.pl)
4621use base 'FlashVideo::Site::Bing';
4622
46231;
4624}
4625##} blib/lib/FlashVideo/Site/Msn.pm
4626BEGIN { $INC{'FlashVideo/Site/Msnbc.pm'}++; }
4627# Part of get-flash-videos. See get_flash_videos for copyright.
4628##{ blib/lib/FlashVideo/Site/Msnbc.pm
4629{
4630package FlashVideo::Site::Msnbc;
4631
4632use strict;
4633BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4634BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
4635
4636sub find_video {
4637  my ($self, $browser, $embed_url) = @_;
4638
4639  $browser->allow_redirects;
4640
4641  my $id;
4642  my $location;
4643  if ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/.+#([0-9]+)/) {
4644    $location = $1;
4645    $id = $3;
4646  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/([0-9]+)/) {
4647    $location = $1;
4648    $id = $3;
4649  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/.+#([0-9]+)/) {
4650    $location = $1;
4651    $id = $3;
4652  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/#([0-9]+)/) {
4653    $location = $1;
4654    $id = $3;
4655  }
4656  die "Unable to find location and videoid" unless $location and $id;
4657
4658  $browser->get($location . $id . '/displaymode/1219/'); # http://today.msnbc.msn.com/id/$id/displaymode/1219/
4659
4660  my $xml = from_xml($browser->content);
4661
4662  my $title;
4663  my $url;
4664  if ($xml->{video}->{docid} eq $id) {
4665    $title = $xml->{video}->{title};
4666    foreach my $media (@{$xml->{video}->{media}}) {
4667      if ($media->{type} =~ /flashVideo$/i) {
4668        $url = $media->{content};
4669        last; #prefer http get over rtmp
4670      } elsif ($media->{type} =~ /flashVideoStream$/i) {
4671        $browser->get($media->{content});
4672        if ($browser->content =~ /<FlashLink>(.+)<\/FlashLink>/i) {
4673          $url = $1; #rtmp
4674        }
4675      }
4676    }
4677  }
4678  die "Unable to extract video url" unless $url;
4679
4680  if ($url =~ /^rtmp/i) {
4681    return {
4682      rtmp => $url,
4683      flv => title_to_filename($title)
4684    };
4685  }
4686
4687  return $url, title_to_filename($title);
4688}
4689
46901;
4691}
4692##} blib/lib/FlashVideo/Site/Msnbc.pm
4693BEGIN { $INC{'FlashVideo/Site/Mtvnservices.pm'}++; }
4694# Part of get-flash-videos. See get_flash_videos for copyright.
4695##{ blib/lib/FlashVideo/Site/Mtvnservices.pm
4696{
4697package FlashVideo::Site::Mtvnservices;
4698
4699
4700use strict;
4701BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4702BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; *from_xml = \&FlashVideo::Utils::from_xml; }
4703use URI::Escape;
4704
4705my $MTVN_URL = qr{http://\w+.mtvnservices.com/(?:\w+/)?mgid:[a-z0-9:.\-_]+};
4706my $MTVN_ALT_URL = qr{mgid:[a-z0-9:.\-_]+};
4707
4708sub find_video {
4709  my ($self, $browser, $embed_url) = @_;
4710
4711  my $page_url = $browser->uri->as_string;
4712
4713  if($embed_url !~ $MTVN_URL) {
4714    if($browser->content =~ m!($MTVN_URL)!) {
4715      $embed_url = $1;
4716    } elsif($browser->content =~ m!($MTVN_ALT_URL)!) {
4717      $embed_url = "http://media.mtvnservices.com/$1";
4718    } else {
4719      die "Unable to find embedding URL";
4720    }
4721  }
4722
4723  $browser->get($embed_url);
4724  die "Unable to get embed URL" unless $browser->response->code =~ /^30\d$/;
4725
4726  my %param;
4727  my $location = $browser->response->header("Location");
4728  for(split /&/, (split /\?/, $location)[-1]) {
4729    my($n, $v) = split /=/;
4730    $param{$n} = uri_unescape($v);
4731  }
4732
4733  die "No config_url/id found\n" unless $param{CONFIG_URL};
4734
4735  $browser->get($param{CONFIG_URL});
4736  my $xml = from_xml_urlfix($browser);
4737
4738  if($xml->{player}->{feed} && !ref $xml->{player}->{feed}) {
4739    my $feed = uri_unescape($xml->{player}->{feed});
4740    $feed =~ s/\{([^}]+)\}/$param{$1}/g;
4741
4742    $browser->get($feed);
4743
4744    return $self->handle_feed($browser->content, $browser, $page_url, $param{uri});
4745  } elsif(ref $xml->{player}->{feed}->{rss}) {
4746    return $self->handle_feed($xml->{player}->{feed}->{rss}, $browser, $page_url, $param{uri});
4747  } else {
4748    die "Unable to find feed\n";
4749  }
4750}
4751
4752sub handle_full_episode {
4753  my($self, $items, $filename, $browser, $page_url, $uri) = @_;
4754
4755  my @rtmpdump_commands;
4756
4757  debug "Handling full episode";
4758
4759  foreach (@$items) {
4760    my $item = $_;
4761
4762    my $affect_counters = (grep { $_->{scheme} eq "urn:mtvn:affect_counters" } @{$item->{"media:group"}->{"media:category"}})[0];
4763    my $iscommercial = 0;
4764    if (defined $affect_counters && $affect_counters->{content} eq 'false') {
4765      $iscommercial = 1;
4766    }
4767
4768    if (!$iscommercial) {
4769      my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url};
4770      die "Unable to find mediagen URL\n" unless $mediagen_url;
4771
4772      $browser->get($mediagen_url);
4773      my $xml = from_xml_urlfix($browser);
4774
4775      my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY'
4776        ?  @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition};
4777      $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY';
4778
4779      my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src};
4780
4781      my $mediagen_id;
4782      if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){
4783        $mediagen_id = $1;
4784      } else {
4785        $mediagen_id = $mediagen_url;
4786      }
4787
4788      $browser->allow_redirects;
4789
4790      push @rtmpdump_commands, {
4791        flv => title_to_filename($item->{"media:group"}->{"media:title"}),
4792        rtmp => $url,
4793        pageUrl => $item->{"link"},
4794        swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id)
4795      };
4796    }
4797  }
4798
4799  return \@rtmpdump_commands;
4800}
4801
4802sub handle_clip {
4803  my($self, $items, $filename, $browser, $page_url, $uri) = @_;
4804
4805  debug "Handling clip";
4806
4807  my $item = ref $items eq 'ARRAY' ?
4808    (grep { $_->{guid}->{content} eq $uri } @$items)[0] :
4809    $items;
4810
4811  my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url};
4812  die "Unable to find mediagen URL\n" unless $mediagen_url;
4813
4814  $browser->get($mediagen_url);
4815  my $xml = from_xml_urlfix($browser);
4816
4817  my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY'
4818    ?  @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition};
4819  $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY';
4820
4821  my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src};
4822
4823  my $mediagen_id;
4824  if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){
4825    $mediagen_id = $1;
4826  } else {
4827    $mediagen_id = $mediagen_url;
4828  }
4829
4830  $browser->allow_redirects;
4831
4832  if($url =~ /^rtmpe?:/) {
4833    return {
4834      flv => $filename,
4835      rtmp => $url,
4836      pageUrl => $page_url,
4837      swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id)
4838    };
4839  } else {
4840    return $url, $filename;
4841  }
4842}
4843
4844sub handle_feed {
4845  my($self, $feed, $browser, $page_url, $uri) = @_;
4846
4847  my $xml = ref $feed ? $feed : from_xml_urlfix($feed);
4848
4849  my $filename = title_to_filename($xml->{channel}->{title});
4850
4851  my $items = $xml->{channel}->{item};
4852  my $categories = ref $items eq 'ARRAY' ? @$items[0]->{"media:group"}->{"media:category"} : $items->{"media:group"}->{"media:category"};
4853
4854  if (ref $categories eq 'ARRAY' && (
4855      (grep { $_->{scheme} eq "urn:mtvn:display:seo" } @$categories)[0]->{content} eq "" ||
4856      (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "Full Episode" ||
4857      (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "full_episode_segment")) {
4858    return $self->handle_full_episode($items, $filename, $browser, $page_url, $uri);
4859  } else {
4860    return $self->handle_clip($items, $filename, $browser, $page_url, $uri);
4861  }
4862}
4863
4864sub can_handle {
4865  my($self, $browser, $url) = @_;
4866
4867  return $browser->content =~ /mtvnservices\.com/i;
4868}
4869
4870
4871sub from_xml_urlfix {
4872  my($xmltext) = @_;
4873  $xmltext =~ s/&(?!amp;)/&amp;/g;  # too lax?
4874  return from_xml($xmltext);
4875}
4876
48771;
4878}
4879##} blib/lib/FlashVideo/Site/Mtvnservices.pm
4880BEGIN { $INC{'FlashVideo/Site/Muzu.pm'}++; }
4881# Part of get-flash-videos. See get_flash_videos for copyright.
4882##{ blib/lib/FlashVideo/Site/Muzu.pm
4883{
4884package FlashVideo::Site::Muzu;
4885
4886use strict;
4887BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4888BEGIN { no strict 'refs'; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4889use HTML::Entities;
4890
4891sub find_video {
4892  my ($self, $browser) = @_;
4893
4894  if ($browser->response->code == 302) {
4895    $browser->allow_redirects;
4896    $browser->get($browser->response->header('Location'))
4897  }
4898
4899  $browser->content =~ /id="trackHeading">(.*?)</;
4900  my $title = $1;
4901
4902  if (!$title) {
4903    $browser->content =~ /id="videosPageMainTitleH1">(.*?)</s;
4904    $title = $1;
4905  }
4906
4907  my $filename = title_to_filename(decode_entities($title));
4908
4909  my $flashvars = ($browser->content =~ m'flashvars:(?:\s+getPlayerData\(\)\s+\+\s+)?"([^"]+)')[0];
4910  die "Unable to extract flashvars" unless $flashvars;
4911
4912  my %map = (
4913    networkId    => "id",
4914    assetId      => "assetId",
4915    vidId        => "assetId",
4916    startChannel => "playlistId",
4917  );
4918
4919  my $playAsset = "http://www.muzu.tv/player/playAsset/?";
4920  for(split /&/, $flashvars) {
4921    my($n, $v) = split /=/;
4922    $playAsset .= "$map{$n}=$v&" if exists $map{$n};
4923  }
4924
4925  $browser->get($playAsset);
4926  die "Unable to get $playAsset" if $browser->response->is_error;
4927
4928  my $url = ($browser->content =~ /src="([^"]+)/)[0];
4929  $url = decode_entities($url);
4930  die "Unable to find video URL" unless $url;
4931
4932  if($url =~ /^rtmp:/) {
4933    my($playpath) = $url =~ m{/([^/]+)$};
4934
4935    return {
4936      flv => $filename,
4937      rtmp => $url,
4938      playpath => $playpath,
4939      $url =~ /live/ ? (live => 1) : ()
4940    };
4941
4942  } else {
4943    return $url, $filename;
4944  }
4945}
4946
49471;
4948}
4949##} blib/lib/FlashVideo/Site/Muzu.pm
4950BEGIN { $INC{'FlashVideo/Site/Mylifetime.pm'}++; }
4951# Part of get-flash-videos. See get_flash_videos for copyright.
4952##{ blib/lib/FlashVideo/Site/Mylifetime.pm
4953{
4954package FlashVideo::Site::Mylifetime;
4955
4956use strict;
4957BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4958BEGIN { no strict 'refs'; }
4959BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
4960use base 'FlashVideo::Site::Brightcove';
4961
4962my $JS_RE = qr/displayFlash\(/;
4963
4964sub find_video {
4965  my($self, $browser, $embed_url) = @_;
4966
4967  my($player_id, $video_id) = $browser->content =~ /$JS_RE\s*"(\d+)",\s*"(\d+)"/;
4968  die "Unable to extract video ids" unless $video_id;
4969
4970  return $self->amfgateway($browser, $player_id, { videoId => $video_id });
4971}
4972
4973sub can_handle {
4974  my($self, $browser, $url) = @_;
4975
4976  return $browser->content =~ $JS_RE;
4977}
4978
49791;
4980}
4981##} blib/lib/FlashVideo/Site/Mylifetime.pm
4982BEGIN { $INC{'FlashVideo/Site/Myvideo.pm'}++; }
4983# Part of get-flash-videos. See get_flash_videos for copyright.
4984##{ blib/lib/FlashVideo/Site/Myvideo.pm
4985{
4986package FlashVideo::Site::Myvideo;
4987
4988use strict;
4989BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
4990BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
4991
4992sub find_video {
4993  my ($self, $browser, $embed_url) = @_;
4994
4995  my $video_url;
4996
4997  if ($browser->content =~ m{<link rel='image_src' href='(http://[^'"]+)'}) {
4998    $video_url = $1;
4999  }
5000
5001  $video_url =~ s|thumbs/||;
5002  $video_url =~ s|_\d\.jpg$|.flv|;
5003
5004  my $title = (split /\//, $browser->uri->as_string)[-1];
5005
5006  return $video_url, title_to_filename($title);
5007}
5008
50091;
5010}
5011##} blib/lib/FlashVideo/Site/Myvideo.pm
5012BEGIN { $INC{'FlashVideo/Site/Nasa.pm'}++; }
5013# Part of get-flash-videos. See get_flash_videos for copyright.
5014##{ blib/lib/FlashVideo/Site/Nasa.pm
5015{
5016package FlashVideo::Site::Nasa;
5017
5018use strict;
5019BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5020BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5021BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
5022BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
5023
5024sub find_video {
5025  my ($self, $browser, $embed_url) = @_;
5026
5027  my $uri = $browser->uri();
5028  my $path = $uri->path();
5029  $path =~ s/index\.html//;               # strip the index.htm at the end of the path.
5030  $path = $path . "vmixVideoLanding2.js"; # specify the javascript src
5031
5032  debug "Nasa videogallery query is " . $uri->query();
5033  my ($media_id) = $uri->query() =~ m/media_id=(\d+)/;
5034
5035  die "Nasa support requires 'media_id=nnnnnnnn' in the query" unless $media_id;
5036
5037  $uri->path($path);                      # Change path to javascript src
5038  $uri->query(undef());                   # Remove the query
5039
5040  info "Downloading video source instructions at " . $uri;
5041  $browser->get($uri);
5042
5043  die "Could not locate video source" unless $browser->success();
5044
5045  my $videojs = $browser->content();      # content is javascript
5046
5047  my ($api_url_host) = $browser->content() =~ m{var +api_url *= *'([^']*)' *;};
5048  die "Could not extract video server" unless $api_url_host;
5049
5050  my ($atoken) = $browser->content() =~ m{var +atoken *= *'([^']*)' *;};
5051
5052  my $query = 'http://' . $api_url_host . '/apis/media.php?action=getMedia&export=JSONP&media_id=' . $media_id . '&atoken=' . $atoken . '&callback=loadCurrentVideo1';
5053
5054  info "Downloading video details from http://" . $api_url_host;
5055  $browser->get($query);
5056  die "Could not get video details" unless $browser->success();
5057
5058  my $result = from_json($browser->content());
5059
5060  my $url = $result->{url};
5061  die "Could not extract video url" unless $url;
5062  $url =~ s/\/core\//\/core-dl\//;
5063
5064  my $filename = $result->{title};
5065  $filename = title_to_filename($filename, "mp4");
5066
5067  return $url, $filename;
5068}
5069
50701;
5071}
5072##} blib/lib/FlashVideo/Site/Nasa.pm
5073BEGIN { $INC{'FlashVideo/Site/Nbc.pm'}++; }
5074# Part of get-flash-videos. See get_flash_videos for copyright.
5075##{ blib/lib/FlashVideo/Site/Nbc.pm
5076{
5077package FlashVideo::Site::Nbc;
5078
5079use strict;
5080BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5081BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
5082use MIME::Base64;
5083
5084sub find_video {
5085  my ($self, $browser, $embed_url) = @_;
5086
5087  my $has_amf_packet = eval { require Data::AMF::Packet };
5088  if (!$has_amf_packet) {
5089    die "Must have Data::AMF::Packet installed to download Nbc videos";
5090  }
5091
5092
5093  my $video_id;
5094  if ($browser->uri->as_string =~ /\/([0-9]+)\//) {
5095    $video_id = $1;
5096  }
5097
5098  my $packet = Data::AMF::Packet->deserialize(decode_base64("AAAAAAABABZnZXRDbGlwSW5mby5nZXRDbGlwQWxsAAIvMQAAAB8KAAAABAIABzEyMjc2MTECAAJVUwIAAzYzMgIAAi0xCg=="));
5099
5100  $packet->messages->[0]->{value}->[0] = $video_id;
5101
5102  if($self->debug) {
5103    require Data::Dumper;
5104    debug Data::Dumper::Dumper($packet);
5105  }
5106
5107  my $data = $packet->serialize;
5108
5109  $browser->post(
5110    "http://video.nbcuni.com/amfphp/gateway.php",
5111    Content_Type => "application/x-amf",
5112    Content => $data
5113  );
5114
5115  die "Failed to post to Nbc AMF gateway"
5116    unless $browser->response->is_success;
5117
5118  debug $browser->content;
5119
5120
5121  my($clipurl) = $browser->content =~ /clipurl.{0,5}(nbc[^\0]+)/;
5122
5123  my($title) = $browser->content =~ /headline.{1,3}([^\0]+)/;
5124
5125  debug $clipurl;
5126  debug $title;
5127
5128  $browser->get("http://video.nbcuni.com/$clipurl");
5129  my $xml = from_xml($browser);
5130  my $video_path = $xml->{body}->{switch}->{ref}->{src};
5131
5132  $browser->get("http://videoservices.nbcuni.com/player/config?configId=17010&clear=true"); # I don't know what configId means but it seems to be generic
5133  my $xml = from_xml($browser);
5134  my $app = $xml->{akamaiAppName};
5135  my $host = $xml->{akamaiHostName};
5136
5137  $browser->get("http://$host/fcs/ident");
5138  my $xml = from_xml($browser);
5139  my $ip = $xml->{ip};
5140  my $port = "1935";
5141
5142  my $rtmpurl = "rtmp://$ip:$port/$app/$video_path";
5143
5144  return {
5145    rtmp => $rtmpurl,
5146    swfUrl => "http://www.nbc.com/[[IMPORT]]/video.nbcuni.com/outlet/extensions/inext_video_player/video_player_extension.swf?4.5.3",
5147    tcUrl => "rtmp://$ip:$port/$app?_fcs_vhost=$host",
5148    flv => title_to_filename($title)
5149  };
5150}
5151
51521;
5153}
5154##} blib/lib/FlashVideo/Site/Nbc.pm
5155BEGIN { $INC{'FlashVideo/Site/Nfb.pm'}++; }
5156# Part of get-flash-videos. See get_flash_videos for copyright.
5157#################################################
5158#
5159# This file was automatically generated by utils/combine-perl.pl
5160# You should edit the original files, not this
5161# combined version.
5162#
5163# The original files are available at:
5164# http://github.com/monsieurvideo/get-flash-videos
5165#
5166#################################################
5167# Except the CCR bits, thanks to Fogerty for those.
5168##{ blib/lib/FlashVideo/Site/Nfb.pm
5169{
5170package FlashVideo::Site::Nfb;
5171
5172use strict;
5173BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5174BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
5175
5176sub find_video {
5177  my ($self, $browser, $embed_url, $prefs) = @_;
5178
5179  my($refer, $cURL) = $browser->content =~ /<link rel="video_src" href="([^?]+)\?configURL=([^&]+)&/;
5180
5181  $browser->post(
5182    $cURL,
5183    "X-NFB-Referer" => $refer,
5184    Content_Type => "application/x-www-form-urlencoded",
5185    Content => "getConfig=true",
5186  );
5187
5188  if (!$browser->success) {
5189    die "Getting config info failed: " . $browser->response->status_line();
5190  }
5191
5192  my $xml = from_xml($browser->content);
5193
5194  my $media;
5195  foreach (@{$xml->{player}->{stream}->{media}}) {
5196    if ($_->{"type"} eq "video") {
5197      $media = $_;
5198      last;
5199    }
5200  }
5201
5202  my $title = $media->{title};
5203
5204
5205  my @assets = sort { _get_quality_from_url($b->{default}->{url}) <=> _get_quality_from_url($a->{default}->{url}) }
5206                    (@{$media->{assets}->{asset}});
5207
5208  if (!@assets) {
5209    die "Couldn't find any streams in the config file";
5210  }
5211
5212  my $quality = $prefs->{quality};
5213  my $asset;
5214  if ($quality eq "high") {
5215    $asset = $assets[0];
5216  } elsif ($quality eq "low") {
5217    $asset = $assets[-1];
5218  } elsif ($quality eq "medium") {
5219    if (scalar(@assets) > 1) {
5220      $asset = $assets[1];
5221    } else {
5222      $asset = $assets[0];
5223    }
5224  } else {
5225    die "Unknown quality setting";
5226  }
5227
5228  my $rtmp_url = $asset->{default}->{streamerURI};
5229  my($host, $app) = $rtmp_url =~ m'rtmp://([^/]+)/(\w+)';
5230  my $playpath = $asset->{default}->{url};
5231
5232  return {
5233    flv => title_to_filename($title),
5234    rtmp => $rtmp_url,
5235    app => $app,
5236    playpath => $playpath
5237  };
5238}
5239
5240sub _get_quality_from_url {
5241  my($url) = @_;
5242
5243  if ($url =~ m'/streams/[A-Z](\d+)([A-Z])') {
5244    my ($size, $units) = ($1, $2);
5245
5246    $size *= 1024 if $units eq 'M';
5247
5248    return $size;
5249  }
5250}
5251
52521;
5253}
5254##} blib/lib/FlashVideo/Site/Nfb.pm
5255BEGIN { $INC{'FlashVideo/Site/Nick.pm'}++; }
5256# Part of get-flash-videos. See get_flash_videos for copyright.
5257##{ blib/lib/FlashVideo/Site/Nick.pm
5258{
5259package FlashVideo::Site::Nick;
5260
5261use strict;
5262BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5263BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; *from_xml = \&FlashVideo::Utils::from_xml; }
5264use URI::Escape;
5265
5266sub find_video {
5267  my ($self, $browser, $embed_url) = @_;
5268
5269
5270  my $page_url = $browser->uri->as_string;
5271
5272  my $title;
5273  if($browser->content =~ /<span content=["']([\w \.:]+)["'] property=["']media:title["']\/>/) {
5274    $title = $1;
5275  } else {
5276    $title = "nothing";
5277  }
5278
5279  my $cmsId;
5280  if($browser->content =~ /KIDS\.add\("cmsId", "(\d+)"\);/) {
5281    $cmsId = $1;
5282  } else {
5283    die "Couldn't get the cmsId.";
5284  }
5285
5286  my $site;
5287  if($browser->content =~ /KIDS\.add\(["']site["'], ["']([\w\.]+)["']\);/) {
5288    $site = lc($1);
5289  } else {
5290    die "Couldn't get the site.";
5291  }
5292
5293  my $type;
5294  if($browser->content =~ /KIDS\.add\(["']type["'], ["']([a-z]+)["']\);/) {
5295    $type = $1;
5296  } else {
5297    $type = "video";
5298  }
5299
5300  my $uri = "mgid:cms:$type:$site:$cmsId";
5301
5302  $browser->get("http://www.nick.com/dynamo/video/data/mediaGen.jhtml?mgid=$uri");
5303  my $xml = from_xml($browser->content);
5304  my $rtmp_url = $xml->{video}->{item}[0]->{rendition}[0]->{src};
5305
5306  return {
5307    rtmp => $rtmp_url,
5308    flv => title_to_filename($title),
5309    pageUrl => $page_url,
5310    swfhash($browser, "http://media.nick.com/" . $uri)
5311  };
5312}
5313
5314sub can_handle {
5315  my($self, $browser) = @_;
5316  return $browser->content =~ /<script src=["']http:\/\/media.nick.com\/player\/scripts\/mtvn_player_control\.1\.0\.1\.js["']/;
5317}
5318
53191;
5320}
5321##} blib/lib/FlashVideo/Site/Nick.pm
5322BEGIN { $INC{'FlashVideo/Site/Nicovideo.pm'}++; }
5323# Part of get-flash-videos. See get_flash_videos for copyright.
5324##{ blib/lib/FlashVideo/Site/Nicovideo.pm
5325{
5326package FlashVideo::Site::Nicovideo;
5327
5328use strict;
5329BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5330BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5331use URI::Escape;
5332
5333sub find_video {
5334  my ($self, $browser, $embed_url) = @_;
5335  my $id = ($embed_url =~ /([ns]m\d+)/)[0];
5336  die "No ID found\n" unless $id;
5337
5338  my $base = "http://ext.nicovideo.jp/thumb_watch/$id";
5339
5340  if($embed_url !~ /ext\.nicovideo\.jp\/thumb_watch/) {
5341    $embed_url = "$base?w=472&h=374&n=1";
5342  }
5343
5344  $browser->get($embed_url);
5345  my $playkey = ($browser->content =~ /'thumbPlayKey': '([^']+)/)[0];
5346  die "No playkey found\n" unless $playkey;
5347
5348  my $title = ($browser->content =~ /title: '([^']+)'/)[0];
5349  $title =~ s/\\u([a-f0-9]{1,5})/chr hex $1/eg;
5350
5351  $browser->get($base . "/$playkey");
5352  my $url = uri_unescape(($browser->content =~ /url=([^&]+)/)[0]);
5353
5354  return $url, title_to_filename($title, $id =~ /^nm/ ? "swf" : "flv");
5355}
5356
53571;
5358}
5359##} blib/lib/FlashVideo/Site/Nicovideo.pm
5360BEGIN { $INC{'FlashVideo/Site/Ooyala.pm'}++; }
5361# Part of get-flash-videos. See get_flash_videos for copyright.
5362##{ blib/lib/FlashVideo/Site/Ooyala.pm
5363{
5364package FlashVideo::Site::Ooyala;
5365
5366use strict;
5367BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5368BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
5369BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
5370BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
5371use File::Basename;
5372use HTML::Entities;
5373use URI::Escape;
5374use Data::Dumper;
5375
5376sub find_video {
5377  my ($self, $browser, $embed_url, $prefs) = @_;
5378
5379  debug $embed_url;
5380
5381  my ($player_js) = uri_unescape(
5382    decode_entities(
5383      $browser->content =~ m{<script src=["'](http://player\.ooyala\.com/player\.js[^'"]*)['"]>}
5384    )
5385  );
5386
5387  die 'Could not find player.js URL' unless $player_js;
5388
5389  $browser->get($player_js);
5390
5391  my ($mobile_player_js) =
5392    $browser->content =~ m{mobile_player_url *= *['"]([^'"]*)["']};
5393  $mobile_player_js .= 'unknown&domain=unknown';
5394
5395  die 'Could not find mobile_player.js URL' unless $mobile_player_js;
5396
5397  $browser->get($mobile_player_js);
5398
5399  my ($streams) = $browser->content =~ m{streams *= *[^;]*eval\("(.*?)"\);};
5400
5401  die 'Could not find streams in mobile_player.js' unless $streams;
5402
5403  my $data = from_json(json_unescape($streams));
5404
5405  my $title = $data->[0]{title};
5406  my $url;
5407  if ($prefs->{quality} =~ /high|ipad/) {
5408    $url = $data->[0]{ipad_url};
5409  } else {
5410     $url =$data->[0]{url};
5411  }
5412
5413  $browser->allow_redirects;
5414
5415  return $url, title_to_filename($title, 'mp4');
5416}
5417
5418sub can_handle {
5419  my($self, $browser, $url) = @_;
5420
5421  return 1 if $url && URI->new($url)->host =~ /\.ooyala\.com$/;
5422
5423  return $browser->content =~ m{<script src=["']http://player\.ooyala\.com/player\.js[^'"]*['"]>};
5424}
5425
54261;
5427}
5428##} blib/lib/FlashVideo/Site/Ooyala.pm
5429BEGIN { $INC{'FlashVideo/Site/Pbs.pm'}++; }
5430# Part of get-flash-videos. See get_flash_videos for copyright.
5431##{ blib/lib/FlashVideo/Site/Pbs.pm
5432{
5433package FlashVideo::Site::Pbs;
5434
5435use strict;
5436use warnings;
5437
5438BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5439BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
5440use MIME::Base64 qw(decode_base64);
5441
5442
5443sub find_video {
5444  my ($self, $browser, $embed_url, $prefs) = @_;
5445
5446  die "Must have Crypt::Rijndael installed to download from PBS"
5447    unless eval { require Crypt::Rijndael };
5448
5449  my ($media_id) = $browser->uri->as_string =~ m[
5450    ^http://video\.pbs\.org/video/(\d+)
5451  ]x;
5452  unless (defined $media_id) {
5453    ($media_id) = $browser->content =~ m[
5454      http://video\.pbs\.org/widget/partnerplayer/(\d+)
5455    ]x;
5456  }
5457  unless (defined $media_id) {
5458    ($media_id) = $browser->content =~ m[
5459      /embed-player[^"]+\bepisodemediaid=(\d+)
5460    ]x;
5461  }
5462  unless (defined $media_id) {
5463    ($media_id) = $browser->content =~ m[var videoUrl = "([^"]+)"];
5464  }
5465  unless (defined $media_id) {
5466    my ($pap_id, $youtube_id) = $browser->content =~ m[
5467      \bDetectFlashDecision\ \('([^']+)',\ '([^']+)'\);
5468    ]x;
5469    if ($youtube_id) {
5470      debug "Youtube ID found, delegating to Youtube plugin\n";
5471      my $url = "http://www.youtube.com/v/$youtube_id";
5472      require FlashVideo::Site::Youtube;
5473      return FlashVideo::Site::Youtube->find_video($browser, $url, $prefs);
5474    }
5475  }
5476  die "Couldn't find media_id\n" unless defined $media_id;
5477  debug "media_id: $media_id\n";
5478
5479  $browser->get("http://video.pbs.org/videoPlayerInfo/$media_id");
5480
5481  my $xml = $browser->content;
5482  $xml =~ s/&/&amp;/g;
5483  my $href = from_xml($xml);
5484  my $file = $href->{videoInfo}->{title};
5485  my $release_url = $href->{releaseURL};
5486
5487  unless ($release_url =~ m[^https?://]) {
5488    debug "encrypted release url: $release_url\n";
5489    my ($type, $iv, $ciphertext) = split '\$', $release_url, 3;
5490    $release_url = undef;
5491
5492    my $key = 'RPz~i4p*FQmx>t76';
5493
5494    my $cipher = Crypt::Rijndael->new($key, Crypt::Rijndael->MODE_CBC);
5495    $iv = pack 'H*', $iv if 32 == length $iv;
5496    $cipher->set_iv($iv);
5497
5498    $release_url = $cipher->decrypt(decode_base64($ciphertext));
5499    $release_url =~ s/\s+$//;
5500  }
5501  debug "unencrypted release url: $release_url\n";
5502
5503  $browser->get($release_url);
5504
5505  my $rtmp_url = $browser->res->header('location')
5506    || from_xml($browser->content)->{choice}{url}
5507    || die "Couldn't find stream url\n";
5508  $rtmp_url =~ s/<break>//;
5509
5510  if(!$file) {
5511    ($file) = $rtmp_url =~ m{([^/\?]+)$};
5512  }
5513
5514  return {
5515    rtmp    => $rtmp_url,
5516    pageUrl => $embed_url,
5517    swfUrl  => 'http://www-tc.pbs.org/video/media/swf/PBSPlayer.swf?18809',
5518    flv     => title_to_filename($file),
5519  };
5520}
5521
55221;
5523}
5524##} blib/lib/FlashVideo/Site/Pbs.pm
5525BEGIN { $INC{'FlashVideo/Site/Pennyarcade.pm'}++; }
5526# Part of get-flash-videos. See get_flash_videos for copyright.
5527##{ blib/lib/FlashVideo/Site/Pennyarcade.pm
5528{
5529package FlashVideo::Site::Pennyarcade;
5530
5531use strict;
5532BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5533BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5534
5535sub find_video {
5536  my ($self, $browser, $embed_url) = @_;
5537
5538  my $id;
5539	my $title;
5540	if ($browser->content =~/<h2>(.*?)<\/h2>/) {
5541		$title = $1;
5542		$title =~ s/<[^>]*>//g;
5543	}
5544	if ($browser->content =~/http:\/\/blip.tv\/play\/(.*).html/) {
5545		$id = $1;
5546	} else {
5547		die "No ID found\n";
5548	}
5549
5550	$browser->add_header("User-Agent" => "Android");
5551	$browser->allow_redirects;
5552	return "http://blip.tv/play/$id.mp4", title_to_filename($title);
5553}
5554
55551;
5556}
5557##} blib/lib/FlashVideo/Site/Pennyarcade.pm
5558BEGIN { $INC{'FlashVideo/Site/Putlocker.pm'}++; }
5559# Part of get-flash-videos. See get_flash_videos for copyright.
5560##{ blib/lib/FlashVideo/Site/Putlocker.pm
5561{
5562package FlashVideo::Site::Putlocker;
5563
5564use strict;
5565BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5566BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5567use HTML::Tree;
5568
5569sub find_video {
5570  my ($self, $browser, $embed_url) = @_;
5571
5572  my ($filename) = title_to_filename(extract_title($browser));
5573  $filename =~ s/[\s\|_]*PutLocker[\s_]*//;
5574
5575  my $tree = HTML::Tree->new();
5576  $tree->parse($browser->content);
5577  my $hash = $tree->look_down( 'name' , 'hash' )->attr('value');
5578  info 'Found hash: ' . $hash;
5579
5580  info "Confirming request to PutLocker.";
5581
5582  $browser->add_header( 'Content-Type' => 'application/x-www-form-urlencoded' );
5583  $browser->add_header( 'Accept-Encoding' => 'text/html' );
5584  $browser->add_header( Referer => $embed_url );
5585
5586  my $response = $browser->post($embed_url,
5587    [ 'confirm'=>"Continue as Free User",
5588      'hash'=>$hash
5589      ]);
5590
5591  die 'Response code was ' . $response->code . '. Should be 302.' unless ($response->code == '302');
5592
5593  info "Re-fetching page, which will now have the video embedded.";
5594  $browser->delete_header( 'Content-Type');
5595  my $page_html = $browser->get($embed_url)->content;
5596
5597  my ($streamID) = ($page_html =~ /get_file\.php\?stream=([A-Za-z0-9]+)/);
5598  info "Found the stream ID: " . $streamID;
5599
5600  my $uri = URI->new( "http://www.putlocker.com/get_file.php" );
5601  $uri->query_form((stream=>$streamID));
5602
5603  my $contents = $browser->get($uri)->content;
5604  my ($url) = ($contents =~ /url="(.*?)"/);
5605
5606  info "Got the video URL: " . $url;
5607
5608  return $url, $filename;
5609}
5610
56111;
5612
5613}
5614##} blib/lib/FlashVideo/Site/Putlocker.pm
5615BEGIN { $INC{'FlashVideo/Site/Redbull.pm'}++; }
5616# Part of get-flash-videos. See get_flash_videos for copyright.
5617##{ blib/lib/FlashVideo/Site/Redbull.pm
5618{
5619package FlashVideo::Site::Redbull;
5620
5621use strict;
5622BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5623BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
5624use URI;
5625use HTML::Entities;
5626
5627sub find_video {
5628  my ($self, $browser, $page_url) = @_;
5629
5630  my $video_info_url;
5631  my $host = $browser->uri->host;
5632
5633  if ( ($browser->content =~ /data_url:\s+'([^']+)'/) or
5634       ($browser->content =~ m{displayVideoPlayer\('([^']+)'\)})) {
5635    $video_info_url = $1;
5636
5637    $video_info_url = "http://$host$video_info_url";
5638  }
5639
5640  if (!$video_info_url) {
5641    die "Couldn't find video info URL";
5642  }
5643
5644  $browser->get($video_info_url);
5645
5646  if ($browser->response->is_redirect) {
5647    $browser->get($browser->response->header('Location'));
5648  }
5649
5650  if (!$browser->success) {
5651    die "Couldn't download Red Bull video info XML: " .
5652      $browser->response->status_line;
5653  }
5654
5655  my $xml = $browser->content;
5656  $xml =~ s/&amp;//g;
5657  $xml = decode_entities($xml);
5658
5659  my $video_info = from_xml($xml);
5660
5661  my $file_type = "flv";
5662
5663  if ($video_info->{high_video_url} =~ /\.mp4$/) {
5664    $file_type = "mp4";
5665  }
5666
5667  return {
5668    flv  => title_to_filename($video_info->{title}, $file_type),
5669    rtmp => $video_info->{high_video_url},
5670  };
5671}
5672
56731;
5674}
5675##} blib/lib/FlashVideo/Site/Redbull.pm
5676BEGIN { $INC{'FlashVideo/Site/Redtube.pm'}++; }
5677# Part of get-flash-videos. See get_flash_videos for copyright.
5678##{ blib/lib/FlashVideo/Site/Redtube.pm
5679{
5680package FlashVideo::Site::Redtube;
5681
5682use strict;
5683BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5684BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5685use URI::Escape;
5686
5687sub find_video {
5688  my($self, $browser, $embed_url) = @_;
5689
5690  my($title) = $browser->content =~ /<h1 class="videoTitle">([^<]+)</;
5691
5692  my($url) = $browser->content =~ /hashlink=([^&"]+)/;
5693  $url = uri_unescape($url);
5694
5695  $browser->allow_redirects;
5696  return $url, title_to_filename($title);
5697}
5698
56991;
5700}
5701##} blib/lib/FlashVideo/Site/Redtube.pm
5702BEGIN { $INC{'FlashVideo/Site/Ringtv.pm'}++; }
5703# Part of get-flash-videos. See get_flash_videos for copyright.
5704##{ blib/lib/FlashVideo/Site/Ringtv.pm
5705{
5706package FlashVideo::Site::Ringtv;
5707
5708use strict;
5709BEGIN { FlashVideo::Site::Grindtv->import(); } # (added by utils/combine-perl.pl)
5710use base 'FlashVideo::Site::Grindtv';
5711
57121;
5713}
5714##} blib/lib/FlashVideo/Site/Ringtv.pm
5715BEGIN { $INC{'FlashVideo/Site/Sapo.pm'}++; }
5716# Part of get-flash-videos. See get_flash_videos for copyright.
5717##{ blib/lib/FlashVideo/Site/Sapo.pm
5718{
5719package FlashVideo::Site::Sapo;
5720
5721use strict;
5722BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5723BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5724
5725sub find_video {
5726  my ($self, $browser) = @_;
5727
5728  my ($video_url, $type);
5729
5730  if ($browser->content =~ m{flvplayer-sapo\.swf\?file=(http://[^&"]+)}) {
5731    $video_url = $1;
5732
5733    if ($video_url =~ m{/mov}) {
5734      $type = "mp4";
5735    }
5736  }
5737  else {
5738    die "Couldn't extract Sapo video URL";
5739  }
5740
5741  (my $title = extract_title($browser)) =~ s/ - SAPO V\x{ed}deos//;
5742
5743  my $filename = title_to_filename($title, $type);
5744
5745  $browser->allow_redirects(1);
5746
5747  return $video_url, $filename;
5748}
5749
57501;
5751}
5752##} blib/lib/FlashVideo/Site/Sapo.pm
5753BEGIN { $INC{'FlashVideo/Site/Sbs.pm'}++; }
5754# Part of get-flash-videos. See get_flash_videos for copyright.
5755##{ blib/lib/FlashVideo/Site/Sbs.pm
5756{
5757package FlashVideo::Site::Sbs;
5758
5759use strict;
5760BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5761BEGIN { no strict 'refs'; }
5762BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
5763BEGIN { no strict 'refs'; }
5764use File::Basename;
5765use HTML::Entities;
5766use URI::Escape;
5767
5768sub find_video {
5769  my ($self, $browser, $embed_url, $prefs) = @_;
5770
5771  my $smil;
5772  my $baseurl;
5773
5774  my($id) = $browser->content =~ /firstVidId = '([^']*)';/;
5775  ($smil) = decode_entities($browser->content =~ /player\.releaseUrl = "([^"]*)";/);
5776
5777  if( $id ){
5778
5779    ($baseurl) = $browser->content =~ m{so\.addVariable\("nielsenLaunchURL", *"([^"]*)"\);}s ;
5780    my($menu) = $browser->content =~ m{loadVideo\('([^']*)', '', [^\)]\);}s ;
5781    if( !$menu ){ $menu = $baseurl . '/video/menu/inline/id/' . $id; }
5782    else { $menu = 'http://www.sbs.com.au' . $menu; }
5783    $menu =~ s/' *\+ *firstVidId *\+ *'/$id/g;
5784
5785    die "No menu URL found" unless $menu;
5786
5787    $browser->get($menu);
5788
5789    ($smil) = $browser->content =~ m{<video *name="[^"]*" *id="[^"]*" *src="([^"]*)">}s ;
5790  }
5791
5792  die "no smil" unless $smil;
5793
5794  $browser->get($smil);
5795
5796  ($baseurl) = decode_entities($browser->content =~ m'<meta base="([^"]*)"/>'s);
5797
5798  my @tmp = $browser->content =~ m'<video src="([^"]*)" system-bitrate="([^"]*)"/>'gs;
5799  my %tmp = reverse @tmp;
5800  my $filename;
5801  my $q = $prefs->{quality};
5802  if( grep {$_ eq $q || $_ == $q || $_ == ($q * 100000)} keys(%tmp) ){
5803    $filename = decode_entities($tmp{$q});
5804    if(!$filename){
5805      my @bitrates = grep {$_ == $q || $_ == ($q * 100000)} keys(%tmp);
5806      $filename = decode_entities($tmp{$bitrates[0]});
5807    }
5808  } else {
5809    my @filenames = ();
5810    foreach (sort { $a <=> $b } keys(%tmp) )
5811      { push @filenames, $tmp{$_}; }
5812    my $cnt = @filenames;
5813    my $num = {high => int($cnt/3)*2, medium => int($cnt/3)*1, low => int($cnt/3)*0}->{$q};
5814    $filename = decode_entities($filenames[$num]);
5815  }
5816
5817  die "no filenames" unless $filename;
5818
5819  if( $baseurl =~ /^rtmp:/ ){
5820    my($flvname) = $filename =~ m'[^/]*/(.*)'s;
5821    return {
5822      rtmp => $baseurl,
5823      playpath => $filename,
5824      flv => $flvname,
5825      swfUrl => 'http://www.sbs.com.au/vod/theplatform/core/4_4_3/swf/flvPlayer.swf',
5826    };
5827  } elsif ($baseurl) {
5828    my $url = $baseurl . $filename;
5829    return $url, $filename;
5830  } else {
5831    return $filename, File::Basename::basename($filename);
5832  }
5833}
5834
58351;
5836}
5837##} blib/lib/FlashVideo/Site/Sbs.pm
5838BEGIN { $INC{'FlashVideo/Site/Scivee.pm'}++; }
5839# Part of get-flash-videos. See get_flash_videos for copyright.
5840##{ blib/lib/FlashVideo/Site/Scivee.pm
5841{
5842package FlashVideo::Site::Scivee; # horrible casing :(
5843
5844
5845use strict;
5846BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5847BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
5848use HTML::Entities;
5849sub find_video {
5850
5851  my ($self, $browser) = @_;
5852
5853  my $title;
5854  if ($browser->content =~ /title\>([^\|]+)/) {
5855    $title = $1;
5856  }
5857  else {
5858    $title = extract_info($browser)->{title};
5859  }
5860  my $filename = title_to_filename($title);
5861  my $vid;
5862  if ($browser->content =~ /\/ratings\/(\d+)/) {
5863    $vid = $1;
5864  }
5865  elsif ($browser->content =~ /flashvars="id=(\d+)/) {
5866    $vid = $1;
5867  }
5868  else {
5869    die "Could not find video!";
5870  }
5871  my $url = "http://www.scivee.tv/asset/video/$vid";
5872
5873  return $url, $filename;
5874}
5875
58761;
5877}
5878##} blib/lib/FlashVideo/Site/Scivee.pm
5879BEGIN { $INC{'FlashVideo/Site/Seesaw.pm'}++; }
5880# Part of get-flash-videos. See get_flash_videos for copyright.
5881##{ blib/lib/FlashVideo/Site/Seesaw.pm
5882{
5883package FlashVideo::Site::Seesaw;
5884
5885use strict;
5886BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
5887BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; }
5888use HTML::Entities qw(decode_entities);
5889use URI::Escape qw(uri_escape);
5890
5891my @res = (
5892  { name => "lowResUrl",  resolution => [ 512, 288 ] },
5893  { name => "stdResUrl",  resolution => [ 672, 378 ] },
5894  { name => "highResUrl", resolution => [ 1024, 576 ] }
5895);
5896
5897sub find_video {
5898  my ($self, $browser, $page_url, $prefs) = @_;
5899
5900  my $player_info = ($browser->content =~ m{(/videoplayerinfo/\d+[^"]+)"})[0];
5901
5902  (my $content = $browser->content) =~ s{\\/}{/}g;
5903
5904  my %seen; # avoid duplication in filenames
5905
5906  my %metadata = map { $_ => '' } qw(brandTitle seriesTitle programmeTitle);
5907
5908  my ($series, $episode);
5909
5910  ($series, $episode) = ($browser->content =~ /Series (\d+) - Ep(?:isode)?\.? (\d+)/);
5911
5912  if (!$series and !$episode) {
5913    ($series, $episode) = ($browser->content =~ /series_number: ["']?(\d+)["']?,\s+ep_number: ['"]?(\d+)['"]/);
5914  }
5915
5916  if ($series and $episode) {
5917    $metadata{series_and_episode} = sprintf "S%02dE%02d", $series, $episode;
5918  }
5919
5920  foreach my $metadata_item (keys %metadata) {
5921    if (my $value = ($content =~ m{<$metadata_item>(.*?)</$metadata_item>}isg)[0]) {
5922      $value = decode_entities($value);
5923
5924      next if $seen{$value};
5925
5926      $seen{$value}++;
5927
5928      $metadata{$metadata_item} = $value;
5929    }
5930  }
5931
5932  my @metadata_items;
5933
5934  if ( (grep length, values %metadata) == 2 and
5935       $metadata{series_and_episode}) {
5936    @metadata_items = ((grep { $_ ne 'series_and_episode' } keys %metadata), 'series_and_episode');
5937  }
5938  elsif (!$metadata{brandTitle}) {
5939    @metadata_items = qw(seriesTitle series_and_episode programmeTitle);
5940  }
5941  else {
5942    @metadata_items = qw(brandTitle series_and_episode seriesTitle programmeTitle);
5943  }
5944
5945  my $title = join "-", map { trim($_) }
5946                        grep length,
5947                        @metadata{@metadata_items};
5948
5949  $browser->get($player_info);
5950
5951  debug "Got player info URL $player_info";
5952
5953  if (!$browser->success) {
5954    die "Couldn't get player info: " . $browser->response->status_line;
5955  }
5956
5957  my @urls;
5958  for my $res(@res) {
5959    if($browser->content =~ /$res->{name}":\["([^"]+)/) {
5960      push @urls, { %$res, url => $1 };
5961    }
5962  }
5963
5964  die "No video URLs found" unless @urls;
5965
5966  my $rtmp = $prefs->quality->choose(@urls);
5967
5968  my($app, $playpath, $query) = $rtmp->{url} =~ m{^\w+://[^/]+/(\w+/\w+)(/[^?]+)(\?.*)};
5969  my $prefix = "mp4";
5970  $prefix = "flv" if $playpath =~ /\.flv$/;
5971
5972  if ($prefs->subtitles) {
5973    if ($browser->content =~ m{"subtitleLocation":\["([^"]+)"\]}) {
5974      my $subtitles_url = $1;
5975
5976      if ($subtitles_url =~ m{^/}) {
5977        $subtitles_url = "http://www.seesaw.com$subtitles_url";
5978      }
5979
5980      debug "Got Seesaw subtitles URL: $subtitles_url";
5981
5982      $browser->get($subtitles_url);
5983
5984      if ($browser->success) {
5985        my $srt_filename = title_to_filename($title, "srt");
5986
5987        convert_sami_subtitles_to_srt($browser->content, $srt_filename);
5988
5989        info "Wrote subtitles to $srt_filename";
5990      }
5991      else {
5992        info "Couldn't download subtitles: " . $browser->response->status_line;
5993      }
5994    }
5995    else {
5996      debug "No Seesaw subtitles available (or couldn't extract URL)";
5997    }
5998  }
5999
6000  return {
6001    flv      => title_to_filename($title, $prefix),
6002    rtmp     => $rtmp->{url},
6003    app      => $app,
6004    playpath => "$prefix:$playpath$query"
6005  }
6006}
6007
6008sub search {
6009  my($self, $search, $type) = @_;
6010
6011  my $series  = $search =~ s/(?:series |\bs)(\d+)//i ? int $1 : "";
6012  my $episode = $search =~ s/(?:episode |\be)(\d+)//i ? int $1 : "";
6013
6014  my $browser = FlashVideo::Mechanize->new;
6015
6016  _update_with_content($browser,
6017    "http://www.seesaw.com/start.layout.searchsuggest:inputtextevent?search="
6018    . uri_escape($search));
6019
6020  my @urls = map  {
6021    chomp(my $name = $_->text);
6022    { name => $name, url => $_->url_abs->as_string }
6023  } $browser->find_all_links(text_regex => qr/.+/);
6024
6025  my @words = split " ", $search;
6026  @urls = grep { my $a = $_; @words == grep { $a->{name} =~ /\Q$_\E/i } @words } @urls;
6027
6028  if(@urls == 1) {
6029    $browser->get($urls[0]->{url});
6030    my $main_title = ($browser->content =~ m{<h1>(.*?)</h1>}s)[0];
6031    $main_title =~ s/<[^>]+>//g;
6032    $main_title =~ s/\s+/ /g;
6033
6034    my $cur_series = ($browser->content =~ /<li class="current">.*?>\w+ (\d+)/i)[0];
6035    if($main_title =~ s/\s*series (\d+)\s*//i && !$cur_series) {
6036      $cur_series = $1;
6037    }
6038
6039    my %series = reverse(
6040      ($browser->content =~ m{<ul class="seriesList">(.*?)</ul>}i)[0]
6041      =~ /<li.*?href="\?([^"]+)".*?>\s*(?:series\s*)?([^<]+)/gi);
6042
6043    my $episode_list;
6044    if($series && $cur_series ne $series) {
6045      if(!$series{$series}) {
6046        error "No such series number ($series).";
6047        return;
6048      }
6049      _update_with_content($browser, $series{$series});
6050      $episode_list = $browser->content;
6051      $cur_series = $series;
6052
6053    } elsif(!$series && keys %series > 1) {
6054      my @series = sort { $a <=> $b } map { s/series\s+//i; $_ } keys %series;
6055      info "Viewing series $cur_series; series " . join(", ", @series) . " also available.";
6056      info "Search for 'seesaw $main_title series $series[0]' to view a specific series.";
6057    }
6058
6059    if(!$episode_list) {
6060      $episode_list = ($browser->content
6061        =~ m{<table id="episodeListTble">(.*?)</table>}is)[0];
6062    }
6063
6064    @urls = ();
6065    for my $episode_html($episode_list =~ m{<tr.*?</tr>}gis) {
6066      my %info;
6067      for(qw(number date title action)) {
6068        my $class = "episode" . ucfirst;
6069        $episode_html =~ m{<td class=['"]$class['"]>(.*?)</td>}gis
6070          && ($info{$_} = $1);
6071      }
6072
6073      $info{number}   = ($info{number} =~ /ep\.?\w*\s*(\d+)/i)[0];
6074      $info{date}     = ($info{date}   =~ />(\w+[^<]+)/)[0];
6075      $info{number} ||= ($info{title}  =~ /ep\.?\w*\s*(\d+)/i)[0];
6076      $info{title}    = ($info{title}  =~ />\s*([^<].*?)\s*</s)[0];
6077      $info{url}      = ($info{action} =~ /href=['"]([^'"]+)/)[0];
6078
6079      my $title = join " - ", $main_title,
6080        ($cur_series
6081          ? sprintf("S%02dE%02d", $cur_series, $info{number})
6082          : $info{number} ? sprintf("E%02d", $info{number})
6083        : ()), $info{title};
6084
6085      my $result = {
6086        name => $title,
6087        url  => URI->new_abs($info{url}, $browser->uri)
6088      };
6089
6090      if($episode && $info{number} == $episode) {
6091        return $result;
6092      }
6093
6094      push @urls, $result;
6095    }
6096  } else {
6097    info "Please specify a more specific title to download a particular programme." if @urls > 1;
6098  }
6099
6100  return @urls;
6101}
6102
6103sub _update_with_content {
6104  my($browser, $url) = @_;
6105
6106  $browser->get($url,
6107    X_Requested_With => 'XMLHttpRequest',
6108    X_Prototype_Version => '1.6.0.3');
6109
6110  my($content) = $browser->content =~ /content":\s*"(.*?)"\s*}/;
6111  $content = json_unescape($content);
6112  debug "Content is '$content'";
6113  $browser->update_html($content);
6114}
6115
6116sub trim {
6117  local $_ = shift;
6118
6119  s/^\s+|\s+$//g;
6120
6121  return $_;
6122}
6123
61241;
6125}
6126##} blib/lib/FlashVideo/Site/Seesaw.pm
6127BEGIN { $INC{'FlashVideo/Site/Sevenload.pm'}++; }
6128# Part of get-flash-videos. See get_flash_videos for copyright.
6129##{ blib/lib/FlashVideo/Site/Sevenload.pm
6130{
6131package FlashVideo::Site::Sevenload;
6132
6133use strict;
6134BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6135BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
6136use HTML::Entities;
6137use URI::Escape;
6138
6139sub find_video {
6140  my ($self, $browser) = @_;
6141
6142  die "Could not find configPath" unless $browser->content =~ /configPath=([^"']+)/;
6143  my $configpath = uri_unescape(decode_entities($1));
6144  $browser->get($configpath);
6145
6146  my $config = from_xml($browser);
6147
6148  my($title, $location);
6149
6150  eval {
6151    my $item = $config->{playlists}->{playlist}->{items}->{item};
6152    $title = title_to_filename($item->{title});
6153
6154    my $streams = $item->{videos}->{video}->{streams}->{stream};
6155    $streams = [ $streams ] unless ref $streams eq 'ARRAY';
6156
6157    $location = (sort { $b->{width} <=> $a->{width} } @$streams)[0]
6158      ->{locations}->{location}->{content};
6159  };
6160
6161  return $location, $title if $location;
6162
6163  die "Unable to get stream location" . ($@ ? ": $@" : "");
6164}
6165
61661;
6167}
6168##} blib/lib/FlashVideo/Site/Sevenload.pm
6169BEGIN { $INC{'FlashVideo/Site/Slashcontrol.pm'}++; }
6170# Part of get-flash-videos. See get_flash_videos for copyright.
6171##{ blib/lib/FlashVideo/Site/Slashcontrol.pm
6172{
6173package FlashVideo::Site::Slashcontrol;
6174
6175use strict;
6176BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6177BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
6178BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
6179BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
6180
6181sub find_video {
6182  my($self, $browser, $embed_url, $prefs) = @_;
6183
6184  my $config;
6185  my $mediaKey;
6186  if ($browser->content =~ /<param name="flashvars" value="config=([^&]*)&mediaKey=([^"]*)"\/>/) {
6187    $config = $1;
6188    $mediaKey = $2;
6189  } else {
6190    die "Couldn't find flashvars param in " . $browser->uri->as_string;
6191  }
6192  my $root;
6193  if ($browser->content =~ /<embed src="(.*)\/[^\/]*\.swf"/) {
6194    $root = $1;
6195  } else {
6196    die "Couldn't find embeded swf " . $browser->uri->as_string;
6197  }
6198  my $config_url;
6199  $config_url = $1 . "/" . $config;
6200
6201  $browser->allow_redirects;
6202  $browser->get($config_url);
6203  if (!$browser->success) {
6204    die "Couldn't download config.xml $config_url: " . $browser->response->status_line;
6205  }
6206
6207  my $xml = from_xml($browser);
6208  my $domain = $xml->{mfs}->{mfsUrl};
6209  my $version = $xml->{mfs}->{mfsVersion};
6210  my $account = $xml->{mfs}->{mfsAccount};
6211  my $partner = $xml->{mfs}->{mfsPartnerId};
6212
6213  my $asset_url = "$domain/$version/$account/assets/$mediaKey/partner/$partner?format=json";
6214  $browser->get($asset_url);
6215  if (!$browser->success) {
6216    die "Couldn't download asset file $asset_url: " . $browser->response->status_line;
6217  }
6218
6219  my $asset_data = from_json($browser->content);
6220  my $videos = $asset_data->{videos};
6221
6222  my $title = title_to_filename($asset_data->{assetFields}->{seriesName} . " - " . $asset_data->{assetFields}->{title});
6223
6224  my $video = $videos->{limelight700};
6225
6226  my $rtmp = $video->{uri};
6227
6228  return {
6229    flv => $title,
6230    rtmp => $rtmp,
6231  };
6232}
6233
62341;
6235}
6236##} blib/lib/FlashVideo/Site/Slashcontrol.pm
6237BEGIN { $INC{'FlashVideo/Site/Spiegel.pm'}++; }
6238# Part of get-flash-videos. See get_flash_videos for copyright.
6239##{ blib/lib/FlashVideo/Site/Spiegel.pm
6240{
6241package FlashVideo::Site::Spiegel;
6242
6243use strict;
6244BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6245BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6246
6247sub find_video {
6248  my ($self, $browser, $embed_url, $prefs) = @_;
6249  my ($video_id, $xmlurl, $filename, $videourl, $quality);
6250
6251  debug "Spiegel::find_video called, embed_url = \"$embed_url\"\n";
6252
6253  $quality = {
6254      high => '.mp4',
6255      medium => 'VP6_928.flv',
6256      low => 'VP6_576.flv'}->{$prefs->{quality}};
6257
6258  if($embed_url =~ /.*?www.spiegel.de\/video\/video-(\d*).html/) {
6259    $video_id = $1;
6260    $xmlurl = "http://video.spiegel.de/flash/$video_id.xml";
6261  } else {
6262    die "Only works for http://www.spiegel/de/video/video... urls\n";
6263  }
6264
6265  if($browser->content =~ /<title>(.*?) -Video/) {
6266    $filename = "Spiegel_$1_${video_id}_$quality";
6267    $filename = title_to_filename($filename, $quality);
6268    $filename =~ s/__/_/g;
6269  } else {
6270    die "Unable to find <title> on page $embed_url\n";
6271  }
6272
6273  $browser->get($xmlurl);
6274
6275  if($browser->content =~ /<filename>(.*?$quality)<\/filename>/) {
6276    $videourl = "http://video.spiegel.de/flash/$1";
6277  } else {
6278    die "could not find video url\n";
6279  }
6280
6281  return $videourl, $filename;
6282}
6283
62841;
6285}
6286##} blib/lib/FlashVideo/Site/Spiegel.pm
6287BEGIN { $INC{'FlashVideo/Site/Spike.pm'}++; }
6288# Part of get-flash-videos. See get_flash_videos for copyright.
6289##{ blib/lib/FlashVideo/Site/Spike.pm
6290{
6291package FlashVideo::Site::Spike;
6292
6293use strict;
6294BEGIN { FlashVideo::Site::Mtvnservices->import(); } # (added by utils/combine-perl.pl)
6295use base 'FlashVideo::Site::Mtvnservices';
6296
6297BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6298BEGIN { no strict 'refs'; *from_xml = \&FlashVideo::Utils::from_xml; }
6299use URI::Escape;
6300
6301sub find_video {
6302  my ($self, $browser, $embed_url) = @_;
6303
6304  my $page_url = $browser->uri->as_string;
6305
6306  my $config_url;
6307  if($browser->content =~ /config_url\s*=\s*["']([^"']+)/) {
6308    $config_url = $1;
6309  } elsif($browser->content =~ /(?:ifilmId|flvbaseclip)=(\d+)/) {
6310    $config_url = "/ui/xml/mediaplayer/config.groovy?ifilmId=$1";
6311  }
6312  die "No config_url/id found\n" unless $config_url;
6313
6314  $browser->get(uri_unescape($config_url));
6315  my $xml = from_xml($browser);
6316
6317  my $feed = uri_unescape($xml->{player}->{feed});
6318  die "Unable to find feed URL\n" unless $feed;
6319
6320  $browser->get($feed);
6321
6322  return $self->handle_feed($browser->content, $browser, $page_url);
6323}
6324
63251;
6326}
6327##} blib/lib/FlashVideo/Site/Spike.pm
6328BEGIN { $INC{'FlashVideo/Site/Stagevu.pm'}++; }
6329# Part of get-flash-videos. See get_flash_videos for copyright.
6330##{ blib/lib/FlashVideo/Site/Stagevu.pm
6331{
6332package FlashVideo::Site::Stagevu;
6333
6334use strict;
6335BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6336BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6337
6338sub find_video {
6339  my ($self, $browser) = @_;
6340
6341  my($title) = $browser->content =~ /<title>(.*?)<\/title>/;
6342  $title =~ s/\s*-\s*Stagevu.*?$//;
6343
6344  my($url) = FlashVideo::Generic->find_video($browser);
6345
6346  return $url, title_to_filename($title);
6347}
6348
63491;
6350}
6351##} blib/lib/FlashVideo/Site/Stagevu.pm
6352BEGIN { $INC{'FlashVideo/Site/Starwars.pm'}++; }
6353# Part of get-flash-videos. See get_flash_videos for copyright.
6354##{ blib/lib/FlashVideo/Site/Starwars.pm
6355{
6356package FlashVideo::Site::Starwars;
6357
6358use strict;
6359BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6360BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
6361
6362sub find_video {
6363  my ($self, $browser, $embed_url) = @_;
6364
6365  my $video_id;
6366  if ($browser->uri->as_string =~ /view\/([0-9]+)\.html$/) {
6367    $video_id = $1;
6368  }
6369
6370  my $page_url = $browser->uri->as_string;
6371
6372  $browser->get("http://starwars.com/webapps/video/item/$video_id");
6373  my $xml = from_xml($browser);
6374
6375  my $items = $xml->{channel}->{item};
6376  my $item = ref $items eq 'ARRAY' ?
6377    (grep { $_->{link}->{content} eq "/video/view/" . $video_id . ".html" } @$items)[0] :
6378    $items;
6379
6380  debug $item->{enclosure}->{url};
6381
6382  my $rtmpurl = $item->{enclosure}->{url};
6383  $rtmpurl =~ s/^rtmp:/rtmpe:/; # for some reason it only works with rtmpe
6384
6385  my $title = $item->{title}; # is there a way to unencrypt <CDATA> tags? or does the xml handler do this for us?
6386
6387  return {
6388    flv => $title,
6389    rtmp => title_to_filename($rtmpurl),
6390    playpath => $item->{content}->{url}
6391  };
6392}
6393
63941;
6395}
6396##} blib/lib/FlashVideo/Site/Starwars.pm
6397BEGIN { $INC{'FlashVideo/Site/Stickam.pm'}++; }
6398# Part of get-flash-videos. See get_flash_videos for copyright.
6399##{ blib/lib/FlashVideo/Site/Stickam.pm
6400{
6401package FlashVideo::Site::Stickam;
6402
6403use strict;
6404BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6405BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; }
6406
6407sub find_video {
6408  my($self, $browser, $embed_url, $prefs) = @_;
6409
6410  my $perfomer_id;
6411
6412  if ($browser->content =~ /profileUserId=(\d+)/) {
6413    $perfomer_id = $1;
6414  }
6415  else {
6416    die "Can't get performer ID";
6417  }
6418
6419  my $filename;
6420  if ($browser->content =~ /userName=([^&]+)/) {
6421    $filename = $1;
6422  }
6423  else {
6424    $filename = $perfomer_id;
6425  }
6426
6427  my $stream_info_url = sprintf
6428    "http://player.stickam.com/servlet/flash/getChannel?" .
6429    "type=join&performerID=%d", $perfomer_id;
6430
6431  $browser->get($stream_info_url);
6432
6433  if (!$browser->success) {
6434    die "Couldn't get stream info: " . $browser->response->status_line;
6435  }
6436
6437  my %stream_info;
6438
6439  foreach my $pair (split /&/, $browser->content) {
6440    my ($name, $value) = split /=/, $pair;
6441
6442    if ($name eq 'freeServerIP') {
6443      $value = (split /,/, $value)[0];
6444    }
6445
6446    $stream_info{$name} = $value;
6447  }
6448
6449  if ($stream_info{errorCode}) {
6450    die "Stickam returned error $stream_info{errorCode}: $stream_info{errorMessage}";
6451  }
6452
6453  my $rtmp_stream_url = sprintf
6454    "rtmp://%s/video_chat2_stickam_peep/%d/public/mainHostFeed",
6455    $stream_info{freeServerIP},
6456    $stream_info{channelID};
6457
6458  return {
6459    rtmp => $rtmp_stream_url,
6460    flv => title_to_filename($filename),
6461    live => '',
6462    conn => [
6463      'O:1',
6464      "NS:channel:$perfomer_id",
6465      'O:1',
6466    ],
6467    swfhash($browser,
6468      "http://player.stickam.com/flash/stickam/stickam_simple_video_player.swf")
6469  };
6470}
6471
64721;
6473}
6474##} blib/lib/FlashVideo/Site/Stickam.pm
6475BEGIN { $INC{'FlashVideo/Site/Stupidvideos.pm'}++; }
6476# Part of get-flash-videos. See get_flash_videos for copyright.
6477##{ blib/lib/FlashVideo/Site/Stupidvideos.pm
6478{
6479package FlashVideo::Site::Stupidvideos;
6480
6481use strict;
6482BEGIN { FlashVideo::Site::Grindtv->import(); } # (added by utils/combine-perl.pl)
6483use base 'FlashVideo::Site::Grindtv';
6484
64851;
6486}
6487##} blib/lib/FlashVideo/Site/Stupidvideos.pm
6488BEGIN { $INC{'FlashVideo/Site/Svtplay.pm'}++; }
6489# Part of get-flash-videos. See get_flash_videos for copyright.
6490##{ blib/lib/FlashVideo/Site/Svtplay.pm
6491{
6492package FlashVideo::Site::Svtplay;
6493
6494use strict;
6495use warnings;
6496
6497BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6498BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6499BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
6500BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
6501
6502sub find_video {
6503  my ($self, $browser, $embed_url, $prefs) = @_;
6504  my @rtmpdump_commands;
6505
6506  if ($browser->uri->as_string !~ m/video\/([0-9]*)/) {
6507    die "No video id found in url";
6508  }
6509
6510  my $video_id = $1;
6511  my $info_url = "http://www.svtplay.se/video/$video_id?output=json";
6512
6513  $browser->get($info_url);
6514
6515  if (!$browser->success) {
6516    die "Couldn't download $info_url: " . $browser->response->status_line;
6517  }
6518
6519  my $video_data = from_json($browser->content);
6520  my $name = $video_data->{context}->{title};
6521  my $bitrate = 0;
6522  my $rtmp_url;
6523
6524  foreach my $video (@{ $video_data->{video}->{videoReferences} }) {
6525    my $rate = int $video->{bitrate};
6526
6527    if ($bitrate < $rate && $video->{playerType} eq "flash") {
6528      $rtmp_url = $video->{url};
6529      $bitrate = $rate;
6530    }
6531  }
6532
6533  if ($prefs->{subtitles}) {
6534    if (my $subtitles_url = $video_data->{video}->{subtitleReferences}[0]->{url}) {
6535      info "Found subtitles URL: $subtitles_url";
6536
6537      $browser->get($subtitles_url);
6538
6539      if (!$browser->success) {
6540        info "Couldn't download subtitles: " . $browser->status_line;
6541      }
6542
6543      my $srt_filename = title_to_filename($name, "srt");
6544
6545      open my $srt_fh, '>', $srt_filename
6546        or die "Can't open subtitles file $srt_filename: $!";
6547      binmode $srt_fh, ':utf8';
6548      print $srt_fh $browser->content;
6549      close $srt_fh;
6550    }
6551    else {
6552      info "No subtitles found!";
6553    }
6554  }
6555
6556  return {
6557	  flv    => title_to_filename($name, "flv"),
6558	  rtmp   => $rtmp_url,
6559	  swfVfy => "http://www.svtplay.se/public/swf/video/svtplayer-2012.15.swf",
6560  };
6561}
6562
65631;
6564}
6565##} blib/lib/FlashVideo/Site/Svtplay.pm
6566BEGIN { $INC{'FlashVideo/Site/Tbs.pm'}++; }
6567# Part of get-flash-videos. See get_flash_videos for copyright.
6568##{ blib/lib/FlashVideo/Site/Tbs.pm
6569{
6570package FlashVideo::Site::Tbs;
6571
6572use strict;
6573BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6574BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
6575
6576sub find_video {
6577  my ($self, $browser, $embed_url) = @_;
6578
6579  my $oid;
6580  if ($browser->uri->as_string =~ /oid=([0-9]*)/) {
6581    $oid = $1;
6582  }
6583
6584  $browser->get("http://www.tbs.com/video/cvp/videoData.jsp?oid=$oid");
6585
6586  my $xml = from_xml($browser);
6587
6588  my $headline = $xml->{headline};
6589
6590  my $akamai;
6591  if ($xml->{akamai}->{src} =~ /[^,]*,([^,]*)/){
6592    $akamai = $1;
6593  }
6594
6595  my $files = $xml->{files}->{file};
6596  my $file = ref $files eq 'ARRAY' ?
6597    (grep { $_->{type} eq "standard" } @$files)[0] :
6598    $files;
6599
6600  if($akamai) {
6601    my $rtmpurl = $akamai . $file->{content};
6602    die "Unable to find RTMP URL\n" unless $rtmpurl;
6603
6604    return {
6605      flv => title_to_filename($headline),
6606      rtmp => $rtmpurl
6607    };
6608  } else {
6609    return $file->{content}, title_to_filename($headline);
6610  }
6611}
6612
66131;
6614}
6615##} blib/lib/FlashVideo/Site/Tbs.pm
6616BEGIN { $INC{'FlashVideo/Site/Techcast.pm'}++; }
6617# Part of get-flash-videos. See get_flash_videos for copyright.
6618##{ blib/lib/FlashVideo/Site/Techcast.pm
6619{
6620package FlashVideo::Site::Techcast;
6621
6622use strict;
6623BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6624BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6625use HTML::Entities;
6626
6627sub find_video {
6628  my ($self, $browser, $embed_url) = @_;
6629
6630  my($clip_url) = $browser->content =~ /clip:\s*{\s*url:\s*['"]([^"']+)/;
6631  die "Unable to extract clip URL" unless $clip_url;
6632  $clip_url = URI->new_abs($clip_url, $browser->uri);
6633
6634  my($talk) = $browser->content =~ /class="lecture_archive"[^>]+>([^<]+)/i;
6635  $talk = decode_entities($talk);
6636
6637  my($author) = $browser->content =~ /class="speaker_archive"[^>]+>([^<]+)/i;
6638  $author = decode_entities($author);
6639
6640  return $clip_url, title_to_filename($talk ? "$author - $talk" : $clip_url);
6641}
6642
66431;
6644}
6645##} blib/lib/FlashVideo/Site/Techcast.pm
6646BEGIN { $INC{'FlashVideo/Site/Ted.pm'}++; }
6647# Part of get-flash-videos. See get_flash_videos for copyright.
6648##{ blib/lib/FlashVideo/Site/Ted.pm
6649{
6650package FlashVideo::Site::Ted;
6651use strict;
6652BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6653BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; }
6654BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
6655BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
6656
6657sub find_video {
6658  my ($self, $browser, $embed_url, $prefs) = @_;
6659
6660  my $basefilename;
6661  if ($browser->content =~ m{<noscript.*download.ted.com/talks/([^.]+)\.mp4.*noscript>}s) {
6662    $basefilename = $1;
6663  } else {
6664    die "Unable to find download link";
6665  }
6666
6667  if ($prefs->subtitles) {
6668    my $lang = "";
6669    if ($browser->content =~ m{talkID = (\d+);}s) {
6670      my $talkID = $1;
6671      my $intro_time = 15000;
6672      if ($browser->content =~ m{introDuration:(\d+)}s) {
6673        $intro_time = int($1);
6674      } else {
6675        error "Can't find the intro duration, so guessing at 15 seconds.";
6676      }
6677      $ENV{LANG} =~ /^([^_]*)/;
6678      $lang = $1;
6679      if (!$lang) {
6680        info "Unable to determine your language, using English";
6681        $lang = "en";
6682      }
6683      info "Downloading subtitles";
6684      get_subtitles($browser, $basefilename . ".srt", $intro_time,
6685                    "http://www.ted.com/talks/subtitles/id/$talkID/lang/$lang/format/json");
6686    } else {
6687      error "Unable to determine the talk ID, so can't get the subtitles";
6688    }
6689  }
6690
6691  my $quality = $prefs->{quality};
6692  if ($quality eq "low") {
6693    $quality = "-light";
6694  } elsif ($quality eq "medium") {
6695    $quality = "";
6696  } elsif ($quality eq "high") {
6697    $quality = "-480p";
6698  } else {
6699    die "Unknown quality setting";
6700  }
6701
6702  my $url = "http://download.ted.com/talks/" . $basefilename . $quality . ".mp4";
6703
6704  $browser->allow_redirects;
6705  return $url, $basefilename . ".mp4";
6706}
6707
6708sub get_subtitles {
6709  my ($browser, $filename, $intro_time, $url) = @_;
6710  $browser->get($url);
6711  if (!$browser->success) {
6712    error "Couldn't download subtitles: " . $browser->response->status_line;
6713    return;
6714  }
6715  json_to_srt($browser->content, $filename, $intro_time);
6716}
6717
6718
6719sub json_to_srt {
6720  my ($subdata, $filename, $intro_time) = @_;
6721  open (SRT, '>', $filename) or die "Can't open subtitles file $filename: $!";
6722
6723  my $subtitle_count = 0;
6724  my $subdata = from_json($subdata);
6725
6726  foreach my $subtitle (@{ $subdata->{captions} }) {
6727    $subtitle_count++; # SubRip starts at 1
6728
6729    my ($srt_start, $srt_end) = convert_to_srt_time(
6730      $subtitle->{startTime} + $intro_time,
6731      $subtitle->{duration},
6732    );
6733
6734    print SRT "$subtitle_count\n" .
6735          "$srt_start --> $srt_end\n" .
6736          "$subtitle->{content}\n\n";
6737  }
6738
6739  close SRT;
6740}
6741
6742sub convert_to_srt_time {
6743  my ($start, $duration) = @_;
6744
6745  return format_srt_time($start),
6746         format_srt_time($start + $duration);
6747}
6748
6749sub format_srt_time {
6750  my $time = shift;
6751
6752  my $seconds = int($time / 1000);
6753  my $milliseconds = $time - ($seconds * 1_000);
6754
6755  return sprintf "%02d:%02d:%02d,%03d", (gmtime $seconds)[2, 1, 0],
6756                                        $milliseconds;
6757}
6758
67591;
6760}
6761##} blib/lib/FlashVideo/Site/Ted.pm
6762BEGIN { $INC{'FlashVideo/Site/Theonion.pm'}++; }
6763# Part of get-flash-videos. See get_flash_videos for copyright.
6764##{ blib/lib/FlashVideo/Site/Theonion.pm
6765{
6766package FlashVideo::Site::Theonion; # horrible casing :(
6767
6768use strict;
6769BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6770BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6771
6772sub find_video {
6773  my ($self, $browser) = @_;
6774
6775  if ($browser->response->is_redirect) {
6776    $browser->get( $browser->response->header('Location') );
6777
6778    if (!$browser->success) {
6779      die "Couldn't follow Onion redirect: " .
6780        $browser->response->status_line;
6781    }
6782  }
6783
6784  my $title;
6785  if ($browser->content =~ /var video_title = "([^"]+)"/) {
6786    $title = $1;
6787  }
6788  else {
6789    $title = extract_info($browser)->{meta_title};
6790  }
6791
6792  my $filename = title_to_filename($title);
6793
6794  my $url = (FlashVideo::Generic->find_video($browser, $browser->uri))[0];
6795
6796  return $url, $filename;
6797}
6798
67991;
6800}
6801##} blib/lib/FlashVideo/Site/Theonion.pm
6802BEGIN { $INC{'FlashVideo/Site/Thirteen.pm'}++; }
6803# Part of get-flash-videos. See get_flash_videos for copyright.
6804##{ blib/lib/FlashVideo/Site/Thirteen.pm
6805{
6806package FlashVideo::Site::Thirteen;
6807use strict;
6808BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6809BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
6810BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
6811BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
6812
6813sub find_video {
6814  my ($self, $browser, $embed_url, $prefs) = @_;
6815
6816  my $iframe;
6817  if ($browser->content =~ /<iframe src="([^"]*)" /) {
6818    $iframe = $1;
6819  } else {
6820    die "Couln't find iframe in " . $browser->uri->as_string;
6821  }
6822
6823  my $url = 'http://www.thirteen.org' . $iframe;
6824  $browser->get($url);
6825  if (!$browser->success) {
6826    die "Couldn't download iframe $url: " . $browser->response->status_line;
6827  }
6828
6829
6830
6831  my $pid;
6832  if ($browser->content =~ /var pid = "([^"]*)";/) {
6833    $pid = $1;
6834  } elsif ($browser->uri->as_string =~ /&pid=([^&]*)&/) {
6835    $pid = $1;
6836  } else {
6837    die "Could not find pid for $url";
6838  }
6839
6840  my $release_url;
6841  if ($browser->content =~ /so.addVariable\("releaseURL", "([^"]*)"+pid+"([^"]*)"\);/) {
6842    $release_url = $1 . $pid . $2;
6843  } else {
6844    $release_url = "http://release.theplatform.com/content.select?pid=" . $pid . "&amp;format=SMIL&amp;Tracking=true";
6845  }
6846
6847  $browser->get($release_url);
6848  my $rtmp_url;
6849  if ($browser->response->is_redirect) {
6850    $rtmp_url = $browser->response->header("Location");
6851  } else {
6852    die "No redirect found for $release_url";
6853  }
6854
6855  $rtmp_url =~ s/<break>//;
6856
6857  my $filename;
6858  if ($rtmp_url =~ /mp4:(.*)\.mp4$/) {
6859    $filename = title_to_filename($1);
6860  } else {
6861    $filename = title_to_filename("");
6862  }
6863
6864
6865  return {
6866    rtmp => $rtmp_url,
6867    flv => $filename,
6868  };
6869}
6870
68711;
6872}
6873##} blib/lib/FlashVideo/Site/Thirteen.pm
6874BEGIN { $INC{'FlashVideo/Site/Todaysbigthing.pm'}++; }
6875# Part of get-flash-videos. See get_flash_videos for copyright.
6876##{ blib/lib/FlashVideo/Site/Todaysbigthing.pm
6877{
6878package FlashVideo::Site::Todaysbigthing;
6879
6880use strict;
6881BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6882BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
6883
6884my $base = "http://www.todaysbigthing.com/betamax";
6885
6886sub find_video {
6887  my ($self, $browser, $embed_url) = @_;
6888
6889  my $id;
6890  if($browser->content =~ /item_id=(\d+)/) {
6891    $id = $1;
6892  } elsif($embed_url =~ m![/:](\d+)!) {
6893    $id = $1;
6894  }
6895  die "No ID found\n" unless $id;
6896
6897  $browser->get("$base:$id");
6898
6899  my $xml = from_xml($browser);
6900
6901  my $title = $xml->{title};
6902  $title = extract_title($browser) if ref $title;
6903  my $filename = title_to_filename($title);
6904
6905  my $url = $xml->{flv};
6906  die "No FLV location" unless $url;
6907
6908  return $url, $filename;
6909}
6910
6911sub can_handle {
6912  my($self, $browser, $url) = @_;
6913
6914  return $browser->content =~ $base;
6915}
6916
69171;
6918}
6919##} blib/lib/FlashVideo/Site/Todaysbigthing.pm
6920BEGIN { $INC{'FlashVideo/Site/Tou.pm'}++; }
6921# Part of get-flash-videos. See get_flash_videos for copyright.
6922#################################################
6923#
6924# This file was automatically generated by utils/combine-perl.pl
6925# You should edit the original files, not this
6926# combined version.
6927#
6928# The original files are available at:
6929# http://github.com/monsieurvideo/get-flash-videos
6930#
6931#################################################
6932# tou.tv
6933#
6934#	Reverse-engineering details at http://store-it.appspot.com/tou/tou.html
6935#	by Sylvain Fourmanoit
6936#
6937#	un grand merci a Sylvain qui a tout debrousaille!
6938#
6939#	Stavr0
6940#
6941##{ blib/lib/FlashVideo/Site/Tou.pm
6942{
6943package FlashVideo::Site::Tou;
6944
6945use strict;
6946BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
6947BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
6948use URI::Escape;
6949
6950sub find_video {
6951  my ($self, $browser) = @_;
6952
6953  my $video_id;
6954  if ($browser->content =~ /,"pid":"(\w+)"/i) {
6955    $video_id = $1;
6956  }
6957  debug "Video ID = " . $video_id;
6958
6959  die "Couldn't find TOU.TV video ID" unless $video_id;
6960
6961  my $filename;
6962  if ($browser->content =~ /,"titleId":"([^"]+)"/i) {
6963    $filename =  $1 ;
6964  }
6965  debug "Filename = " . $filename;
6966
6967  $browser->get("http://release.theplatform.com/content.select?pid=$video_id");
6968
6969  die "Couldn't download TOU.TV XML: " . $browser->response->status_line
6970    if !$browser->success;
6971
6972  my $url;
6973  if ($browser->content =~ /(rtmp:[^\<]+)/i) {
6974    $url = uri_unescape($1);
6975  }
6976  debug "URL = " . $url;
6977
6978  my $auth;
6979  if ($url =~ /auth=([^&]+)/i) {
6980    $auth = uri_unescape($1);
6981  }
6982  debug "AUTH = " . $auth;
6983
6984  my $app;
6985  if ($url =~ /(ondemand\/.+)/i) {
6986    $app = uri_unescape($1);
6987  }
6988  debug "APP = " . $app;
6989
6990  my $playpath;
6991  if ($url =~ /&lt;break&gt;(.+)/i) {
6992    $playpath = uri_unescape($1);
6993  }
6994  debug "PLAYPATH = " . $playpath;
6995
6996
6997  return {
6998      app => $app,
6999      pageUrl => $url,
7000      swfUrl => "http://static.tou.tv/lib/ThePlatform/4.1.2/swf/flvPlayer.swf",
7001      tcUrl => $url,
7002      auth => $auth,
7003      rtmp => $url,
7004      playpath => $playpath,
7005      flv => "$filename.flv",
7006  };
7007}
7008
7009sub search {
7010  my($self, $search, $type) = @_;
7011
7012  my $browser = FlashVideo::Mechanize->new;
7013  $browser->get("http://www.tou.tv/recherche?q=" . uri_escape($search));
7014  return unless $browser->success;
7015
7016  my $results = $browser->content;
7017
7018  my @emissions;
7019  my @links;
7020
7021  while($results =~ /<a\s+href="([^"]+)"\s+id="[^"]+"\s+class="([^"]+)/g) {
7022    debug $1;
7023    if($2 eq "tousEpisodes") {
7024      push @emissions, $1;
7025    }
7026  }
7027
7028  for my $emission (@emissions) {
7029    $browser->get($emission);
7030    my $liste = $browser->content;
7031
7032    while($liste =~ /<a.+class="episode".+href="([^"]+)".+>(.+)<\/a>/g) {
7033      push @links, { name => $1, url => "http://www.tou.tv$1", description => $2 };
7034    }
7035  }
7036
7037  return @links;
7038}
7039
70401;
7041}
7042##} blib/lib/FlashVideo/Site/Tou.pm
7043BEGIN { $INC{'FlashVideo/Site/Traileraddict.pm'}++; }
7044# Part of get-flash-videos. See get_flash_videos for copyright.
7045##{ blib/lib/FlashVideo/Site/Traileraddict.pm
7046{
7047package FlashVideo::Site::Traileraddict;
7048
7049use strict;
7050BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7051BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7052use URI::Escape;
7053
7054sub find_video {
7055  my ($self, $browser) = @_;
7056
7057  my $video_id;
7058  if ($browser->content =~ m'/em[db]/(\d+)') {
7059    $video_id = $1;
7060  }
7061  else {
7062    die "Unable to get Traileraddict video ID";
7063  }
7064
7065  my $video_info_url = "http://www.traileraddict.com/fvar.php?tid=$video_id";
7066
7067  $browser->get($video_info_url);
7068
7069  if (!$browser->success) {
7070    die "Couldn't download Traileraddict video info URL: " .
7071        $browser->response->status_line;
7072  }
7073
7074  my %info = parse_video_info($browser->content);
7075
7076  die "Couldn't find Traileraddict video URL" unless $info{fileurl};
7077
7078  $browser->head($info{fileurl});
7079  if ($browser->response->is_redirect()) {
7080    $info{fileurl} = $browser->response->header('Location');
7081  }
7082
7083  my $type = $info{fileurl} =~ /\.mp4/i ? 'mp4' : 'flv';
7084
7085  return $info{fileurl}, title_to_filename($info{title}, $type);
7086}
7087
7088sub parse_video_info {
7089  my $raw_video_info = shift;
7090
7091  my %info;
7092
7093  foreach my $pair (split /&/, $raw_video_info) {
7094    $pair = uri_unescape($pair);
7095
7096    my ($name, $value) = split /=/, $pair;
7097
7098    $info{$name} = $value;
7099  }
7100
7101  return %info;
7102}
7103
71041;
7105}
7106##} blib/lib/FlashVideo/Site/Traileraddict.pm
7107BEGIN { $INC{'FlashVideo/Site/Truveo.pm'}++; }
7108# Part of get-flash-videos. See get_flash_videos for copyright.
7109##{ blib/lib/FlashVideo/Site/Truveo.pm
7110{
7111package FlashVideo::Site::Truveo;
7112
7113use strict;
7114BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7115BEGIN { no strict 'refs'; *url_exists = \&FlashVideo::Utils::url_exists; }
7116
7117sub find_video {
7118  my($self, $browser, $embed_url, $prefs) = @_;
7119
7120  my($videourl) = $browser->content =~ /var videourl = "(.*?)"/;
7121
7122  $videourl = $embed_url
7123    if !$videourl && $browser->uri->host eq 'xml.truveo.com';
7124
7125  die "videourl not found" unless $videourl;
7126
7127  $browser->get($videourl);
7128
7129  if($browser->content =~ /url=(http:.*?)["']/) {
7130    my $redirect = url_exists($browser, $1);
7131
7132    $browser->get($redirect);
7133
7134    my($package, $possible_url) = FlashVideo::URLFinder->find_package($redirect, $browser);
7135
7136    die "Recursion detected" if $package eq __PACKAGE__;
7137
7138    return $package->find_video($browser, $possible_url, $prefs);
7139  } else {
7140    die "Redirect URL not found";
7141  }
7142}
7143
71441;
7145}
7146##} blib/lib/FlashVideo/Site/Truveo.pm
7147BEGIN { $INC{'FlashVideo/Site/Tudou.pm'}++; }
7148##{ blib/lib/FlashVideo/Site/Tudou.pm
7149{
7150package FlashVideo::Site::Tudou;
7151
7152use strict;
7153BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7154BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
7155
7156sub find_video {
7157  my ($self, $browser, $embed_url) = @_;
7158
7159  my $check_response = sub {
7160    my ( $message ) = @_;
7161    return if $browser->success;
7162    die sprintf $message, $browser->response->code;
7163  };
7164
7165
7166  my $videoID = 0;
7167
7168  if ( $embed_url =~ m`hd.tudou.com/program/\w+` )
7169  {
7170    ( $videoID ) = ( $browser->content =~ /iid: "(\w+)"/ );
7171  }
7172
7173  else
7174  {
7175    if ( $embed_url =~ m`tudou.com/programs/view/(.+)$` )
7176    {
7177      $embed_url = sprintf "http://www.tudou.com/v/%s", $1;
7178      $browser->get( $embed_url );
7179    }
7180
7181    if ( $browser->response->code eq 302 and $embed_url =~ m`tudou.com/v/(.+)$` )
7182    {
7183      $embed_url = $browser->response->header( 'Location' );
7184    }
7185
7186    ( $videoID ) = ( $embed_url =~ m`\.swf\?iid=(\d+)` );
7187  }
7188
7189  die "Couldn't extract video ID, we are out probably out of date" unless $videoID;
7190  debug "Using video ID $videoID";
7191
7192  $browser->get(
7193    sprintf "http://v2.tudou.com/v2/kili?safekey=%s&id=%s&noCatch=%d",
7194    'YouNeverKnowThat', $videoID, rand( 10000 ) );
7195
7196  if ( not $browser->success )
7197  {
7198    debug 'Using fallback tudou link for video info';
7199    $browser->get(
7200      sprintf "http://v2.tudou.com/v2/cdn?safekey=%s&id=%s&noCatch=%d",
7201      'YouNeverKnowThat', $videoID, rand( 10000 ) );
7202  }
7203  $check_response->( "Couldn't grab video informaton from tudou, server response was %s" );
7204
7205  return parse_video_info( $browser->content );
7206}
7207
7208sub parse_video_info {
7209  my ( $raw_xml ) = @_;
7210
7211
7212  my $xml = from_xml($raw_xml, forcearray => [ 'f' ] );
7213
7214  my %streams;
7215  foreach my $file ( @{$xml->{b}->{f}} )
7216  {
7217    my $url = $file->{content};
7218
7219    my ( $format ) = ( $url =~ m`http://[^/]+/([^/]+)/` );
7220    debug "Unable to extract file format for $url" and next
7221      unless $format;
7222
7223    push @{$streams{$format}{urls}}, $url;
7224    $streams{$format}{size} = $file->{size};
7225  }
7226
7227  my $stream
7228    = ( exists $streams{mp4} ? 'mp4'
7229      : exists $streams{m4v} ? 'm4v'
7230      : exists $streams{flv} ? 'flv'
7231      : exists $streams{wwwFlv} ? 'wwwFlv'
7232      : exists $streams{f4v} ? 'f4v'
7233      : exists $streams{phoneMp4} ? 'phoneMp4'
7234      : '' );
7235
7236  my $stream_formats = join ', ', ( keys %streams );
7237  die "Video is only available in unknown file formats ($stream_formats)",
7238    unless $stream;
7239
7240  debug "Choosing to use the $stream stream (available: $stream_formats)";
7241  my $stream_choice = int rand( 1 + $#{$streams{$stream}{urls}} );
7242  my $url = @{$streams{$stream}{urls}}[$stream_choice];
7243
7244  my $sourceID = ( $stream eq 'flv' ? '11000' : '18000' );
7245  $url =~ s/\?key=/?$sourceID&key=/;
7246
7247  my $title = $xml->{title};
7248  my $filename = title_to_filename( $title, 'flv' );
7249
7250  my $stream_duration = $xml->{time};
7251  my $stream_size = $streams{$stream}{size};
7252  debug sprintf
7253    "%s, %d seconds, %s bytes",
7254    $title, $stream_duration / 1000, $stream_size
7255      if ( $title and $stream_duration and $stream_size );
7256
7257  return ( $url, $filename );
7258}
7259
72601;
7261}
7262##} blib/lib/FlashVideo/Site/Tudou.pm
7263BEGIN { $INC{'FlashVideo/Site/Tv.pm'}++; }
7264# Part of get-flash-videos. See get_flash_videos for copyright.
7265##{ blib/lib/FlashVideo/Site/Tv.pm
7266{
7267package FlashVideo::Site::Tv;
7268
7269use strict;
7270BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7271BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
7272BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
7273BEGIN { no strict 'refs'; }
7274
7275sub find_video {
7276  my($self, $browser, $embed_url, $prefs) = @_;
7277
7278
7279  my $pid;
7280  if ($browser->content =~ /so.addVariable\("pid", "([^"]*)"\);/) {
7281    $pid = $1;
7282  } else {
7283    die "Could not find PID for video! " . $browser->uri->as_string;
7284  }
7285
7286  my $url = "http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&pid=$pid";
7287  $browser->get($url);
7288  if (!$browser->success) {
7289    die "Couldn't download content.select $url: " . $browser->response->status_line;
7290  }
7291
7292  my $xml = from_xml($browser);
7293  my $items = $xml->{body}->{ref};
7294  my $item = ref $items eq 'ARRAY' ?
7295    (grep { $_->{src} =~ /^rtmp:\/\// } @$items)[0] :
7296    $items;
7297
7298  my $filename = title_to_filename($item->{title});
7299
7300  my $playpath = "";
7301  my $rtmpurl = $item->{src};
7302
7303  $rtmpurl =~ s/<break>.*//;
7304
7305  return {
7306    flv => $filename,
7307    rtmp => $rtmpurl,
7308  };
7309}
7310
7311sub can_handle {
7312  my($self, $browser, $url) = @_;
7313  return $browser->uri->host =~ /(^|\.)tv\.com$/;
7314}
7315
73161;
7317}
7318##} blib/lib/FlashVideo/Site/Tv.pm
7319BEGIN { $INC{'FlashVideo/Site/Tv3play.pm'}++; }
7320# Part of get-flash-videos. See get_flash_videos for copyright.
7321##{ blib/lib/FlashVideo/Site/Tv3play.pm
7322{
7323package FlashVideo::Site::Tv3play;
7324use strict;
7325BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7326BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; }
7327
7328
7329sub find_video {
7330  my ($self, $browser, $embed_url, $prefs) = @_;
7331  return $self->find_video_viasat($browser,$embed_url,$prefs);
7332}
7333
7334sub find_video_viasat {
7335  my ($self, $browser, $embed_url, $prefs) = @_;
7336  my $video_id = ($browser->content =~ /id:([0-9]*),/)[0];
7337  info "Got video_id: $video_id";
7338  my $info_url = "http://viastream.viasat.tv/PlayProduct/$video_id";
7339  $browser->get($info_url);
7340  my $variable = $browser->content;
7341  $variable =~ s/\n//g;
7342  my $title = ($variable =~ /<Title><!\[CDATA\[(.*?)\]\]><\/Title>/)[0];
7343  my $flv_filename = title_to_filename($title, "flv");
7344
7345
7346
7347  my @urls;
7348  my $count = 0;
7349  my $base = ($variable =~ /<Videos>(.*)<\/Videos>/)[0];
7350  for ($count = 0; $count < 3; $count++){
7351    my $video = ($base =~ /<Video>(.+)<\/Video>/p)[0];
7352    if ($video eq ''){last;};
7353    $base = ${^POSTMATCH};
7354    my $bitrate = ($video =~ /<BitRate>([0-9]*)<\/BitRate>/)[0];
7355    my $url = ($video =~ /<Url><!\[CDATA\[(.*)]]><\/Url>/)[0];
7356    if (not (($url =~ /http:\/\//)[0] eq '')){
7357      $browser->get($url);
7358      $variable = $browser->content;
7359      $variable =~ s/\n//g;
7360      $url = ($variable =~ /<Url>(.*)<\/Url>/)[0];
7361    }
7362
7363    $urls[$count++] = { 'bitrate' => $bitrate,
7364		      'rtmp' => $url
7365		    };
7366  }
7367  my $bitrate = 0;
7368  my $rtmp;
7369  my $new_bitrate;
7370
7371  foreach (@urls) {
7372    $new_bitrate = int($_->{bitrate});
7373    if($new_bitrate > $bitrate){
7374        $bitrate = int($_->{bitrate});
7375        $rtmp = $_->{rtmp};
7376    }
7377  };
7378
7379
7380  return{
7381      rtmp => $rtmp,
7382      swfVfy => "http://flvplayer-viastream-viasat-tv.origin.vss.viasat.tv/play/swf/player110420.swf",
7383      flv => $flv_filename
7384  };
7385
7386
7387}
7388
73891;
7390}
7391##} blib/lib/FlashVideo/Site/Tv3play.pm
7392BEGIN { $INC{'FlashVideo/Site/Tv4play.pm'}++; }
7393# Part of get-flash-videos. See get_flash_videos for copyright.
7394##{ blib/lib/FlashVideo/Site/Tv4play.pm
7395{
7396package FlashVideo::Site::Tv4play;
7397use strict;
7398BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7399BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; *from_xml = \&FlashVideo::Utils::from_xml; }
7400
7401sub find_video {
7402  my ($self, $browser, $embed_url, $prefs) = @_;
7403  my $vid = ($embed_url =~ /videoid=([0-9]*)/)[0];
7404  my $smi_url = "http://premium.tv4play.se/api/web/asset/$vid/play";
7405
7406  my $title = ($browser->content =~ /property="og:title" content="(.*?)"/)[0];
7407  my $flv_filename = title_to_filename($title, "flv");
7408
7409  $browser->get($smi_url);
7410  my $content = from_xml($browser);
7411  my $i = 0;
7412  my @dump;
7413  my $subtitle_url;
7414  for ($i = 0; $i < 5; $i++){
7415    my $format = $content->{items}->{item}[$i]->{mediaFormat};
7416    my $bitrate = $content->{items}->{item}[$i]->{bitrate};
7417    my $rtmp = $content->{items}->{item}[$i]->{base};
7418    my $mp4 = $content->{items}->{item}[$i]->{url};
7419    @dump[$i] = { 'rtmp' => $rtmp,
7420		  'bitrate' => $bitrate,
7421		  'mp4' => $mp4,
7422		  'format' => $format
7423		};
7424  }
7425  foreach (@dump) {
7426    if($_->{format} eq 'smi'){ $subtitle_url = $_->{mp4};}
7427  }
7428  debug "Subtitle_url: $subtitle_url";
7429
7430
7431
7432  return {
7433      rtmp => $dump[0]->{rtmp},
7434      swfVfy => "http://www.tv4play.se/flash/tv4playflashlets.swf",
7435      playpath =>  $dump[0]->{mp4},
7436      flv => $flv_filename
7437  };
7438
7439}
7440
74411;
7442}
7443##} blib/lib/FlashVideo/Site/Tv4play.pm
7444BEGIN { $INC{'FlashVideo/Site/Tv6play.pm'}++; }
7445# Part of get-flash-videos. See get_flash_videos for copyright.
7446##{ blib/lib/FlashVideo/Site/Tv6play.pm
7447{
7448package FlashVideo::Site::Tv6play;
7449use strict;
7450BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7451BEGIN { no strict 'refs'; }
7452BEGIN { FlashVideo::Site::Tv3play->import(); } # (added by utils/combine-perl.pl)
7453use base 'FlashVideo::Site::Tv3play';
7454
7455
7456sub find_video {
7457  my ($self, $browser, $embed_url, $prefs) = @_;
7458  return $self->find_video_viasat($browser,$embed_url,$prefs);
7459}
74601;
7461}
7462##} blib/lib/FlashVideo/Site/Tv6play.pm
7463BEGIN { $INC{'FlashVideo/Site/Tv8play.pm'}++; }
7464# Part of get-flash-videos. See get_flash_videos for copyright.
7465##{ blib/lib/FlashVideo/Site/Tv8play.pm
7466{
7467package FlashVideo::Site::Tv8play;
7468use strict;
7469BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7470BEGIN { no strict 'refs'; }
7471BEGIN { FlashVideo::Site::Tv3play->import(); } # (added by utils/combine-perl.pl)
7472use base 'FlashVideo::Site::Tv3play';
7473
7474
7475sub find_video {
7476  my ($self, $browser, $embed_url, $prefs) = @_;
7477  return $self->find_video_viasat($browser,$embed_url,$prefs);
7478}
74791;
7480}
7481##} blib/lib/FlashVideo/Site/Tv8play.pm
7482BEGIN { $INC{'FlashVideo/Site/Tva.pm'}++; }
7483# Part of get-flash-videos. See get_flash_videos for copyright.
7484##{ blib/lib/FlashVideo/Site/Tva.pm
7485{
7486package FlashVideo::Site::Tva;
7487
7488use strict;
7489BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7490BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
7491BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
7492use base 'FlashVideo::Site::Brightcove';
7493
7494sub find_video {
7495  my ($self, $browser, $embed_url) = @_;
7496
7497  my $video_id  = ($browser->content =~ /player.SetVideo.(\d+)/i)[0];
7498  my $player_id = ($browser->content =~ /player.SetPlayer.(\d+)/i)[0];
7499
7500  debug "Extracted playerId: $player_id, videoId: $video_id"
7501    if $player_id or $video_id;
7502
7503  if(!$video_id) {
7504    my $video_offset = ($browser->content =~ /player.SetVideo.\w+\[(\d+)/i)[0];
7505    $video_id = ($browser->content =~ /videos\[$video_offset\].+'(\d+)'\s*\]/)[0];
7506  }
7507
7508  die "Unable to extract Brightcove IDs from page"
7509    unless $player_id and $video_id;
7510
7511  return $self->amfgateway($browser, $player_id, { videoId => $video_id, } );
7512}
7513
7514sub can_handle {
7515  my($self, $browser, $url) = @_;
7516
7517  return $browser->content =~ /player = CanoeVideoStandalone\.create\(\);/i;
7518}
7519
75201;
7521}
7522##} blib/lib/FlashVideo/Site/Tva.pm
7523BEGIN { $INC{'FlashVideo/Site/Ustream.pm'}++; }
7524# Part of get-flash-videos. See get_flash_videos for copyright.
7525##{ blib/lib/FlashVideo/Site/Ustream.pm
7526{
7527package FlashVideo::Site::Ustream;
7528
7529use strict;
7530BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7531BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7532use MIME::Base64;
7533
7534sub find_video {
7535  my ($self, $browser, $embed_url) = @_;
7536
7537  unless(eval { require Data::AMF::Packet }) {
7538    die "Must have Data::AMF::Packet installed to download ustream videos";
7539  }
7540
7541  my $packet = Data::AMF::Packet->deserialize(decode_base64(<<EOF));
7542AAAAAAABAA9WaWV3ZXIuZ2V0VmlkZW8AAi8xAAAAiAoAAAABAwAIYXV0b3BsYXkBAQAEcnBpbgIA
7543GHJwaW4uMC4xODM2MDk4NTkzMTY0Njg5OAAHdmlkZW9JZAIABzIzNTU3MzYAB3BhZ2VVcmwCACZo
7544dHRwOi8vd3d3LnVzdHJlYW0udHYvcmVjb3JkZWQvMjM1NTczNgAHYnJhbmRJZAIAATEAAAkK
7545EOF
7546
7547  my $title = extract_info($browser)->{meta_title};
7548
7549  my($video_id) = $browser->uri =~ m{recorded/(\d+)};
7550  $video_id ||= $browser->content =~ m{vid\s*=\s*["']?(\d+)};
7551
7552  $packet->messages->[0]->{value}->[0]->{videoId} = $video_id;
7553
7554  my $data = $packet->serialize;
7555
7556  $browser->post(
7557    "http://rgw.ustream.tv/gateway.php",
7558    Content_Type => "application/x-amf",
7559    Content => $data
7560  );
7561
7562  die "Failed to post to Ustream AMF gateway"
7563    unless $browser->response->is_success;
7564
7565  my($flv_url) = $browser->content =~ /flv.{3,5}(http:[^\0]+)/;
7566
7567  return $flv_url, title_to_filename($title);
7568}
7569
75701;
7571}
7572##} blib/lib/FlashVideo/Site/Ustream.pm
7573BEGIN { $INC{'FlashVideo/Site/Videobb.pm'}++; }
7574# Part of get-flash-videos. See get_flash_videos for copyright.
7575##{ blib/lib/FlashVideo/Site/Videobb.pm
7576{
7577package FlashVideo::Site::Videobb;
7578
7579use strict;
7580BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7581BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7582BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
7583BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
7584use MIME::Base64;
7585
7586sub find_video {
7587  my ($self, $browser) = @_;
7588
7589  if($browser->status == 302) {
7590    $browser->allow_redirects;
7591    $browser->get;
7592  }
7593  my $flash_settings_b64 = ($browser->content =~ /<param value="setting=([^"]+)" name="FlashVars">/s)[0];
7594  my $flash_settings = decode_base64($flash_settings_b64);
7595
7596  $browser->get($flash_settings);
7597
7598  if (!$browser->success) {
7599    die "Couldn't download video settings: " . $browser->response->status_line;
7600  }
7601
7602  my $settings_data = from_json($browser->content);
7603
7604  my $url = decode_base64($settings_data->{settings}{res}->[-1]->{u});
7605
7606  my $title  = $settings_data->{settings}{video_details}{video}{title};
7607  my $filename = title_to_filename($title);
7608
7609  return $url, $filename;
7610}
7611
76121;
7613}
7614##} blib/lib/FlashVideo/Site/Videobb.pm
7615BEGIN { $INC{'FlashVideo/Site/Videojug.pm'}++; }
7616# Part of get-flash-videos. See get_flash_videos for copyright.
7617##{ blib/lib/FlashVideo/Site/Videojug.pm
7618{
7619package FlashVideo::Site::Videojug;
7620
7621use strict;
7622BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7623BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
7624
7625my $playlist_url = "http://www.videojug.com/views/film/playlist.aspx?items=&userName=&ar=16_9&id=";
7626
7627sub find_video {
7628  my ($self, $browser) = @_;
7629
7630  my $interview_clip;
7631
7632  if ($browser->uri->as_string =~ m'/interview/'i) {
7633    $playlist_url =
7634      "http://www.videojug.com/views/interview/playlist.aspx?ar=16_9&id=";
7635
7636    $interview_clip = $browser->uri->fragment;
7637  }
7638
7639  my $video_id;
7640
7641  if ($browser->content =~
7642    /<meta name=["']video-id["'] content="([A-F0-9a-f\-]+)"/) {
7643    $video_id = $1;
7644  } else {
7645    die "Couldn't find video ID in Videojug page";
7646  }
7647
7648  $browser->get($playlist_url . $video_id);
7649
7650
7651  my($video_url, $filename);
7652  eval {
7653    my $xml = from_xml($browser);
7654
7655    my $shape = $xml->{Shapes}->{Shape}->[-1];
7656    my $location = (grep { $shape->{Locations} =~ /\Q$_->{Name}\E/ }
7657      @{$xml->{Locations}->{Location}})[0];
7658
7659    my ($prefix, $title);
7660
7661    if ($interview_clip) {
7662      ($prefix, $title) = get_prefix_and_title($xml, $interview_clip);
7663    }
7664    else {
7665      $prefix = $xml->{Items}->{Media}->{Prefix};
7666      $title = $xml->{Items}->{Media}->{Title};
7667    }
7668
7669    $video_url = sprintf "%s%s__%sENG.flv",
7670      $location->{Url}, $prefix, $shape->{Code};
7671
7672    $filename = title_to_filename($title);
7673  };
7674  die "Unable to retrieve/parse Videojug playlist. $@" if $@;
7675
7676  die "Couldn't find video URL" unless $video_url;
7677
7678  return $video_url, $filename;
7679}
7680
7681sub get_prefix_and_title {
7682  my ($xml, $video_name) = @_;
7683
7684  foreach my $media (@{ $xml->{Items}->{Media} }) {
7685    my $title = lc $media->{Title};
7686    $title =~ s/ /-/g;
7687    $title =~ s/[^a-z0-9\-]//g;
7688
7689    if ($title eq $video_name) {
7690      return $media->{Prefix}, $media->{Title};
7691    }
7692  }
7693
7694  die "Couldn't find prefix for video '$video_name'";
7695}
7696
76971;
7698}
7699##} blib/lib/FlashVideo/Site/Videojug.pm
7700BEGIN { $INC{'FlashVideo/Site/Videolectures.pm'}++; }
7701# Part of get-flash-videos. See get_flash_videos for copyright.
7702##{ blib/lib/FlashVideo/Site/Videolectures.pm
7703{
7704package FlashVideo::Site::Videolectures;
7705
7706use strict;
7707BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7708BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7709
7710sub find_video {
7711  my ($self, $browser) = @_;
7712
7713  my $author = ($browser->content =~ /author:\s*<\/span><a [^>]+>([^<]+)/s)[0];
7714  my $title  = ($browser->content =~ /<h2>([^<]+)/)[0];
7715
7716  my $streamer = ($browser->content =~ /clip\.netConnectionUrl\s*=\s*["']([^"']+)/)[0];
7717  my $playpath = ($browser->content =~ /clip\.url\s*=\s*["']([^"']+)/)[0];
7718  $playpath =~ s/\.flv$//;
7719
7720  my $data = {
7721    app      => (split m{/}, $streamer)[-1],
7722    rtmp     => $streamer,
7723    playpath => $playpath,
7724    flv      => title_to_filename("$author - $title")
7725  };
7726
7727  return $data;
7728}
7729
77301;
7731}
7732##} blib/lib/FlashVideo/Site/Videolectures.pm
7733BEGIN { $INC{'FlashVideo/Site/Vimeo.pm'}++; }
7734# Part of get-flash-videos. See get_flash_videos for copyright.
7735##{ blib/lib/FlashVideo/Site/Vimeo.pm
7736{
7737package FlashVideo::Site::Vimeo;
7738
7739use strict;
7740BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7741BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
7742
7743sub find_video {
7744  my ($self, $browser, $embed_url) = @_;
7745  my $base = "http://vimeo.com/moogaloop";
7746
7747  my $id;
7748  if($embed_url =~ /clip_id=(\d+)/) {
7749    $id = $1;
7750  } elsif($embed_url =~ m!/(\d+)!) {
7751    $id = $1;
7752  }
7753  die "No ID found\n" unless $id;
7754
7755  $browser->get("$base/load/clip:$id/embed?param_fullscreen=1&param_clip_id=$id&param_show_byline=0&param_server=vimeo.com&param_color=cc6600&param_show_portrait=0&param_show_title=1");
7756
7757  my $xml = from_xml($browser);
7758  my $filename = title_to_filename($xml->{video}->{caption});
7759  my $request_signature = $xml->{request_signature};
7760  my $request_signature_expires = $xml->{request_signature_expires};
7761  my $isHD = $xml->{video}->{isHD};
7762
7763  $browser->allow_redirects;
7764
7765  my $url = "$base/play/clip:$id/$request_signature/$request_signature_expires/?q=hd&type=embed";
7766  if ($isHD == '1') {
7767      return $url, $filename;
7768  };
7769  $url = "$base/play/clip:$id/$request_signature/$request_signature_expires/?q=sd&type=embed";
7770  return $url, $filename;
7771}
7772
77731;
7774}
7775##} blib/lib/FlashVideo/Site/Vimeo.pm
7776BEGIN { $INC{'FlashVideo/Site/Vrak.pm'}++; }
7777##{ blib/lib/FlashVideo/Site/Vrak.pm
7778{
7779package FlashVideo::Site::Vrak;
7780
7781use strict;
7782BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7783BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
7784no strict 'refs';
7785
7786
7787
7788sub find_video {
7789  my($self, $browser, $embed_url, $prefs) = @_;
7790
7791  my $check_response = sub {
7792    my ( $message ) = @_;
7793    return if $browser->success;
7794    die sprintf $message, $browser->response->code;
7795  };
7796
7797
7798  my $videoID = 0;
7799
7800  ( $videoID ) = ( $browser->content =~ /var\s+videoId\s*=\s*(\d+)\s*;/i );
7801  debug "VIDEOID = " . $videoID;
7802
7803  die "No Vrak Video ID found" unless  $videoID;
7804
7805  my $title;
7806  ( $title ) = ( $browser->content =~ /var\s+videoTitle\s*=\s*"([^"]+)/i );
7807
7808  debug "TITLE = " . $title . " " . title_to_filename($title, 'flv');
7809
7810  my $xmlurl = 'http://www.vrak.tv/webtele/_dyn/getVideoDataXml.jsp?videoId=' . $videoID;
7811  $browser->get($xmlurl);
7812  my $xml = from_xml($browser);
7813
7814  my $url;
7815  if ( $prefs->{quality} == "high" ) {
7816        $url = $xml->{video}->{highFlvUrl};
7817  } else {
7818        $url = $xml->{video}->{lowFlvUrl};
7819  }
7820  debug "URL = " . $url;
7821
7822  my $ext;
7823  ( $ext ) = ( $url =~ /\.(.+)$/i );
7824
7825  die "No (high|low)FlvUrl found in XML ". $xmlurl unless $url;
7826
7827  return $url, title_to_filename($title);
7828
7829 }
7830
78311;
7832
7833}
7834##} blib/lib/FlashVideo/Site/Vrak.pm
7835BEGIN { $INC{'FlashVideo/Site/Wat.pm'}++; }
7836# Part of get-flash-videos. See get_flash_videos for copyright.
7837##{ blib/lib/FlashVideo/Site/Wat.pm
7838{
7839package FlashVideo::Site::Wat;
7840
7841use strict;
7842BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7843BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
7844use HTML::Entities;
7845use URI::Escape;
7846
7847die "Must have Digest::MD5 for this download\n"
7848  unless eval {
7849    require Digest::MD5;
7850  };
7851
7852sub token {
7853  my $url = shift;
7854  my $hexdate = sprintf("%x",time());
7855  $hexdate .= "0" x (length($hexdate) - 8);
7856  my $key = "9b673b13fa4682ed14c3cfa5af5310274b514c4133e9b3a81e6e3aba00912564";
7857  return Digest::MD5::md5_hex($key . $url . $hexdate)."/".$hexdate;
7858}
7859
7860
7861sub find_video {
7862  my ($self, $browser) = @_;
7863
7864  $browser->content =~ /url\s*:\s*["'].*?nIc0K11(\d+)["']/i
7865    || die "No video ID found";
7866  my $video_id = $1;
7867
7868  $browser->get("http://www.wat.tv/interface/contentv3/$video_id");
7869
7870  my $title = json_unescape(($browser->content =~ /title":"(.*?)",/)[0]);
7871
7872  my $location = "/web/$video_id";
7873  my $token = &token($location);
7874
7875  my $url = "http://www.wat.tv/get".$location.
7876         "?token=".$token.
7877         "&context=swf2&getURL=1&version=WIN%2010,3,181,14";
7878
7879  my $file_type = 'flv';
7880
7881  $browser->head($url);
7882
7883  if (!$browser->success) {
7884    die "Couldn't do HEAD request $url: " . $browser->response->status_line;
7885  }
7886
7887  my $content_type = $browser->response->header('Content-Type');
7888  if ($content_type =~ /text/) {
7889    $browser->get($url);
7890
7891    if (!$browser->success) {
7892      die "Couldn't get $url: " . $browser->response->status_line;
7893    }
7894
7895    if ($browser->content =~ m'^(http://\S+)') {
7896      $url = $1;
7897
7898      if ($url =~ /\.h264/) {
7899        $file_type = 'mp4';
7900      }
7901    }
7902  }
7903  else {
7904    die "Unexpected Content-Type ($content_type) from Wat server.";
7905  }
7906
7907  my $filename = title_to_filename($title, $file_type);
7908
7909  $browser->allow_redirects;
7910
7911  return $url, $filename;
7912}
7913
79141;
7915}
7916##} blib/lib/FlashVideo/Site/Wat.pm
7917BEGIN { $INC{'FlashVideo/Site/Xhamster.pm'}++; }
7918# Part of get-flash-videos. See get_flash_videos for copyright.
7919##{ blib/lib/FlashVideo/Site/Xhamster.pm
7920{
7921package FlashVideo::Site::Xhamster;
7922
7923use strict;
7924BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7925BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7926
7927sub find_video {
7928  my ($self, $browser) = @_;
7929
7930  my $server;
7931  if ($browser->content =~ m{'srv': '(http://[^'"]+)'}) {
7932    $server = $1;
7933  }
7934  else {
7935    die "Couldn't determine xhamster server";
7936  }
7937
7938  my $video_file;
7939  if ($browser->content =~ m{'file': '([^'"]+\.flv)'}) {
7940    $video_file = $1;
7941  }
7942  else {
7943    die "Couldn't determine xhamster video filename";
7944  }
7945
7946  my $filename = title_to_filename(extract_title($browser));
7947
7948  my $url = sprintf "%s/flv2/%s", $server, $video_file;
7949
7950  $browser->allow_redirects;
7951
7952  return $url, $filename;
7953}
7954
79551;
7956}
7957##} blib/lib/FlashVideo/Site/Xhamster.pm
7958BEGIN { $INC{'FlashVideo/Site/Xnxx.pm'}++; }
7959# Part of get-flash-videos. See get_flash_videos for copyright.
7960##{ blib/lib/FlashVideo/Site/Xnxx.pm
7961{
7962package FlashVideo::Site::Xnxx;
7963
7964use strict;
7965BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
7966BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
7967use URI::Escape;
7968
7969sub find_video {
7970  my ($self, $browser, $embed_url) = @_;
7971
7972  my $url = ($browser->content =~ /flv_url=(.+?)&/)[0];
7973  $url = uri_unescape($url);
7974  die "Unable to extract url" unless $url;
7975
7976  $browser->content =~ /(?:<span class="style5">|<td style="font-size: 20px;">\s*)<strong>([^<]+)/;
7977
7978  my $filename = title_to_filename($1);
7979
7980  return $url, $filename;
7981}
7982
79831;
7984}
7985##} blib/lib/FlashVideo/Site/Xnxx.pm
7986BEGIN { $INC{'FlashVideo/Site/Xvideos.pm'}++; }
7987# Part of get-flash-videos. See get_flash_videos for copyright.
7988##{ blib/lib/FlashVideo/Site/Xvideos.pm
7989{
7990package FlashVideo::Site::Xvideos;
7991
7992use strict;
7993BEGIN { FlashVideo::Site::Xnxx->import(); } # (added by utils/combine-perl.pl)
7994use base 'FlashVideo::Site::Xnxx';
7995
79961;
7997}
7998##} blib/lib/FlashVideo/Site/Xvideos.pm
7999BEGIN { $INC{'FlashVideo/Site/Youku.pm'}++; }
8000##{ blib/lib/FlashVideo/Site/Youku.pm
8001{
8002package FlashVideo::Site::Youku;
8003
8004use strict;
8005BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
8006BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
8007BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
8008BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; }
8009
8010sub find_video {
8011  my ($self, $browser, $embed_url) = @_;
8012
8013  my $check_response = sub {
8014    my ( $message ) = @_;
8015    return if $browser->success;
8016    die sprintf $message, $browser->response->code;
8017  };
8018
8019
8020  if ( $embed_url !~ m`^http://v.youku.com/v_show/` )
8021  {
8022    die "Don't recognise the youku link"
8023      unless $embed_url =~ m`player.php/sid/(.+)/v\.swf`
8024      or $embed_url =~ m`qplayer\.swf\?VideoIDS=([^&]+)`;
8025
8026    $embed_url = sprintf "http://v.youku.com/v_show/id_%s.html", $1;
8027    $browser->get( $embed_url );
8028  }
8029  $check_response->( "Can't load the youku page, server response was %s" );
8030
8031  my ( $videoID ) = ( $browser->content =~ /var videoId = '(.+?)';/ );
8032  die "Couldn't extract video ID from youku page, we are probably out of date"
8033    unless $videoID;
8034  debug "Using video ID $videoID";
8035
8036  $browser->get(
8037    sprintf "http://v.youku.com/player/getPlayList/VideoIDS/%s/version/5/source/video/password/?ran=%d&n=%d",
8038    $videoID, rand( 10000 ), 3 );
8039  $check_response->( "Couldn't grab video informaton from youku, server response was %s" );
8040
8041  return parse_video_info( $browser );
8042}
8043
8044sub extract {
8045  my ($json, $key, $type) = @_;
8046  die "Can't find '$key' key in the JSON data"
8047    unless exists $json->{$key};
8048  my $data = $json->{$key};
8049  if (defined $type) {
8050    my $dtype = ref $data || 'DATA';
8051    die "JSON data under '$key' is not the right type"
8052      . " (expecting $type, but got $dtype)"
8053      unless $dtype eq $type;
8054  }
8055  return $data;
8056}
8057
8058sub parse_video_info {
8059  my ($browser) = @_;
8060
8061  my $jsonstr = $browser->content;
8062  debug "Video data: $jsonstr";
8063
8064  my $json = from_json($jsonstr);
8065
8066  my $data_array = extract($json, data => 'ARRAY');
8067  die "No elements found in 'data' array" unless @$data_array;
8068  my $data = $data_array->[0];
8069
8070  my $segmap = extract($data, segs => 'HASH');
8071
8072  my @streamtype_preferences = qw(mp4 flv);
8073  my @streamtypes = keys %$segmap;
8074
8075  my $stream = $streamtypes[0];
8076
8077  for my $pref (@streamtype_preferences) {
8078    if (grep { $_ eq $pref } @streamtypes) {
8079      $stream = $pref;
8080      last;
8081    }
8082  }
8083
8084  my $streams = join ' ', @streamtypes;
8085  debug "Choosing to use the $stream stream (available: $streams)";
8086
8087  my $fileID;
8088  if (exists $data->{streamfileids}) {
8089    my $streamfileids = extract($data, streamfileids => 'HASH');
8090
8091    $fileID = extract($streamfileids, $stream)
8092      if exists $streamfileids->{$stream};
8093  }
8094
8095  $fileID = extract($data, 'fileid')
8096    if not $fileID and exists $data->{fileid};
8097
8098  die "Can't find the encrypted file ID in the video info JSON"
8099    unless $fileID;
8100  debug "Encrypted file ID: $fileID";
8101
8102  my $shuffle_seed = extract($data, 'seed');
8103
8104  my @lookup_table = shuffle_table( $shuffle_seed );
8105  $fileID =~ s/(\d+)\*/$lookup_table[$1]/eg;
8106  debug "Decrypted file ID: $fileID (seed is $shuffle_seed)";
8107
8108  my $sID = sprintf "%s1%07d_00", time, rand( 10000000 ) ;
8109
8110  my $key1 = extract($data, 'key1');
8111  my $key2 = extract($data, 'key2');
8112  my $key = sprintf "%s%x", $key2, hex( $key1 ) ^ hex( 'a55aa5a5' );
8113
8114  my $title = extract($data, 'title');
8115  $title =~ s/\\u([a-f0-9]{4})/chr(hex $1)/egi;
8116
8117  my $filename = get_video_filename( $stream );
8118  $filename = title_to_filename( $title, $stream ) if $title;
8119
8120  my $segs = extract($segmap, $stream, 'ARRAY');
8121
8122  my @urls;
8123  my $segment_count = 0;
8124
8125  for my $seg (@$segs) {
8126    my $segment_number = extract($seg, 'no');
8127    my $segment_size = extract($seg, 'size');
8128    my $segment_seconds = extract($seg, 'seconds');
8129    $key = extract($seg, 'k') if exists $seg->{'k'};
8130
8131    my $segment_number_str = sprintf '%02X', $segment_number;
8132    my $segment_fileID = $fileID;
8133    substr $segment_fileID, 8, 2, $segment_number_str;
8134
8135    $browser->get(
8136      sprintf "http://f.youku.com/player/getFlvPath/sid/%s/st/%s/fileid/%s?K=%s&myp=0&ts=%s",
8137        $sID, $stream, $segment_fileID, $key, $segment_seconds );
8138
8139    my $url = $browser->response->header( 'Location' );
8140    die "Youku rejected our attempt to get the video, we're probably out of date"
8141      unless $browser->response->code eq 302 and $url;
8142
8143    debug "Video location for segment $segment_number is $url";
8144    $url = "$url.$stream" unless $url =~ /$stream$/;
8145
8146    debug sprintf "%s, segment %d, %s seconds, %s bytes",
8147      $title, $segment_number, $segment_seconds, $segment_size
8148      if ( $title and $segment_seconds and $segment_size );
8149
8150    push @urls, [$url, ++$segment_count, 0, $segment_size];
8151  }
8152
8153  $_->[2] = $segment_count for @urls;
8154
8155  return ( \@urls, $filename );
8156}
8157
8158sub shuffle_table {
8159  my ( $seed ) = @_;
8160  my @lookup
8161    = split //,
8162      q`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890`;
8163
8164  my @shuffled;
8165  while ( $#lookup > 0 )
8166  {
8167    $seed = ( 211 * $seed + 30031 ) % 2**16;
8168
8169    my $x = int( $seed / 2**16 * ( $#lookup + 1 ) );
8170    push @shuffled, splice( @lookup, $x, 1 );
8171  }
8172  return @shuffled;
8173}
8174
81751;
8176}
8177##} blib/lib/FlashVideo/Site/Youku.pm
8178BEGIN { $INC{'FlashVideo/Site/Youtu.pm'}++; }
8179# Part of get-flash-videos. See get_flash_videos for copyright.
8180BEGIN { $INC{'FlashVideo/Site/Youtube.pm'}++; }
8181# Part of get-flash-videos. See get_flash_videos for copyright.
8182##{ blib/lib/FlashVideo/Site/Youtube.pm
8183{
8184package FlashVideo::Site::Youtube;
8185
8186use strict;
8187use Encode;
8188use HTML::Entities;
8189BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
8190BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *json_unescape = \&FlashVideo::Utils::json_unescape; }
8191BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
8192BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
8193use URI::Escape;
8194
8195my @formats = (
8196  { id => 38, resolution => [4096, 2304] },
8197  { id => 37, resolution => [1920, 1080] },
8198  { id => 22, resolution => [1280, 720] },
8199  { id => 35, resolution => [854, 480] },
8200  { id => 34, resolution => [640, 360] },
8201  { id => 18, resolution => [480, 270] },
8202  { id => 5,  resolution => [400, 224] },
8203  { id => 17, resolution => [176, 144] },
8204  { id => 13, resolution => [176, 144] },
8205);
8206
8207sub find_video {
8208  my ($self, $browser, $embed_url, $prefs) = @_;
8209
8210  if($embed_url !~ m!youtube\.com/watch!) {
8211    $browser->get($embed_url);
8212    if ($browser->response->header('Location') =~ m!/swf/.*video_id=([^&]+)!
8213        || $browser->content =~ m!\<iframe[^\>]*src="http://www.youtube.com/embed/([^"]+)"!i
8214        || $embed_url =~ m!/v/([-_a-z0-9]+)!i
8215        || $browser->uri =~ m!v%3D([-_a-z0-9]+)!i) {
8216      $embed_url = "http://www.youtube.com/watch?v=$1";
8217      $browser->get($embed_url);
8218    }
8219  }
8220
8221  if (!$browser->success) {
8222    verify_age($browser, $prefs);
8223  }
8224
8225  my $title = extract_info($browser)->{meta_title};
8226  if (!$title and
8227    $browser->content =~ /<div id="vidTitle">\s+<span ?>(.+?)<\/span>/ or
8228      $browser->content =~ /<div id="watch-vid-title">\s*<div ?>(.+?)<\/div>/) {
8229    $title = $1;
8230  }
8231
8232  if ($browser->content =~ /["']fmt_url_map["']:\s{0,3}(["'][^"']+["'])/) {
8233    my $fmt_map = $1;
8234    if ($fmt_map !~ /\|/) {
8235      $fmt_map = uri_unescape($fmt_map);
8236    }
8237    debug "Using fmt_url_map method from page ($fmt_map)";
8238    return $self->download_fmt_map($prefs, $browser, $title, {}, @{from_json $fmt_map});
8239  }
8240
8241  my $video_id;
8242  if ($browser->content =~ /(?:var pageVideoId =|(?:CFG_)?VIDEO_ID'?\s*:)\s*'(.+?)'/
8243      || $browser->content =~ /"video_id": "([^"]+)"/
8244      || $embed_url =~ /v=([^&]+)/
8245      || $browser->content =~ /&amp;video_id=([^&]+)&amp;/) {
8246    $video_id = $1;
8247  } else {
8248    check_die($browser, "Couldn't extract video ID");
8249  }
8250
8251  my $t;
8252  if ($browser->content =~ /\W['"]?t['"]?: ?['"](.+?)['"]/) {
8253    $t = $1;
8254  }
8255
8256  my $video_page_url = $browser->uri->as_string;
8257
8258  if (my %info = get_youtube_video_info($browser->clone, $video_id, $video_page_url, $t)) {
8259    if($self->debug) {
8260      require Data::Dumper;
8261      debug Data::Dumper::Dumper(\%info);
8262    }
8263
8264    if ($info{conn} =~ /^rtmp/) {
8265      my ($season, $episode);
8266
8267      if ($browser->content =~ m{<span[^>]*>Season ?(\d+)}i) {
8268        $season = $1;
8269      }
8270
8271      if ($browser->content =~ m{<span[^>]*>[^<]+Ep\.?\w* ?(\d+)\W*\s*</span>}i) {
8272        $episode = $1;
8273      }
8274
8275      if ($season and $episode) {
8276        $title .= sprintf " S%02dE%02d", $season, $episode;
8277      }
8278
8279      my $swf_url;
8280      if ($browser->content =~ /SWF_URL['"] ?: ?.{0,90}?(http:\/\/[^ ]+\.swf)/) {
8281        $swf_url = $1;
8282      } elsif($browser->content =~ /swfConfig\s*=\s*(\{.*?\});/ && (my $swf = from_json($1))) {
8283        $swf_url = $swf->{url};
8284      } elsif($browser->content =~ /src=\\['"]([^'"]+\.swf)/) {
8285        $swf_url = json_unescape($1);
8286      } else {
8287        die "Couldn't extract SWF URL";
8288      }
8289
8290      my $rtmp_url = $info{conn};
8291
8292      if($info{fmt_stream_map}) {
8293        my $fmt_stream_map = parse_youtube_format_url_map($info{fmt_stream_map}, 1);
8294
8295        my $preferred_quality = $prefs->quality->choose(map { $fmt_stream_map->{$_->{id}}
8296            ? { resolution => $_->{resolution}, url => $fmt_stream_map->{$_->{id}} }
8297            : () } @formats);
8298
8299        $rtmp_url = $preferred_quality->{url};
8300      }
8301
8302      return {
8303        flv => title_to_filename($title),
8304        rtmp => $rtmp_url,
8305        swfhash($browser, $swf_url)
8306      };
8307    } elsif($info{fmt_url_map}) {
8308      debug "Using fmt_url_map method from info";
8309      return $self->download_fmt_map($prefs, $browser, $title, \%info, $info{fmt_url_map});
8310    } elsif($info{url_encoded_fmt_stream_map}) {
8311      debug "Using url_encoded_fmt_stream_map method from info";
8312      if ($info{title}) {
8313        $title=$info{title};
8314      }
8315      return $self->download_url_encoded_fmt_stream_map($prefs, $browser, $title, \%info, $info{url_encoded_fmt_stream_map});
8316    }
8317  }
8318
8319  return download_get_video($browser, $prefs, $video_id, $title, $t);
8320}
8321
8322sub download_url_encoded_fmt_stream_map {
8323  my($self, $prefs, $browser, $title, $info, $fmt_map) = @_;
8324
8325  my $fmt_url_map = parse_youtube_url_encoded_fmt_stream_map($fmt_map);
8326
8327  if (!$title and $browser->uri->as_string =~ m'/user/.*?#') {
8328    my $video_id = (split /\//, $browser->uri->fragment)[-1];
8329
8330    my %info = get_youtube_video_info($browser->clone, $video_id);
8331
8332    $title = $info->{title};
8333  }
8334
8335  my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}}
8336      ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} }
8337      : () } @formats);
8338
8339  $browser->allow_redirects;
8340
8341  return $preferred_quality->{url}, title_to_filename($title, "mp4");
8342}
8343
8344sub parse_youtube_url_encoded_fmt_stream_map {
8345  my($raw_map) = @_;;
8346
8347  my $map = {};
8348
8349  foreach my $params (split /,/, $raw_map) {
8350
8351    my $format = "";
8352    my $url = "";
8353
8354    foreach my $pair (split /&/, $params) {
8355      my ($name, $value) = split /=/, $pair;
8356      if ($name eq "itag"){
8357        $format = $value;
8358      } elsif ($name eq "url") {
8359        $url = uri_unescape($value);
8360      }
8361    }
8362
8363    $map->{$format} = $url;
8364  }
8365
8366  return $map;
8367}
8368
8369sub download_fmt_map {
8370  my($self, $prefs, $browser, $title, $info, $fmt_map) = @_;
8371
8372  my $fmt_url_map = parse_youtube_format_url_map($fmt_map);
8373
8374  if (!$title and $browser->uri->as_string =~ m'/user/.*?#') {
8375    my $video_id = (split /\//, $browser->uri->fragment)[-1];
8376
8377    my %info = get_youtube_video_info($browser->clone, $video_id);
8378
8379    $title = $info->{title};
8380  }
8381
8382  my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}}
8383      ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} }
8384      : () } @formats);
8385
8386  $browser->allow_redirects;
8387
8388  return $preferred_quality->{url}, title_to_filename($title, "mp4");
8389}
8390
8391sub download_get_video {
8392  my($browser, $prefs, $video_id, $title, $t) = @_;
8393
8394  my $fetcher = sub {
8395    my($url, $filename) = @_;
8396    $url = url_exists($browser->clone, $url, 1);
8397    return $url, $filename if $url;
8398    return;
8399  };
8400
8401  my @formats_to_try = @formats;
8402
8403  while(my $fmt = $prefs->quality->choose(@formats_to_try)) {
8404    @formats_to_try = grep { $_ != $fmt } @formats_to_try;
8405
8406    my @ret = $fetcher->("http://www.youtube.com/get_video?fmt=$fmt->{id}&video_id=$video_id&t=$t",
8407      title_to_filename($title, "mp4"));
8408    return @ret if @ret;
8409  }
8410
8411  my @ret = $fetcher->("http://www.youtube.com/get_video?video_id=$video_id&t=$t",
8412    title_to_filename($title));
8413
8414  check_die($browser, "Unable to find video URL") unless @ret;
8415
8416  $browser->allow_redirects;
8417
8418  return @ret;
8419}
8420
8421sub check_die {
8422  my($browser, $message) = @_;
8423
8424  if($browser->content =~ m{class="yt-alert-content">([^<]+)}) {
8425    my $alert = $1;
8426    $alert =~ s/(^\s+|\s+$)//g;
8427    $message .= "\nYouTube: $alert";
8428    error $message;
8429    exit 1;
8430  } else {
8431    die "$message\n";
8432  }
8433}
8434
8435sub verify_age {
8436  my($browser, $prefs) = @_;
8437  my $orig_uri = $browser->uri;
8438
8439  if ($browser->response->code == 303
8440    && $browser->response->header('Location') =~ m!/verify_age|/accounts/!) {
8441
8442    my $confirmation_url = $browser->response->header('Location');
8443    $browser->get($confirmation_url);
8444
8445    if($browser->content =~ /has_verified=1/) {
8446      my($verify_url) = $browser->content =~ /href="(.*?has_verified=1)"/;
8447      $verify_url = decode_entities($verify_url);
8448      $browser->get($verify_url);
8449      return if $browser->response->code == 200;
8450    }
8451
8452    my $account = $prefs->account("youtube", <<EOT);
8453Unfortunately, due to Youtube being lame, you have to have
8454an account to download this video. (See the documentation for how to configure
8455~/.netrc)
8456
8457EOT
8458
8459    unless ($account->username and $account->password) {
8460      error "You must supply Youtube account details.";
8461      exit 1;
8462    }
8463
8464    $browser->get("http://www.youtube.com/login");
8465    if ($browser->response->code != 303) {
8466      die "Unexpected response from Youtube login.\n";
8467    }
8468
8469    my $real_login_url = $browser->response->header('Location');
8470    $browser->get($real_login_url);
8471
8472    $browser->form_with_fields('Email', 'Passwd');
8473    $browser->set_fields(
8474      Email  => $account->username,
8475      Passwd => $account->password,
8476    );
8477    $browser->submit();
8478
8479    if ($browser->content =~ /your login was incorrect/) {
8480      error "Couldn't log you in, check your username and password.";
8481      exit 1;
8482    } elsif ($browser->response->code == 302) {
8483      my $check_cookie_url = $browser->response->header('Location');
8484      $browser->get($check_cookie_url);
8485
8486      if ($browser->content =~ /<meta.*"refresh".*?url=&#39;(.*?)&#39;"/i) {
8487        my $redirected = decode_entities($1);
8488        $browser->get($redirected);
8489
8490        if(URI->new($redirected)->host !~ /youtube/i) {
8491          if($browser->response->code == 302) {
8492            $browser->get($browser->response->header("Location"));
8493          } else {
8494            die "Did not find expected redirection";
8495          }
8496        }
8497      } else {
8498        die "Did not find expected redirection";
8499      }
8500    }
8501    else {
8502      die "Unexpected response during login";
8503    }
8504
8505    $browser->get($orig_uri);
8506
8507    if ($browser->response->code == 303) {
8508      my $real_confirmation_url = $browser->response->header('Location');
8509      $browser->get($real_confirmation_url);
8510      if ($browser->form_with_fields('next_url', 'action_confirm')) {
8511        $browser->field('action_confirm' => 'Confirm Birth Date');
8512        $browser->click_button(name => "action_confirm");
8513
8514        if ($browser->response->code != 303) {
8515          die "Unexpected response from Youtube";
8516        }
8517        $browser->get($browser->response->header('Location'));
8518      }
8519    }
8520  }
8521  else {
8522    if ($browser->response->code == 302) {
8523      $browser->get($browser->response->header('Location'));
8524    }
8525
8526    if ($browser->response->code == 303) {
8527      debug "Video not available (303), trying " . $browser->response->header('Location');
8528      $browser->get($browser->response->header('Location'));
8529    }
8530
8531    if (!$browser->success) {
8532      die "Couldn't download URL: " . $browser->response->status_line;
8533    }
8534  }
8535}
8536
8537sub get_youtube_video_info {
8538  my ($browser, $video_id, $url, $t) = @_;
8539
8540  $url ||= "http://www.youtube.com/watch?v=$video_id";
8541
8542  for my $el(qw(profilepage detailpage)) {
8543    my $video_info_url_template =
8544      "http://www.youtube.com/get_video_info?&video_id=%s&el=$el&ps=default&eurl=%s&hl=en_US&t=%s";
8545
8546    my $video_info_url = sprintf $video_info_url_template,
8547      uri_escape($video_id), uri_escape($url), uri_escape_utf8($t);
8548
8549    debug "get_youtube_video_info: $video_info_url";
8550
8551    $browser->get($video_info_url);
8552
8553    next unless $browser->success;
8554
8555    my %info = parse_youtube_video_info($browser->content);
8556    next if $info{status} eq 'fail';
8557
8558    return %info;
8559  }
8560
8561  error "Unable to get YouTube video information.";
8562}
8563
8564sub parse_youtube_video_info {
8565  my $raw_info = shift;
8566
8567  my %video_info;
8568
8569  foreach my $raw_pair (split /&/, $raw_info) {
8570    my ($key, $value) = split /=/, $raw_pair;
8571    $value = uri_unescape($value);
8572    $value =~ s/\+/ /g;
8573
8574    $video_info{$key} = $value;
8575  }
8576
8577  return %video_info;
8578}
8579
8580sub parse_youtube_format_url_map {
8581  my($raw_map, $param_idx) = @_;
8582
8583  $param_idx = 0 unless defined $param_idx;
8584
8585  my $map = {};
8586
8587  foreach my $pair (split /,/, $raw_map) {
8588    my ($format, @params) = split /\|/, $pair;
8589
8590    my $url = $params[$param_idx];
8591
8592    $url = uri_unescape($url);
8593
8594    $map->{$format} = $url;
8595  }
8596
8597  return $map;
8598}
8599
86001;
8601}
8602##} blib/lib/FlashVideo/Site/Youtube.pm
8603##{ blib/lib/FlashVideo/Site/Youtu.pm
8604{
8605package FlashVideo::Site::Youtu;
8606
8607BEGIN { FlashVideo::Site::Youtube->import(); } # (added by utils/combine-perl.pl)
8608use base 'FlashVideo::Site::Youtube';
8609
86101;
8611}
8612##} blib/lib/FlashVideo/Site/Youtu.pm
8613BEGIN { $INC{'FlashVideo/Site/Youtubenocookie.pm'}++; }
8614# Part of get-flash-videos. See get_flash_videos for copyright.
8615##{ blib/lib/FlashVideo/Site/Youtubenocookie.pm
8616{
8617package FlashVideo::Site::Youtubenocookie;
8618
8619use strict;
8620BEGIN { FlashVideo::Site::Youtube->import(); } # (added by utils/combine-perl.pl)
8621use base 'FlashVideo::Site::Youtube';
8622
86231;
8624}
8625##} blib/lib/FlashVideo/Site/Youtubenocookie.pm
8626BEGIN { $INC{'FlashVideo/Site/Zdf.pm'}++; }
8627# Part of get-flash-videos. See get_flash_videos for copyright.
8628##{ blib/lib/FlashVideo/Site/Zdf.pm
8629{
8630package FlashVideo::Site::Zdf;
8631
8632use strict;
8633BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
8634BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
8635
8636sub find_video {
8637  my ($self, $browser, $embed_url, $prefs) = @_;
8638  my ($id, $filename, $videourl, $quality);
8639
8640  $quality = {high => 'veryhigh', low => 'low'}->{$prefs->{quality}};
8641
8642  debug "Zdf::find_video called, embed_url = \"$embed_url\"\n";
8643
8644  if($browser->content =~ /\/video\/(\d*)\/(.*)"/) {
8645    $id = $1;
8646    debug "found video $1 $2\n";
8647    $filename = title_to_filename($2);
8648
8649    $browser->get("http://www.zdf.de/ZDFmediathek/xmlservice/web/beitragsDetails?id=$id&ak=web");
8650
8651    if($browser->content =~ /(http:\/\/fstreaming\.zdf\.de\/zdf\/$quality\/.*\.meta)/) {
8652        $browser->get($1);
8653        if($browser->content =~ /(rtmp.*)</) {
8654            debug "found rtmp url\"$1\"\n";
8655            $videourl = {
8656                rtmp => $1,
8657                flv => $filename,
8658                swfVfy => "http://www.zdf.de/ZDFmediatek/flash/player.swf"
8659            };
8660        }
8661    }
8662  }
8663  return $videourl, $filename;
8664}
8665
86661;
8667}
8668##} blib/lib/FlashVideo/Site/Zdf.pm
8669BEGIN { $INC{'FlashVideo/Site/Zshare.pm'}++; }
8670# A get-flash-videos module for the zshare.net website
8671#################################################
8672#
8673# This file was automatically generated by utils/combine-perl.pl
8674# You should edit the original files, not this
8675# combined version.
8676#
8677# The original files are available at:
8678# http://github.com/monsieurvideo/get-flash-videos
8679#
8680#################################################
8681# Copyright (C) 2011 Rudolf Olah <rolah@goaugust.com>
8682# Licensed under the GNU GPL v3 or later
8683
8684# Created using the instructions from: http://code.google.com/p/get-flash-videos/wiki/AddingSite
8685
8686##{ blib/lib/FlashVideo/Site/Zshare.pm
8687{
8688package FlashVideo::Site::Zshare;
8689
8690use strict;
8691BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
8692BEGIN { no strict 'refs'; }
8693
8694sub find_video {
8695  my ($self, $browser, $embed_url, $prefs) = @_;
8696  $embed_url = ($browser->content =~ /iframe src="(.*videoplayer.*?)"/i)[0];
8697  $browser->get($embed_url);
8698  my $url = ($browser->content =~ /file:.*"(.*?)"/i)[0];
8699  my $filename = ($browser->content =~ /<title>.*?- (.*)<\/title>/i)[0];
8700  return $url, $filename;
8701}
8702
87031;
8704}
8705##} blib/lib/FlashVideo/Site/Zshare.pm
8706##{ .sitemodules
8707{
8708package main;
8709}
8710##} .sitemodules
8711#!/usr/bin/perl
8712BEGIN { $INC{'FlashVideo/URLFinder.pm'}++; }
8713# Part of get-flash-videos. See get_flash_videos for copyright.
8714BEGIN { $INC{'FlashVideo/Generic.pm'}++; }
8715# Part of get-flash-videos. See get_flash_videos for copyright.
8716##{ blib/lib/FlashVideo/Generic.pm
8717{
8718package FlashVideo::Generic;
8719
8720use strict;
8721BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
8722BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; }
8723use URI;
8724BEGIN { FlashVideo::URLFinder->import(); } # (added by utils/combine-perl.pl)
8725use URI::Escape qw(uri_unescape);
8726
8727my $video_re = qr!http[-:/a-z0-9%_.?=&]+@{[EXTENSIONS]}
8728                  (?:\?[-:/a-z0-9%_.?=&]+)?!xi;
8729
8730sub find_video {
8731  my ($self, $browser, $embed_url, $prefs) = @_;
8732
8733  if (!$browser->success) {
8734    $browser->get($browser->response->header('Location'));
8735    die "Couldn't download URL: " . $browser->response->status_line
8736      unless $browser->success;
8737  }
8738
8739  my ($possible_filename, $actual_url, $title);
8740  $title = extract_title($browser);
8741
8742  my @flv_urls = map {
8743    (m{http://.+?(http://.+?@{[EXTENSIONS]})}i) ? $1 : $_
8744  } ($browser->content =~ m{($video_re)}gi);
8745  if (@flv_urls) {
8746    require LWP::Simple;
8747    require Memoize;
8748    Memoize::memoize("LWP::Simple::head");
8749    @flv_urls = sort { (LWP::Simple::head($a))[1] <=> (LWP::Simple::head($b))[1] } @flv_urls;
8750    $possible_filename = (split /\//, $flv_urls[-1])[-1];
8751
8752    if ($flv_urls[-1] =~ /^http%3a%2f%2f/) {
8753      $flv_urls[-1] = uri_unescape($flv_urls[-1])
8754    }
8755
8756    $actual_url = url_exists($browser->clone, $flv_urls[-1]);
8757  }
8758
8759  my $filename_is_reliable;
8760
8761  if(!$actual_url) {
8762    RE: for my $regex(
8763        qr{(?si)<embed.*?flashvars=["']?([^"'>]+)},
8764        qr{(?si)<embed.*?src=["']?([^"'>]+)},
8765        qr{(?si)<a[^>]* href=["']?([^"'>]+?@{[EXTENSIONS]})},
8766        qr{(?si)<object[^>]*>.*?<param [^>]*value=["']?([^"'>]+)},
8767        qr{(?si)<object[^>]*>(.*?)</object>},
8768        qr{(?si)<script[^>]*>(.*?)</script>}) {
8769
8770      for my $param($browser->content =~ /$regex/gi) {
8771        (my $url, $possible_filename, $filename_is_reliable) = find_file_param($browser->clone, $param, $prefs);
8772
8773        if($url) {
8774          my $resolved_url = url_exists($browser->clone, $url);
8775          if($resolved_url) {
8776            $actual_url = $resolved_url;
8777            last RE;
8778          }
8779        }
8780      }
8781    }
8782
8783    if(!$actual_url) {
8784      for my $iframe($browser->content =~ /<iframe[^>]+src=["']?([^"'>]+)/gi) {
8785        $iframe = URI->new_abs($iframe, $browser->uri);
8786        debug "Found iframe: $iframe";
8787        my $sub_browser = $browser->clone;
8788        $sub_browser->get($iframe);
8789        my($package, $possible_url) = FlashVideo::URLFinder->find_package($iframe, $sub_browser);
8790
8791        if($package->can("pre_find")) {
8792          $package->pre_find($sub_browser);
8793        }
8794
8795        info "Downloading $iframe";
8796        $sub_browser->get($iframe);
8797
8798        my($actual_url, @suggested_fnames) = eval {
8799          $package->find_video($sub_browser, $possible_url, $prefs);
8800        };
8801        return $actual_url, @suggested_fnames if $actual_url;
8802      }
8803    }
8804  }
8805
8806  my @filenames;
8807
8808  return $actual_url, $possible_filename if $filename_is_reliable;
8809
8810  $possible_filename =~ s/\?.*//;
8811  push @filenames, $possible_filename if $possible_filename
8812    && $possible_filename !~ /^[0-9_.]+@{[EXTENSIONS]}$/;
8813
8814  my $ext = substr(($actual_url =~ /(@{[EXTENSIONS]})$/)[0], 1);
8815  push @filenames, title_to_filename($title, $ext) if
8816    $title && $title !~ /\Q$possible_filename\E/i;
8817
8818  push @filenames, get_video_filename() if !@filenames;
8819
8820  return $actual_url, @filenames if $actual_url;
8821
8822
8823  my %swf_urls;
8824
8825  if (eval { require URI::Find }) {
8826    my $finder = URI::Find->new(
8827      sub { $swf_urls{$_[1]}++ if $_[1] =~ /\.swf$/i }
8828    );
8829    $finder->find(\$browser->content);
8830  }
8831  else {
8832    my $content = $browser->content;
8833    while($content =~ m{(http://[^ "']+?\.swf)}ig) {
8834      $swf_urls{$1}++;
8835    }
8836  }
8837
8838  if (%swf_urls) {
8839    foreach my $swf_url (keys %swf_urls) {
8840      if (my ($flv_url, $title) = search_for_flv_in_swf($browser, $swf_url)) {
8841        return $flv_url, title_to_filename($title);
8842      }
8843    }
8844  }
8845
8846  die "No URLs found";
8847}
8848
8849sub search_for_flv_in_swf {
8850  my ($browser, $swf_url) = @_;
8851
8852  $browser = $browser->clone();
8853
8854  $browser->get($swf_url);
8855
8856  if (!$browser->success) {
8857    die "Couldn't download SWF URL $swf_url: " .
8858      $browser->response->status_line();
8859  }
8860
8861  my $swf_data = $browser->content;
8862
8863  if ('C' eq substr $swf_data, 0, 1) {
8864    if (eval { require Compress::Zlib }) {
8865      $swf_data = Compress::Zlib::uncompress(substr $swf_data, 8);
8866    }
8867    else {
8868      die "Compress::Zlib is required to uncompress compressed SWF files.\n";
8869    }
8870  }
8871
8872  if ($swf_data =~ m{(http://.{10,300}?\.flv)}i) {
8873    my $flv_url = $1;
8874
8875    my $filename = uri_unescape(File::Basename::basename(URI->new($flv_url)->path()));
8876    $filename =~ s/\.flv$//i;
8877
8878    return ($flv_url, $filename);
8879  }
8880
8881  return;
8882}
8883
8884sub find_file_param {
8885  my($browser, $param, $prefs) = @_;
8886
8887  for my $file($param =~ /(?:video|movie|file|path)_?(?:href|src|url)?['"]?\s*[=:,]\s*['"]?([^&'" ]+)/gi,
8888      $param =~ /(?:config|playlist|options)['"]?\s*[,:=]\s*['"]?(http[^'"&]+)/gi,
8889      $param =~ /['"=](.*?@{[EXTENSIONS]})/gi,
8890      $param =~ /([^ ]+@{[EXTENSIONS]})/gi,
8891      $param =~ /SWFObject\(["']([^"']+)/) {
8892
8893    debug "Found $file";
8894
8895    my ($actual_url, $filename, $filename_is_reliable) = guess_file($browser, $file, '', $prefs);
8896
8897    if(!$actual_url && $file =~ /\?(.*)/) {
8898      debug "Trying query param on $1";
8899
8900      for my $query_param(split /[;&]/, $1) {
8901        my($query_key, $query_value) = split /=/, $query_param;
8902        debug "Found $query_value from $query_key";
8903
8904        ($actual_url, $filename, $filename_is_reliable)
8905          = guess_file($browser, $query_value, '', $prefs);
8906
8907        last if $actual_url;
8908      }
8909    }
8910
8911    if($actual_url) {
8912      my $possible_filename = $filename || (split /\//, $actual_url)[-1];
8913
8914      return $actual_url, $possible_filename, $filename_is_reliable;
8915    }
8916  }
8917
8918  if($param =~ m{(rtmp://[^ &"']+)}) {
8919    info "This looks like RTMP ($1), no generic support yet..";
8920  }
8921
8922  return;
8923}
8924
8925sub guess_file {
8926  my($browser, $file, $once, $prefs) = @_;
8927
8928  $file = uri_unescape($file) if scalar(() = $file =~ /%[A-F0-9]{2}/gi) > 3;
8929
8930  my $orig_uri = URI->new_abs($file, $browser->uri);
8931
8932  info "Guessed $orig_uri trying...";
8933
8934  if($orig_uri) {
8935    my $uri = url_exists($browser->clone, $orig_uri);
8936
8937    if($uri) {
8938      my ($package, $url) = FlashVideo::URLFinder->find_package($uri,
8939        $browser->clone);
8940
8941      if($package && $package ne __PACKAGE__) {
8942        debug "$uri is supported by $package.";
8943        (my $browser_on_supported_site = $browser->clone())->get($uri);
8944        return $package->find_video($browser_on_supported_site, $uri, $prefs), 1;
8945      }
8946
8947      my $content_type = $browser->response->header("Content-type");
8948
8949      if($content_type =~ m!^(text|application/xml)!) {
8950        $browser->add_header("Range", "bytes=0-10000");
8951        $browser->get($uri);
8952        $browser->delete_header("Range");
8953
8954        if(FlashVideo::Downloader->check_magic($browser->content)
8955            || $uri =~ m!$video_re!) {
8956          debug "Found a video at $uri";
8957          return $uri;
8958        }
8959
8960        return if $browser->content =~ /<html[^>]*>/i;
8961
8962        if($browser->content =~ m!($video_re)!) {
8963          return $1;
8964        } elsif(!defined $once
8965            && $browser->content =~ m!(http[-:/a-zA-Z0-9%_.?=&]+)!i) {
8966          return guess_file($browser, $1, 1, $prefs);
8967        } else {
8968          info "Tried $uri, but no video URL found";
8969        }
8970      } elsif($content_type =~ m!application/! && $uri ne $orig_uri) {
8971        return((find_file_param($browser, $uri))[0]);
8972      } else {
8973        return $uri->as_string;
8974      }
8975    } elsif(not defined $once) {
8976      if($browser->content =~ /["']([^ ]+\.swf)/) {
8977        my $swf_uri = URI->new_abs($1, $browser->uri);
8978        if($swf_uri) {
8979          my $new_uri = URI->new_abs($file, $swf_uri);
8980          debug "Found SWF: $swf_uri -> $new_uri";
8981          if($new_uri ne $uri) {
8982            return guess_file($browser, $new_uri, 1, $prefs);
8983          }
8984        }
8985      }
8986    }
8987  }
8988
8989  return;
8990}
8991
89921;
8993}
8994##} blib/lib/FlashVideo/Generic.pm
8995##{ blib/lib/FlashVideo/URLFinder.pm
8996{
8997package FlashVideo::URLFinder;
8998
8999use strict;
9000BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl)
9001BEGIN { FlashVideo::Generic->import(); } # (added by utils/combine-perl.pl)
9002BEGIN { FlashVideo::Site->import(); } # (added by utils/combine-perl.pl)
9003BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
9004BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; }
9005use URI;
9006
9007
9008my @extra_can_handle = qw(Brightcove Mtvnservices Gawker Ooyala Gorillavid);
9009
9010sub find_package {
9011  my($class, $url, $browser) = @_;
9012  my $package = _find_package_url($url, $browser);
9013
9014  if(!defined $package) {
9015
9016    for my $possible_url($browser->content =~
9017        m!(?:<object[^>]+>.*?|<(?:script|embed|iframe|param) [^>]*(?:src=["']?|name=["']src["']\ value=["']))(http://[^"'> ]+)!gixs) {
9018      $package = _find_package_url($possible_url, $browser);
9019
9020      return _found($package, $possible_url) if defined $package;
9021    }
9022  }
9023
9024  if(!defined $package) {
9025    for(@extra_can_handle) {
9026      my $possible_package = _load($_);
9027
9028      $browser->get($url);
9029
9030      my $r = $possible_package->can_handle($browser, $url);
9031      if($r) {
9032        $package = $possible_package;
9033        last;
9034      }
9035    }
9036  }
9037
9038  if(!defined $package) {
9039    $package = "FlashVideo::Generic";
9040  }
9041
9042  return _found($package, $url);
9043}
9044
9045
9046sub _find_package_url {
9047  my($url, $browser) = @_;
9048  my $package;
9049
9050  foreach my $host_part (split /\./, URI->new($url)->host) {
9051    $host_part = lc $host_part;
9052    $host_part =~ s/[^a-z0-9]//i;
9053
9054    my $possible_package = _load($host_part);
9055
9056    if($possible_package->can("find_video")) {
9057
9058      if($possible_package->can("can_handle")) {
9059        next unless $possible_package->can_handle($browser, $url);
9060      }
9061
9062      $package = $possible_package;
9063      last;
9064    }
9065  }
9066
9067  return $package;
9068}
9069
9070sub _found {
9071  my($package, $url) = @_;
9072  info "Using method '" . lc((split /::/, $package)[-1]) . "' for $url";
9073  return $package, $url;
9074}
9075
9076sub _load {
9077  my($site) = @_;
9078
9079  my $package = "FlashVideo::Site::" . ucfirst lc $site;
9080
9081  if(eval "require $package") {
9082    no strict 'refs';
9083    push @{$package . "::ISA"}, "FlashVideo::Site";
9084  }
9085  return $package;
9086}
9087
90881;
9089}
9090##} blib/lib/FlashVideo/URLFinder.pm
9091BEGIN { $INC{'FlashVideo/RTMPDownloader.pm'}++; }
9092# Part of get-flash-videos. See get_flash_videos for copyright.
9093##{ blib/lib/FlashVideo/RTMPDownloader.pm
9094{
9095package FlashVideo::RTMPDownloader;
9096
9097use strict;
9098BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl)
9099use base 'FlashVideo::Downloader';
9100use IPC::Open3;
9101use Fcntl ();
9102use Symbol qw(gensym);
9103BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
9104BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *swfhash = \&FlashVideo::Utils::swfhash; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; }
9105
9106use constant LATEST_RTMPDUMP => 2.2;
9107
9108sub download {
9109  my ($self, $rtmp_data, $file) = @_;
9110
9111  $self->{printable_filename} = $file;
9112
9113  $file = $rtmp_data->{flv} = $self->get_filename($file);
9114
9115  if (-s $file && !$rtmp_data->{live}) {
9116    info "RTMP output filename '$self->{printable_filename}' already " .
9117                 "exists, asking to resume...";
9118    $rtmp_data->{resume} = '';
9119  }
9120
9121  if(my $socks = FlashVideo::Mechanize->new->get_socks_proxy) {
9122    $rtmp_data->{socks} = $socks;
9123  }
9124
9125  my($r_fh, $w_fh); # So Perl doesn't close them behind our back..
9126
9127  if ($rtmp_data->{live} && $self->action eq 'play') {
9128
9129    pipe($r_fh, $w_fh);
9130
9131    my $pid = fork;
9132    die "Fork failed" unless defined $pid;
9133    if(!$pid) {
9134      fcntl $r_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC();
9135      exec $self->replace_filename($self->player, "/dev/fd/" . fileno $r_fh);
9136      die "Exec failed\n";
9137    }
9138
9139    fcntl $w_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC();
9140    $rtmp_data->{flv} = "/dev/fd/" . fileno $w_fh;
9141
9142    $self->{stream} = undef;
9143  }
9144
9145  my $prog = $self->get_rtmp_program;
9146
9147  if($prog eq 'flvstreamer' && ($rtmp_data->{rtmp} =~ /^rtmpe:/ || $rtmp_data->{swfhash})) {
9148    error "FLVStreamer does not support "
9149      . ($rtmp_data->{swfhash} ? "SWF hashing" : "RTMPE streams")
9150      . ", please install rtmpdump.";
9151    exit 1;
9152  }
9153
9154  if($self->debug) {
9155    $rtmp_data->{verbose} = undef;
9156  }
9157
9158  my($return, @errors) = $self->run($prog, $rtmp_data);
9159
9160  if($return != 0 && "@errors" =~ /failed to connect/i) {
9161    info "Couldn't connect on RTMP port, trying port 443 instead";
9162    $rtmp_data->{port} = 443;
9163    ($return, @errors) = $self->run($prog, $rtmp_data);
9164  }
9165
9166  if($file ne '-' && (-s $file < 100 || !$self->check_file($file))) {
9167    error "Download failed, no valid file downloaded";
9168    unlink $rtmp_data->{flv};
9169    return 0;
9170  }
9171
9172  if($return == 2) {
9173    info "\nDownload incomplete -- try running again to resume.";
9174    return 0;
9175  } elsif($return) {
9176    info "\nDownload failed.";
9177    return 0;
9178  }
9179
9180  return -s $file;
9181}
9182
9183sub get_rtmp_program {
9184  if(is_program_on_path("rtmpdump")) {
9185    return "rtmpdump";
9186  } elsif(is_program_on_path("flvstreamer")) {
9187    return "flvstreamer";
9188  }
9189
9190  return "rtmpdump";
9191}
9192
9193sub get_command {
9194  my($self, $rtmp_data, $debug) = @_;
9195
9196  return map {
9197    my $arg = $_;
9198
9199    (ref $rtmp_data->{$arg} eq 'ARRAY'
9200      ? (map {
9201        ("--$arg" => $debug
9202          ? $self->shell_escape($_)
9203          : $_) } @{$rtmp_data->{$arg}})
9204      : ("--$arg" => (($debug && $rtmp_data->{$arg})
9205        ? $self->shell_escape($rtmp_data->{$arg})
9206        : $rtmp_data->{$arg}) || ()))
9207  } keys %$rtmp_data;
9208}
9209
9210sub run {
9211  my($self, $prog, $rtmp_data) = @_;
9212
9213  debug "Running $prog", join(" ", $self->get_command($rtmp_data, 1));
9214
9215  my($in, $out, $err);
9216  $err = gensym;
9217  my $pid = open3($in, $out, $err, $prog, $self->get_command($rtmp_data));
9218
9219  local $SIG{INT};
9220  if ($^O =~ /mswin/i) {
9221    $SIG{INT} = sub {
9222      kill 'TERM', $pid;
9223      exit;
9224    };
9225  }
9226
9227  my $complete = 0;
9228  my $buf = "";
9229  my @error;
9230
9231  while(sysread($err, $buf, 128, length $buf) > 0) {
9232    $buf =~ s/\015\012/\012/g;
9233
9234    my @parts = split /\015/, $buf;
9235    $buf = "";
9236
9237    for(@parts) {
9238      if(/^((?:DEBUG:|WARNING:|Closing connection|ERROR: No playpath found).*)\n/) {
9239        debug "$prog: $1";
9240      } elsif(/^(ERROR: .*)\012/) {
9241        push @error, $1;
9242        info "$prog: $1";
9243      } elsif(/^([0-9.]+) kB(?:\s+\/ \S+ sec)?(?: \(([0-9.]+)%\))?/i) {
9244        $self->{downloaded} = $1 * 1024;
9245        my $percent = $2;
9246
9247        if($self->{downloaded} && $percent != 0) {
9248          $self->{content_length} = $self->{downloaded} / ($percent / 100);
9249        }
9250
9251        $self->progress;
9252      } elsif(/\012$/) {
9253        for my $l(split /\012/) {
9254          if($l =~ /^[A-F0-9]{,2}(?:\s+[A-F0-9]{2})*\s*$/) {
9255            debug $l;
9256          } elsif($l =~ /Download complete/) {
9257            $complete = 1;
9258          } elsif($l =~ /\s+filesize\s+(\d+)/) {
9259            $self->{content_length} = $1;
9260          } elsif($l =~ /\w/) {
9261            print STDERR "\r" if $self->{downloaded};
9262            info $l;
9263
9264            if($l =~ /^RTMPDump v([0-9.]+)/ && $1 < LATEST_RTMPDUMP) {
9265              error "==== Using the latest version of RTMPDump (version "
9266                . LATEST_RTMPDUMP . ") is recommended. ====";
9267            }
9268          }
9269        }
9270
9271        if(/open3/) {
9272          error "\nMake sure you have 'rtmpdump' or 'flvstreamer' installed and available on your PATH.";
9273          return 0;
9274        }
9275      } else {
9276        $buf = $_;
9277      }
9278    }
9279
9280    if(defined $self->{stream} && $self->{downloaded} > 300_000) {
9281      $self->{stream}->();
9282    }
9283  }
9284
9285  waitpid $pid, 0;
9286  return $? >> 8, @error;
9287}
9288
92891;
9290}
9291##} blib/lib/FlashVideo/RTMPDownloader.pm
9292BEGIN { $INC{'FlashVideo/Search.pm'}++; }
9293# Part of get-flash-videos. See get_flash_videos for copyright.
9294##{ blib/lib/FlashVideo/Search.pm
9295{
9296package FlashVideo::Search;
9297
9298use strict;
9299use Carp;
9300BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
9301BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; }
9302
9303my @sites_with_search = ('4oD', 'GoogleVideoSearch');
9304
9305sub search {
9306  my ($class, $search, $max_per_site, $max_results) = @_;
9307
9308  my @search_sites = map { FlashVideo::URLFinder::_load($_) } @sites_with_search;
9309
9310  if ($search =~ /^(\w+) \w+/) {
9311    my $possible_site = ucfirst lc $1;
9312
9313    debug "Checking to see if '$possible_site' in '$search' is a search-supported site.";
9314
9315    my $possible_package = FlashVideo::URLFinder::_load($possible_site);
9316
9317    if ($possible_package->can("search")) {
9318      debug "Search for '$search' will only search $possible_site.";
9319
9320      $search =~ s/^\w+ //;
9321
9322      return search_site($possible_package, $search, "site", $max_results);
9323    }
9324  }
9325
9326  my @plugins = App::get_flash_videos::get_installed_plugins();
9327
9328  foreach my $plugin (@plugins) {
9329    $plugin =~ s/\.pm$//;
9330
9331    my $plugin_package = FlashVideo::URLFinder::_load($plugin);
9332
9333    if ($plugin_package->can("search")) {
9334      debug "Plugin '$plugin' has a search method.";
9335
9336      unshift @search_sites, $plugin_package;
9337    }
9338    else {
9339      debug "Plugin '$plugin' doesn't have a search method.";
9340    }
9341  }
9342
9343  my @results = map { search_site($_, $search, "all", $max_per_site) } @search_sites;
9344
9345  trim_resultset(\@results, $max_results);
9346
9347  return @results;
9348}
9349
9350sub search_site {
9351  my($search_site, $search, $type, $max) = @_;
9352
9353  debug "Searching '$search_site' for '$search'.";
9354
9355  if (my @site_results = eval { $search_site->search($search, $type) }) {
9356    debug "Found " . @site_results . " results for $search.";
9357
9358    trim_resultset(\@site_results, $max);
9359    return @site_results;
9360  }
9361  elsif($@) {
9362    info "Searching '$search_site' failed with: $@";
9363  }
9364  else {
9365    debug "No results found for '$search'.";
9366  }
9367
9368  return ();
9369}
9370
9371sub trim_resultset {
9372  my ($results, $max) = @_;
9373
9374  croak "Must be supplied a reference to resultset" unless ref($results) eq 'ARRAY';
9375  croak "No max supplied" unless $max;
9376
9377  if (@$results > $max) {
9378    debug "Found " . @$results . " results, trimming to $max.";
9379    splice @$results, $max;
9380  }
9381}
9382
93831;
9384}
9385##} blib/lib/FlashVideo/Search.pm
9386BEGIN { $INC{'FlashVideo/VideoPreferences.pm'}++; }
9387# Part of get-flash-videos. See get_flash_videos for copyright.
9388BEGIN { $INC{'FlashVideo/VideoPreferences/Quality.pm'}++; }
9389# Part of get-flash-videos. See get_flash_videos for copyright.
9390##{ blib/lib/FlashVideo/VideoPreferences/Quality.pm
9391{
9392package FlashVideo::VideoPreferences::Quality;
9393
9394use strict;
9395
9396my %format_map = (
9397  "240p"  => [320,  240,  "low"],
9398  "240w"  => [427,  240,  "low"],
9399  "480p"  => [640,  480,  "medium"],
9400  "480w"  => [854,  480,  "medium"],
9401  "576p"  => [720,  576,  "medium"],
9402  "720p"  => [1280, 720,  "high"],
9403  "1080p" => [1920, 1080, "high"],
9404);
9405
9406sub new {
9407  my($class, $quality) = @_;
9408
9409  return bless \$quality, $class;
9410}
9411
9412sub name {
9413  my($self) = @_;
9414  return $$self;
9415}
9416
9417sub choose {
9418  my($self, @available) = @_;
9419
9420
9421
9422  my $max_preferred_res = $self->quality_to_resolution($self->name);
9423  my $max_preferred_size = $max_preferred_res->[0] * $max_preferred_res->[1];
9424
9425  my @sorted =
9426    sort { $a->[0] <=> $b->[0] }
9427    map { my $r = $_->{resolution}; $r = $r->[0] * $r->[1]; [$r, $_] } @available;
9428
9429  if(my @at_or_under_preferred = grep { $_->[0] <= $max_preferred_size } @sorted) {
9430    return $at_or_under_preferred[-1]->[1];
9431  } else {
9432    return $sorted[0]->[1];
9433  }
9434}
9435
9436sub format_to_resolution {
9437  my($self, $name) = @_;
9438  $name .= "p" if $name !~ /[a-z]$/i;
9439
9440  if(my $resolution = $format_map{lc $name}) {
9441    return $resolution;
9442  } elsif(my $num = ($name =~ /(\d+)/)[0]) {
9443    my $resolution = [($num) x 2];
9444    return [@$resolution, $self->resolution_to_quality($resolution)];
9445  }
9446
9447  die "Unknown format '$name'";
9448}
9449
9450sub quality_to_resolution {
9451  my($self, $quality) = @_;
9452
9453  if($quality =~ /^(\d+)x(\d+)$/) {
9454    my $resolution = [$1, $2];
9455    return [@$resolution, $self->resolution_to_quality($resolution)];
9456
9457  } elsif(my $resolution = eval { $self->format_to_resolution($quality) }) {
9458    return $resolution;
9459
9460  } else {
9461    for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) }
9462        values %format_map) {
9463      if($r->[2] eq lc $quality) {
9464        return $r;
9465      }
9466    }
9467  }
9468
9469  die "Unknown quality '$quality'";
9470}
9471
9472sub resolution_to_quality {
9473  my($self, $resolution) = @_;
9474
9475  my $quality = "high";
9476
9477  for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) }
9478      values %format_map) {
9479    $quality = $r->[2] if $r->[0] >= $resolution->[0];
9480  }
9481
9482  return $quality;
9483}
9484
94851;
9486}
9487##} blib/lib/FlashVideo/VideoPreferences/Quality.pm
9488BEGIN { $INC{'FlashVideo/VideoPreferences/Account.pm'}++; }
9489# Part of get-flash-videos. See get_flash_videos for copyright.
9490##{ blib/lib/FlashVideo/VideoPreferences/Account.pm
9491{
9492package FlashVideo::VideoPreferences::Account;
9493
9494use strict;
9495
9496sub new {
9497  my($class, $site, $prompt) = @_;
9498
9499  require Net::Netrc; # Core since 5.8
9500
9501  my $record = Net::Netrc->lookup($site);
9502  my($user, $pass) = $record ? $record->lpa : ();
9503
9504
9505  if(!$user) {
9506    print $prompt;
9507
9508    print "Username: ";
9509    chomp($user = <STDIN>);
9510  }
9511
9512  if(!$pass) {
9513    print "Ok, need your password";
9514    if(eval { require Term::ReadKey }) {
9515      print ": ";
9516      Term::ReadKey::ReadMode(2);
9517      chomp($pass = <STDIN>);
9518      Term::ReadKey::ReadMode(0);
9519      print "\n";
9520    } else {
9521      print " (will be displayed): ";
9522      chomp($pass = <STDIN>);
9523    }
9524  }
9525
9526  return bless {
9527    username => $user,
9528    password => $pass,
9529  }, $class;
9530}
9531
9532sub username {
9533  my($self) = @_;
9534  return $self->{username};
9535}
9536
9537sub password {
9538  my($self) = @_;
9539  return $self->{password};
9540}
9541
95421;
9543}
9544##} blib/lib/FlashVideo/VideoPreferences/Account.pm
9545##{ blib/lib/FlashVideo/VideoPreferences.pm
9546{
9547package FlashVideo::VideoPreferences;
9548
9549use strict;
9550BEGIN { FlashVideo::VideoPreferences::Quality->import(); } # (added by utils/combine-perl.pl)
9551BEGIN { FlashVideo::VideoPreferences::Account->import(); } # (added by utils/combine-perl.pl)
9552
9553sub new {
9554  my($class, %opt) = @_;
9555
9556  return bless {
9557    quality => $opt{quality} || "high",
9558    subtitles => $opt{subtitles} || 0,
9559  }, $class;
9560}
9561
9562sub quality {
9563  my($self) = @_;
9564
9565  return FlashVideo::VideoPreferences::Quality->new($self->{quality});
9566}
9567
9568sub subtitles {
9569  my($self) = @_;
9570
9571  return $self->{subtitles};
9572}
9573
9574sub account {
9575  my($self, $site, $prompt) = @_;
9576
9577  return FlashVideo::VideoPreferences::Account->new($site, $prompt);
9578}
9579
95801;
9581}
9582##} blib/lib/FlashVideo/VideoPreferences.pm
9583##{ bin/get_flash_videos
9584{
9585package main;
9586$::SCRIPT_NAME = "get_flash_videos";
9587$::INSTALL_TYPE = "cpan-manual";
9588
9589package App::get_flash_videos;
9590use strict;
9591use Encode ();
9592use File::Basename qw(basename);
9593use File::stat;
9594use Getopt::Long;
9595use Text::Wrap;
9596
9597BEGIN {
9598  if(!$::SCRIPT_NAME) {
9599    require Cwd;
9600    require File::Spec;
9601    my($vol, $dir) = (File::Spec->splitpath(Cwd::realpath($0)))[0, 1];
9602    unshift @INC, File::Spec->catpath($vol, File::Spec->catdir($dir, "lib"));
9603  }
9604}
9605
9606BEGIN { FlashVideo::URLFinder->import(); } # (added by utils/combine-perl.pl)
9607BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl)
9608BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl)
9609BEGIN { FlashVideo::RTMPDownloader->import(); } # (added by utils/combine-perl.pl)
9610BEGIN { FlashVideo::Search->import(); } # (added by utils/combine-perl.pl)
9611BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
9612BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; *get_terminal_width = \&FlashVideo::Utils::get_terminal_width; }
9613BEGIN { FlashVideo::VideoPreferences->import(); } # (added by utils/combine-perl.pl)
9614
9615unshift @INC, \&plugin_loader;
9616
9617our $VERSION = "1.25";
9618
9619our %opt;
9620BEGIN {
9621  my $player = "mplayer -really-quiet";
9622  $player = "VLC" if $^O =~ /MSWin/i;
9623  $player = "open" if $^O =~ /darwin/ && !is_program_on_path("mplayer");
9624
9625  if(is_program_on_path("xdg-open") && !is_program_on_path("mplayer")) {
9626    $player = "xdg-open";
9627  } elsif(is_program_on_path("gnome-open") && !is_program_on_path("mplayer")) {
9628    $player = "gnome-open";
9629  } elsif(is_program_on_path("kde-open") && !is_program_on_path("mplayer")) {
9630    $player = "kde-open";
9631  }
9632
9633  %opt = (
9634    yes => 0,
9635    filename => '',
9636    version => 0,
9637    update => 0,
9638    play => 0,
9639    player => $player,
9640    proxy => '',
9641    debug => 0,
9642    quiet => 0,
9643    quality => "high",
9644    subtitles => 0,
9645    info => 0
9646  );
9647}
9648
9649use constant VER_INFO => <<EOF;
9650get_flash_videos version $VERSION (http://code.google.com/p/get-flash-videos/)
9651EOF
9652
9653use constant USAGE => VER_INFO . <<EOF;
9654
9655Usage: $0 [OPTION]... URL...
9656       $0 [OPTION]... search string
9657
9658Downloads videos from the web pages given in URL or searches Google Video
9659Search for 'search string'. If the URL contains characters such as '&' you
9660will need to quote it.
9661
9662Options:
9663     --add-plugin Add a plugin from a URL.
9664  -d --debug      Print extra debugging information.
9665  -f --filename   Filename to save the video as.
9666  -p --play       Start playing the video once enough has been downloaded.
9667     --player     Player to use for the video (default: $opt{player}).
9668     --proxy      Proxy to use, use host:port for SOCKS, or URL for HTTP.
9669     --subtitles  Download subtitles where available.
9670  -q --quiet      Be quiet (only print errors).
9671  -r --quality    Quality to download at (high|medium|low, or site specific).
9672  -u --update     Update to latest version.
9673  -v --version    Print version.
9674  -y --yes        Say yes to any questions (don't prompt for any information).
9675  -i --info       Print out info about video instead of downloading.
9676
9677EOF
9678
9679use constant REQ_INFO => <<EOF;
9680
9681A required Perl module for downloading this video is not installed.
9682EOF
9683
9684use constant FRIENDLY_FAILURE => <<EOF;
9685
9686Couldn't extract Flash movie URL. This site may need specific support adding,
9687or fixing.
9688
9689Please confirm the site is using Flash video and if you have Flash available
9690check that the URL really works(!).
9691
9692Check for updates by running: $0 --update
9693
9694If the latest version does not support this please open a bug (or
9695contribute a patch!) at http://code.google.com/p/get-flash-videos/
9696make sure you include the output with --debug enabled.
9697EOF
9698
9699read_conf();
9700
9701GetOptions(
9702  "yes|y"        => \$opt{yes},
9703  "filename|f=s" => \$opt{filename},
9704  "version|v"    => \$opt{version},
9705  "update|u"     => \$opt{update},
9706  "help|h"       => \$opt{help},
9707  "play|p"       => \$opt{play},
9708  "player=s"     => \$opt{player},
9709  "proxy=s"      => \$opt{proxy},
9710  "debug|d"      => \$opt{debug},
9711  "quiet|q"      => \$opt{quiet},
9712  "add-plugin=s" => \$opt{add_plugin},
9713  "quality|r=s"  => \$opt{quality},
9714  "subtitles"    => \$opt{subtitles},
9715  "info|i"       => \$opt{info},
9716) or die "Try $0 --help for more information.\n";
9717
9718if($opt{version}) {
9719  die VER_INFO;
9720} elsif($opt{update}) {
9721  exit update();
9722} elsif($opt{help}) {
9723  die USAGE;
9724} elsif($opt{add_plugin}) {
9725  exit add_plugin($opt{add_plugin});
9726}
9727
9728if ($opt{debug}) {
9729  if(my @plugins = get_installed_plugins()) {
9730    debug @plugins . " plugin" . (@plugins != 1 && "s") . " installed:";
9731    debug "- $_" for @plugins;
9732  } else {
9733    debug "No plugins installed";
9734  }
9735}
9736
9737if($^O =~ /MSWin/i) {
9738  $opt{filename} = Encode::decode(get_win_codepage(), $opt{filename});
9739  binmode STDERR, ":encoding(" . get_win_codepage() . ")";
9740  binmode STDOUT, ":encoding(" . get_win_codepage() . ")";
9741} else {
9742  $opt{filename} = Encode::decode("utf-8", $opt{filename});
9743  binmode STDERR, '<:encoding(UTF-8)';
9744  binmode STDOUT, '<:encoding(UTF-8)';
9745}
9746
9747my (@urls) = @ARGV;
9748@urls > 0 or die USAGE;
9749
9750my $search;
9751if ( ((@urls == 1) and $urls[0] !~ m'\.') or
9752     ( (@urls > 1) and ! grep /^http:\/\/|^[\w\-]+\.[\w\-]+/, @urls)) {
9753  $search = join ' ', @urls;
9754}
9755
9756my @download_urls;
9757
9758if ($search) {
9759  if (my @results = FlashVideo::Search->search($search, 10, 20)) {
9760    if ($opt{yes} or @results == 1) {
9761      my $message = (@results == 1) ?
9762        "Downloading only match for '$search': '$results[0]->{name}'" :
9763        "Downloading first match for '$search': '$results[0]->{name}'" ;
9764      info $message;
9765
9766      push @download_urls, $results[0]->{url};
9767    }
9768    else {
9769      print "Search for '$search' found these results:\n";
9770
9771      my $columns = get_terminal_width() - 5;
9772      local $Text::Wrap::columns = $columns;
9773
9774      my $count = 1;
9775      for my $result(@results) {
9776        printf "[%2d] %s\n", $count, $result->{name};
9777
9778        if ($result->{description}) {
9779          print wrap("     ", "     ",
9780                     substr($result->{description}, 0, $columns * 2)), "\n";
9781        }
9782
9783        $count++;
9784      }
9785
9786      print "Enter the number(s) or range (e.g. 1-3) of the videos to download " .
9787            "(separate multiple with comma or space): ";
9788      chomp(my $choice = <STDIN>);
9789      $choice ||= 1;
9790
9791      for(split /[ ,]+/, $choice) {
9792        if (/-/) {
9793          my ($lower, $upper) = split /-/, $choice;
9794          if ($upper > $lower and $upper > 0) {
9795            push @download_urls, map { $results[$_]->{url} } $lower - 1 .. $upper - 1;
9796            next;
9797          }
9798          else {
9799            print STDERR "Search range '$_' is invalid.\n";
9800            exit 1;
9801          }
9802        }
9803
9804        $_--;
9805
9806        if (!$results[$_]) {
9807          print STDERR "'$_' is an invalid choice.\n";
9808          exit 1;
9809        }
9810
9811        push @download_urls, $results[$_]->{url};
9812      }
9813    }
9814  }
9815  else {
9816    print STDERR "No results found for '$search'.\n";
9817    exit 1;
9818  }
9819}
9820else {
9821  @download_urls = @urls;
9822}
9823
9824my $download_count = 0;
9825
9826my $prefs = FlashVideo::VideoPreferences->new(%opt);
9827
9828foreach my $url (@download_urls) {
9829  if (download($url, $prefs, @download_urls - $download_count)) {
9830    $download_count++;
9831  }
9832}
9833
9834if($download_count == 0) {
9835  info "Couldn't download any videos.";
9836  exit 1;
9837} elsif($download_count != @download_urls) {
9838  info "Problems downloading some videos.";
9839  exit 2;
9840}
9841
9842exit 0;
9843
9844sub download {
9845  my($url, $prefs, $remaining) = @_;
9846
9847  $url = "http://$url" if $url !~ m!^\w+:!;
9848
9849  my $browser = FlashVideo::Mechanize->new;
9850
9851  my($package, $possible_url) = FlashVideo::URLFinder->find_package($url, $browser);
9852
9853  if($package->can("pre_find")) {
9854    $package->pre_find($browser);
9855  }
9856
9857  info "Downloading $url";
9858  $browser->get($url);
9859
9860  if (!$browser->success and !$browser->response->is_redirect) {
9861    if ($opt{proxy}) {
9862      if ($browser->response->header('Client-Warning') eq 'Internal response') {
9863        info "Couldn't download $url - might not be able to contact " .
9864             "your proxy server ($opt{proxy})";
9865      }
9866    }
9867
9868    error "Couldn't download '$url': " . $browser->response->status_line;
9869  }
9870
9871  my($actual_url, @suggested_fnames) = eval {
9872    $package->find_video($browser, $possible_url, $prefs);
9873  };
9874
9875  if(!$actual_url) {
9876    if($@ =~ /^Must have | requires /) {
9877      my $error = "$@";
9878      $error =~ s/at $0.*//;
9879      print STDERR "$error" . REQ_INFO;
9880      return 0;
9881    } else {
9882      print STDERR "Error: $@" . FRIENDLY_FAILURE;
9883      return 0;
9884    }
9885  }
9886
9887  my $suggested_filename = $suggested_fnames[-1];
9888  if (ref($actual_url) eq 'ARRAY') {
9889      $suggested_filename ||= $actual_url->{flv};
9890  }
9891
9892  if (!$opt{play}) {
9893    if (!$opt{yes} && !$opt{filename} && @suggested_fnames > 1) {
9894      print "There are different suggested filenames, please choose:\n";
9895      my $count;
9896      foreach my $filename (@suggested_fnames) {
9897        $count++;
9898        print "$count - $filename\n";
9899      }
9900
9901      print "\nWhich filename would you like to use?: ";
9902      chomp(my $chosen_fname = <STDIN>);
9903
9904      $suggested_filename = $suggested_fnames[$chosen_fname - 1] ||
9905        $suggested_fnames[-1];
9906    }
9907  }
9908
9909  my $save_as = $opt{filename} || $suggested_filename;
9910
9911  if($opt{info}) {
9912    if(ref($actual_url) eq 'ARRAY') {
9913      for my $data(@$actual_url) {
9914        print "Filename: " . $data->{flv} . "\n";
9915        $_ = $suggested_filename || $data->{flv};
9916        s/_/ /g;
9917        s/\.[^\.]*$//;
9918        print "Title: " . $_ . "\n";
9919        print "Content-Location: " . $data->{rtmp} . "\n";
9920        print "\n";
9921      }
9922    } else {
9923      print "Filename: " . ($save_as || $actual_url->{flv}) . "\n";
9924      $_ = $suggested_filename || $actual_url->{flv};
9925      s/_/ /g;
9926      s/\.[^\.]*$//;
9927      print "Title: " . $_ . "\n";
9928      print "Content-Location: ";
9929      if(ref($actual_url) eq 'HASH') {
9930        print $actual_url->{rtmp} . "\n";
9931      } else {
9932        print $actual_url . "\n";
9933        $browser->head($actual_url);
9934        if($browser->response->header('Content-Length')) {
9935          print "Content-Length: " . $browser->response->header('Content-Length') . "\n";
9936        }
9937      }
9938    }
9939    exit;
9940  }
9941
9942  my $action = $opt{play} ? "play" : "download";
9943
9944  for my $data((ref($actual_url) eq 'ARRAY' ? @$actual_url : $actual_url)) {
9945    my $downloader;
9946    my $file = $save_as;
9947
9948    if(ref $data eq 'HASH') {
9949      $downloader = FlashVideo::RTMPDownloader->new;
9950      $file ||= $data->{flv};
9951    } else {
9952      $downloader = FlashVideo::Downloader->new;
9953    }
9954
9955    if (ref $data eq 'ARRAY') {
9956      my ($url, $part_number, $part_count, $part_size) = @$data;
9957      $data = $url;
9958      if (defined $part_number && defined $part_count) {
9959        my $part_suffix = sprintf('.part%02d_of_%02d', $part_number, $part_count);
9960        substr $file, rindex($file, '.'), 0, $part_suffix
9961          if $part_count > 1;
9962      }
9963
9964      if (defined $part_size && -f $file && -s $file == $part_size) {
9965        info "Already downloaded $file ($part_size bytes)";
9966        next;
9967      }
9968    }
9969
9970    my $size = $downloader->$action($data, $file, $browser) || return 0;
9971
9972    info "\n" . ($remaining == 1 ? "Done. " : "")
9973      . "Saved $size bytes to $downloader->{printable_filename}";
9974  }
9975
9976  return 1;
9977}
9978
9979sub read_conf {
9980  for my $file("/etc/get_flash_videosrc", "$ENV{HOME}/.get_flash_videosrc") {
9981    open my $fh, "<", $file or next;
9982
9983    while(<$fh>) {
9984      s/\r?\n//;
9985      next if /^\s*(#|$)/;
9986
9987      my($n, $v) = split /\s*=\s*/;
9988      $v = 1 unless defined $v;
9989      $opt{$n} = $v;
9990    }
9991  }
9992}
9993
9994sub add_plugin {
9995  my($plugin_url) = @_;
9996
9997  my $uri = URI->new($plugin_url);
9998
9999  unless(-d get_plugin_dir()) {
10000    require File::Path;
10001    File::Path::mkpath(get_plugin_dir())
10002      or die "Unable to create plugin dir: $!";
10003  }
10004
10005  my $filename = get_plugin_dir() . "/" . basename($uri->path);
10006
10007  if($filename !~ /\.pm$/) {
10008    die "Plugins must have a file extension of '.pm'\n";
10009  }
10010
10011  if(!$uri->scheme) {
10012    require File::Copy;
10013    File::Copy::copy($plugin_url => $filename)
10014      || die "Unable to copy plugin to '$filename': $!\n";
10015
10016    info "Plugin installed.";
10017    return 0;
10018  } else {
10019    my $browser = FlashVideo::Mechanize->new;
10020    return !install_plugin($browser, $plugin_url, $filename);
10021  }
10022}
10023
10024sub update {
10025  my %update_types = (
10026    'cpan-cpan' => [1, "cpan " . __PACKAGE__],
10027    'cpan-cpanp' => [1, "cpanp i " . __PACKAGE__],
10028    'cpan-cpanm' => [1, "cpanm " . __PACKAGE__],
10029    'cpan-manual' => [0, "Manual install"],
10030  );
10031
10032  if($::SCRIPT_NAME) {
10033    my $browser = FlashVideo::Mechanize->new;
10034
10035    $browser->get("http://get-flash-videos.googlecode.com/svn/wiki/Version.wiki");
10036
10037    if(!$browser->response->is_success) {
10038      die "Unable to retrieve version data: " . $browser->response->status_line . "\n";
10039    }
10040
10041    my $version = ($browser->content =~ /version: (\S+)/)[0];
10042    my $base = ($browser->content =~ /from: (\S+)/)[0];
10043    my $info = ($browser->content =~ /info: (\S+)/)[0];
10044    my $url = $base . $::SCRIPT_NAME . "-" . $version;
10045
10046    die "Unable to parse version data" unless $version and $base;
10047
10048    my @v = split /\./, $version;
10049    my @V = split /\./, $VERSION;
10050
10051    my $newer = 0;
10052    my $i = 0;
10053    for(@v) {
10054      $newer = 1 if !defined $V[$i] || $_ > $V[$i];
10055      last if $V[$i] > $v[$i];
10056      $i++;
10057    }
10058
10059    if($newer) {
10060      info "Newer version ($version) available";
10061      debug "(Install type: $::INSTALL_TYPE)";
10062
10063      if($::INSTALL_TYPE =~ /^cpan-/) {
10064
10065        my $update_method = $update_types{$::INSTALL_TYPE};
10066        if($update_method->[0]) {
10067          info "This was installed via CPAN, you may upgrade by running:";
10068          info $update_method->[1];
10069
10070          my $run_cpan = $opt{yes} || do {
10071            info "Shall I run that for you? (Y/n)";
10072            <STDIN> =~ /(?:^\s*$|y)/i;
10073          };
10074
10075          if($run_cpan) {
10076            system $update_method->[1];
10077          }
10078        } else {
10079          info "Please visit http://code.google.com/p/get-flash-videos to upgrade";
10080        }
10081      } else {
10082        update_script($browser, $url, $info);
10083      }
10084    } else {
10085      print STDERR "You already have the latest version.\n";
10086    }
10087  } else {
10088    info "Development version, not updated";
10089  }
10090
10091  update_plugins();
10092
10093  return 0; # exit code
10094}
10095
10096sub update_script {
10097  my($browser, $url, $info) = @_;
10098
10099  info "Downloading new version...";
10100  die "Cannot update -- unable to write to $0\n" unless -w $0;
10101
10102  my $new_file = $0 . ".new";
10103  $browser->mirror($url, $new_file);
10104
10105  if($browser->response->is_success && -f $new_file) {
10106    rename $0, "$0.old" or die "Unable to rename $0 to $0.old: $!";
10107    rename $new_file, $0 or die "Unable to rename $new_file to $0: $!";
10108    chmod 0755, $0;
10109
10110    info "New version installed as $0";
10111    info "(previous version backed up to $0.old).";
10112    info $info;
10113  } else {
10114    die "Download failed: " . $browser->response->status_line;
10115  }
10116}
10117
10118sub update_plugins {
10119  my $browser = FlashVideo::Mechanize->new;
10120
10121  foreach my $plugin(get_installed_plugins()) {
10122    debug "Seeing if there is an update for $plugin..";
10123
10124    my $file = get_plugin_dir() . "/$plugin";
10125    require $file;
10126
10127    my $package = "FlashVideo::Site::" . ($plugin =~ /(.*)\.pm$/)[0];
10128
10129    if($package->can("update")) {
10130      $package->update();
10131    } else {
10132      no strict 'refs';
10133
10134      my $downloaded  = 0;
10135      my $newer_found = 0;
10136
10137      foreach my $update_url (@{ "$package\::update_urls" }) {
10138        $browser->head($update_url);
10139
10140        if (!$browser->response->is_success) {
10141          debug "Couldn't retrieve $update_url for $plugin: " . $browser->response->status_line;
10142          next;
10143        }
10144
10145        my $file_mtime = stat($file)->mtime;
10146
10147        my $remote_plugin_mtime = $browser->response->last_modified;
10148
10149        if ($remote_plugin_mtime > $file_mtime) {
10150          info "Newer version of plugin $plugin found at $update_url, trying to download and install";
10151          $newer_found = 1;
10152
10153          if ($downloaded = install_plugin($browser, $update_url, $file)) {
10154            last;
10155          }
10156        }
10157        else {
10158          debug "Plugin $plugin is already the lastest version.";
10159          debug "(Remote: " . $browser->response->header("Last-Modified")
10160            . "; Local: " . gmtime($file_mtime) . " GMT)";
10161        }
10162      }
10163
10164      if ($newer_found and !$downloaded) {
10165        die "Couldn't install $plugin plugin";
10166      }
10167    }
10168  }
10169}
10170
10171sub install_plugin {
10172  my ($browser, $url, $file) = @_;
10173
10174  my $plugin_exists = -f $file;
10175
10176  my $new_file = $plugin_exists ? "$file.new" : $file;
10177
10178  $browser->mirror($url, $new_file);
10179
10180  if ($browser->response->is_success && -f $new_file) {
10181    my $short_name = basename($file);
10182
10183    if ($plugin_exists) {
10184      rename $file, "$file.old" or die "Unable to rename $file to $file.old: $!";
10185      rename $new_file, $file   or die "Unable to rename $new_file to $file: $!";
10186
10187      info "New version of $short_name installed as $file";
10188      info "(previous version backed up to $file.old).";
10189    }
10190    else {
10191      info "New plugin $short_name installed as $file";
10192    }
10193
10194    return 1;
10195  }
10196  else {
10197    warn "Download failed: " . $browser->response->status_line;
10198  }
10199
10200  return 0;
10201}
10202
10203sub plugin_loader {
10204  my (undef, $module) = @_;
10205
10206  if ($module =~ m'^FlashVideo/Site/(.*)') {
10207    my $plugin_name = $1;
10208
10209    my $plugin_dir = get_plugin_dir();
10210
10211    debug "Trying to open plugin $plugin_dir/$plugin_name";
10212
10213    if (open my $plugin_fh, '<', "$plugin_dir/$plugin_name") {
10214      return $plugin_fh; # Perl then reads the plugin from the FH
10215    }
10216  }
10217
10218  return;
10219}
10220
10221sub get_installed_plugins {
10222  my $plugin_dir = get_plugin_dir();
10223
10224  my @plugins;
10225  if (opendir my $plugin_dir_dh, $plugin_dir) {
10226    @plugins = grep /\.pm$/i,
10227               readdir $plugin_dir_dh;
10228    closedir $plugin_dir_dh;
10229  }
10230
10231  return @plugins;
10232}
10233
10234sub get_plugin_dir {
10235  return get_user_config_dir() . "/plugins";
10236}
10237}
10238##} bin/get_flash_videos
10239