get-flash-videos-1.25~git2012.06.27/0000755000175000017500000000000011772754142015552 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/utils/0000755000175000017500000000000011772753754016722 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/utils/combine-header0000644000175000017500000000151711772753754021513 0ustar junixjunix#!/usr/bin/env perl # # get_flash_videos -- download all the Flash videos off a web page # # http://code.google.com/p/get-flash-videos/ # # Copyright 2009, zakflash and MonsieurVideo # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain a # copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # Contributions are welcome and encouraged, but please take care to # maintain the JustWorks(tm) nature of the program. get-flash-videos-1.25~git2012.06.27/utils/combine-perl.pl0000755000175000017500000000777411772753754021655 0ustar junixjunix#!/usr/bin/env perl # Combine a perl program and modules it needs into one file use strict; use warnings; use Getopt::Long; use Module::CoreList; use UNIVERSAL::require; use constant TARGETED_MIN => 5.008; # Include a warning in files we output, so it is obvious they are not the # original source. use constant COMBINED_WARNING => < \$include, "exclude|e=s" => \$exclude, "name|n=s" => \$name); my %done; for my $file(@ARGV) { print process_file($file, 1); } sub process_file { my($file, $main) = @_; my $start = 1; my $pre = ""; my $output = ""; $output .= "##{ $file\n{\n"; if(defined $main && $main) { $output .= "package main;\n"; if($name) { $output .= "\$::SCRIPT_NAME = '$name';\n"; $name = ""; } } open my $fh, "<", $file or die $!; while(<$fh>) { if(/^(?:require|\s*use) ([^ ;(]+)/) { my $module = $1; my $base = ""; if($module eq 'base') { $base = $_; /use\s+base\s+([^;]+)/ && ($module = eval $1); $_ = "use $module;"; } # Pass version dependencies through $output .= $_, next unless $module =~ /^[A-Z]/i; if(has_module($module) || $module =~ $exclude || $module !~ $include) { $output .= $_; } else { if(/^\s*use [^ ;(]+((?: |\()[^;]*)?;/) { my $params = defined $1 ? $1 : ""; if($params !~ /^\s*\(\s*\)\s*$/) { my @items = eval $params; $output .= "BEGIN { $module->import($params); } # (added by $0)\n"; if(!@items) { no strict 'refs'; $module->require; @items = @{$module . "::EXPORT"}; } if(@items) { $output .= "BEGIN { no strict 'refs'; "; @items = filter_imports($file, @items); for my $item(@items) { next if $item =~ /^\d/; next if $item =~ /^RC_/; $output .= "*$item = \\&${module}::${item}; "; } $output .= "}\n"; } } } elsif(!/^\s*require /) { die "Unable to handle use for: $module ($file:$.)\n"; } unless($done{$module}++) { my $module_file = module_to_file($module, "$file:$."); my $module_path = module_to_path($module); $pre .= "BEGIN { \$INC{'$module_path'}++; }\n"; $pre .= process_file($module_file); } } if($base) { $output .= $base; } } elsif(/^=(?!cut)\w+/) { while(<$fh>) { last if /^=cut/; } } elsif(/^__END__$/) { last; } elsif(/^__DATA__$/) { die "Data sections not supported ($file:$.)\n"; } elsif($start && /^\s*(#|$)/) { $pre .= COMBINED_WARNING if $. == 2; $pre .= $_; } elsif(!/^\s*#/) { $start = 0; $output .= $_; } } $output .= "}\n##} $file\n"; return $pre . $output; } sub has_module { my($module) = @_; my $first = Module::CoreList->first_release($module); return defined $first && $first <= TARGETED_MIN; } sub module_to_file { my($module, $from) = @_; my $file = module_to_path($module); for my $dir(@INC) { return "$dir/$file" if -f "$dir/$file"; } die "Unable to find '$module' in \@INC (from $from)\n"; } sub module_to_path { my($file) = @_; $file =~ s/::/\//g; $file .= ".pm"; return $file; } sub filter_imports { my($file, @imports) = @_; open my $fh, "<", $file or die $!; my $text = join "", <$fh>; return grep { $text =~ /\Q$_\E/ } @imports; } get-flash-videos-1.25~git2012.06.27/utils/combine-head0000644000175000017500000000070411772753754021161 0ustar junixjunix#!/usr/bin/env perl # # get_flash_videos -- download all the Flash videos off a web page # # http://code.google.com/p/get-flash-videos/ # # Copyright 2009, zakflash and MonsieurVideo # # This file includes various perl modules, see their original source for their # copyright and license terms. use HTTP::Cookies (); use HTTP::Config (); use HTTP::Request::Common (); use LWP::Protocol::http (); use XML::Simple (); use WWW::Mechanize::Link (); 1; get-flash-videos-1.25~git2012.06.27/utils/uncompress-flash.pl0000755000175000017500000000067311772753754022561 0ustar junixjunix#!/usr/bin/env perl # http://board.flashkit.com/board/archive/index.php/t-283660.html use strict; use Compress::Zlib; my $file = shift; -f $file or die "Usage: $0 file > output\n"; open my $fh, "<", $file or die $!; binmode $fh; my $body; read $fh, $body, -s $file; die "Doesn't look like compressed flash to me..\n" unless 'C' eq substr $body, 0, 1; substr($body, 0, 1) = "F"; print substr $body, 0, 8; print uncompress(substr $body, 8); get-flash-videos-1.25~git2012.06.27/utils/autoplay.sh0000755000175000017500000000072311772753754021121 0ustar junixjunix#!/bin/bash last="" cd /tmp play() { get_flash_videos -y -p --player "mplayer -really-quiet %s 2>/dev/null; rm %s" "$1" } while sleep 1; do clip="$(xclip -o)" # If changed if [ "${clip}x" != "${last}x" ]; then # Must be a http URL if [ "${clip/http:}" != "${clip}" ]; then # Looks like it might be a video.. if [ "${clip/{watch,flv,show,video}}" != "${clip}" ]; then play "${clip}" fi fi last="${clip}" fi done get-flash-videos-1.25~git2012.06.27/lib/0000755000175000017500000000000011772753754016330 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/lib/FlashVideo/0000755000175000017500000000000011772753754020354 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Generic.pm0000644000175000017500000002200511772753754022265 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Generic; use strict; use FlashVideo::Utils; use URI; use FlashVideo::URLFinder; use URI::Escape qw(uri_unescape); my $video_re = qr!http[-:/a-z0-9%_.?=&]+@{[EXTENSIONS]} # Grab any params that might be used for auth.. (?:\?[-:/a-z0-9%_.?=&]+)?!xi; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; # First strategy - identify all the Flash video files, and download the # biggest one. Yes, this is hacky. if (!$browser->success) { $browser->get($browser->response->header('Location')); die "Couldn't download URL: " . $browser->response->status_line unless $browser->success; } my ($possible_filename, $actual_url, $title); $title = extract_title($browser); my @flv_urls = map { (m{http://.+?(http://.+?@{[EXTENSIONS]})}i) ? $1 : $_ } ($browser->content =~ m{($video_re)}gi); if (@flv_urls) { require LWP::Simple; require Memoize; Memoize::memoize("LWP::Simple::head"); @flv_urls = sort { (LWP::Simple::head($a))[1] <=> (LWP::Simple::head($b))[1] } @flv_urls; $possible_filename = (split /\//, $flv_urls[-1])[-1]; # Un-escape URLs if necessary if ($flv_urls[-1] =~ /^http%3a%2f%2f/) { $flv_urls[-1] = uri_unescape($flv_urls[-1]) } $actual_url = url_exists($browser->clone, $flv_urls[-1]); } my $filename_is_reliable; if(!$actual_url) { RE: for my $regex( qr{(?si)]+)}, qr{(?si)]+)}, qr{(?si)]* href=["']?([^"'>]+?@{[EXTENSIONS]})}, qr{(?si)]*>.*?]*value=["']?([^"'>]+)}, qr{(?si)]*>(.*?)}, # Attempt to handle scripts using flashvars / swfobject qr{(?si)]*>(.*?)}) { for my $param($browser->content =~ /$regex/gi) { (my $url, $possible_filename, $filename_is_reliable) = find_file_param($browser->clone, $param, $prefs); if($url) { my $resolved_url = url_exists($browser->clone, $url); if($resolved_url) { $actual_url = $resolved_url; last RE; } } } } if(!$actual_url) { for my $iframe($browser->content =~ /]+src=["']?([^"'>]+)/gi) { $iframe = URI->new_abs($iframe, $browser->uri); debug "Found iframe: $iframe"; my $sub_browser = $browser->clone; $sub_browser->get($iframe); # Recurse! my($package, $possible_url) = FlashVideo::URLFinder->find_package($iframe, $sub_browser); # Before fetching the url, give the package a chance if($package->can("pre_find")) { $package->pre_find($sub_browser); } info "Downloading $iframe"; $sub_browser->get($iframe); my($actual_url, @suggested_fnames) = eval { $package->find_video($sub_browser, $possible_url, $prefs); }; return $actual_url, @suggested_fnames if $actual_url; } } } my @filenames; return $actual_url, $possible_filename if $filename_is_reliable; $possible_filename =~ s/\?.*//; # The actual filename, provided it looks like it might be reasonable # (not just numbers).. push @filenames, $possible_filename if $possible_filename && $possible_filename !~ /^[0-9_.]+@{[EXTENSIONS]}$/; # The title of the page, if it isn't similar to the filename.. my $ext = substr(($actual_url =~ /(@{[EXTENSIONS]})$/)[0], 1); push @filenames, title_to_filename($title, $ext) if $title && $title !~ /\Q$possible_filename\E/i; # A title with just the timestamp in it.. push @filenames, get_video_filename() if !@filenames; return $actual_url, @filenames if $actual_url; # As a last ditch attempt, download the SWF file as in some cases, sites # use an SWF movie file for each FLV. # Get SWF URL(s) my %swf_urls; if (eval { require URI::Find }) { my $finder = URI::Find->new( sub { $swf_urls{$_[1]}++ if $_[1] =~ /\.swf$/i } ); $finder->find(\$browser->content); } else { # Extract URLs in a frail way. my $content = $browser->content; while($content =~ m{(http://[^ "']+?\.swf)}ig) { $swf_urls{$1}++; } } if (%swf_urls) { foreach my $swf_url (keys %swf_urls) { if (my ($flv_url, $title) = search_for_flv_in_swf($browser, $swf_url)) { return $flv_url, title_to_filename($title); } } } die "No URLs found"; } sub search_for_flv_in_swf { my ($browser, $swf_url) = @_; $browser = $browser->clone(); $browser->get($swf_url); if (!$browser->success) { die "Couldn't download SWF URL $swf_url: " . $browser->response->status_line(); } # SWF data might be compressed. my $swf_data = $browser->content; if ('C' eq substr $swf_data, 0, 1) { if (eval { require Compress::Zlib }) { $swf_data = Compress::Zlib::uncompress(substr $swf_data, 8); } else { die "Compress::Zlib is required to uncompress compressed SWF files.\n"; } } if ($swf_data =~ m{(http://.{10,300}?\.flv)}i) { my $flv_url = $1; my $filename = uri_unescape(File::Basename::basename(URI->new($flv_url)->path())); $filename =~ s/\.flv$//i; return ($flv_url, $filename); } return; } sub find_file_param { my($browser, $param, $prefs) = @_; for my $file($param =~ /(?:video|movie|file|path)_?(?:href|src|url)?['"]?\s*[=:,]\s*['"]?([^&'" ]+)/gi, $param =~ /(?:config|playlist|options)['"]?\s*[,:=]\s*['"]?(http[^'"&]+)/gi, $param =~ /['"=](.*?@{[EXTENSIONS]})/gi, $param =~ /([^ ]+@{[EXTENSIONS]})/gi, $param =~ /SWFObject\(["']([^"']+)/) { debug "Found $file"; my ($actual_url, $filename, $filename_is_reliable) = guess_file($browser, $file, '', $prefs); if(!$actual_url && $file =~ /\?(.*)/) { # Maybe we have query params? debug "Trying query param on $1"; for my $query_param(split /[;&]/, $1) { my($query_key, $query_value) = split /=/, $query_param; debug "Found $query_value from $query_key"; ($actual_url, $filename, $filename_is_reliable) = guess_file($browser, $query_value, '', $prefs); last if $actual_url; } } if($actual_url) { my $possible_filename = $filename || (split /\//, $actual_url)[-1]; return $actual_url, $possible_filename, $filename_is_reliable; } } if($param =~ m{(rtmp://[^ &"']+)}) { info "This looks like RTMP ($1), no generic support yet.."; } return; } sub guess_file { my($browser, $file, $once, $prefs) = @_; # Contains lots of URI encoding, so try escaping.. $file = uri_unescape($file) if scalar(() = $file =~ /%[A-F0-9]{2}/gi) > 3; my $orig_uri = URI->new_abs($file, $browser->uri); info "Guessed $orig_uri trying..."; if($orig_uri) { my $uri = url_exists($browser->clone, $orig_uri); if($uri) { # Check to see if this URL is for a supported site. my ($package, $url) = FlashVideo::URLFinder->find_package($uri, $browser->clone); if($package && $package ne __PACKAGE__) { debug "$uri is supported by $package."; (my $browser_on_supported_site = $browser->clone())->get($uri); return $package->find_video($browser_on_supported_site, $uri, $prefs), 1; } my $content_type = $browser->response->header("Content-type"); if($content_type =~ m!^(text|application/xml)!) { # Just in case someone serves the video itself as text/plain. $browser->add_header("Range", "bytes=0-10000"); $browser->get($uri); $browser->delete_header("Range"); if(FlashVideo::Downloader->check_magic($browser->content) || $uri =~ m!$video_re!) { # It's a video.. debug "Found a video at $uri"; return $uri; } # If this looks like HTML we have no hope of guessing right, so # give up now. return if $browser->content =~ /]*>/i; if($browser->content =~ m!($video_re)!) { # Found a video URL return $1; } elsif(!defined $once && $browser->content =~ m!(http[-:/a-zA-Z0-9%_.?=&]+)!i) { # Try once more, one level deeper.. return guess_file($browser, $1, 1, $prefs); } else { info "Tried $uri, but no video URL found"; } } elsif($content_type =~ m!application/! && $uri ne $orig_uri) { # We were redirected, maybe something in the new URL? return((find_file_param($browser, $uri))[0]); } else { return $uri->as_string; } } elsif(not defined $once) { # Try using the location of the .swf file as the base, if it's different. if($browser->content =~ /["']([^ ]+\.swf)/) { my $swf_uri = URI->new_abs($1, $browser->uri); if($swf_uri) { my $new_uri = URI->new_abs($file, $swf_uri); debug "Found SWF: $swf_uri -> $new_uri"; if($new_uri ne $uri) { return guess_file($browser, $new_uri, 1, $prefs); } } } } } return; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site.pm0000644000175000017500000000102511772753754021614 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site; use strict; # Various accessors to avoid plugins needing to know about the exact command # line options. This will improve at some point (i.e. more OO) sub debug { $App::get_flash_videos::opt{debug}; } sub action { $App::get_flash_videos::opt{play} ? "play" : "download"; } sub player { $App::get_flash_videos::opt{player}; } sub yes { $App::get_flash_videos::opt{yes}; } sub quiet { $App::get_flash_videos::opt{quiet}; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/VideoPreferences/0000755000175000017500000000000011772753754023604 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/lib/FlashVideo/VideoPreferences/Quality.pm0000644000175000017500000000554311772753754025601 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::VideoPreferences::Quality; use strict; my %format_map = ( "240p" => [320, 240, "low"], "240w" => [427, 240, "low"], "480p" => [640, 480, "medium"], "480w" => [854, 480, "medium"], "576p" => [720, 576, "medium"], "720p" => [1280, 720, "high"], "1080p" => [1920, 1080, "high"], ); sub new { my($class, $quality) = @_; return bless \$quality, $class; } sub name { my($self) = @_; return $$self; } sub choose { my($self, @available) = @_; # To make it easier we take the total number of pixels in a resolution, this # may be a bit confusing if someone prefers a widescreen version and we don't # choose it, however they can always specify the precise format in that case. # TODO: If we have a video at a higher res than 1080p we won't choose it, # maybe need to extend high (or add a very-high?). my $max_preferred_res = $self->quality_to_resolution($self->name); my $max_preferred_size = $max_preferred_res->[0] * $max_preferred_res->[1]; my @sorted = sort { $a->[0] <=> $b->[0] } map { my $r = $_->{resolution}; $r = $r->[0] * $r->[1]; [$r, $_] } @available; if(my @at_or_under_preferred = grep { $_->[0] <= $max_preferred_size } @sorted) { # Max under preferred size return $at_or_under_preferred[-1]->[1]; } else { # Min over preferred size return $sorted[0]->[1]; } } sub format_to_resolution { my($self, $name) = @_; $name .= "p" if $name !~ /[a-z]$/i; if(my $resolution = $format_map{lc $name}) { return $resolution; } elsif(my $num = ($name =~ /(\d+)/)[0]) { # Don't know about this, we'll return the number given as the size, in theory the # height should be correct, which means if anything we'll be slightly under # on the resolution. my $resolution = [($num) x 2]; return [@$resolution, $self->resolution_to_quality($resolution)]; } die "Unknown format '$name'"; } sub quality_to_resolution { my($self, $quality) = @_; # Allow specifying an actual resolution if($quality =~ /^(\d+)x(\d+)$/) { my $resolution = [$1, $2]; return [@$resolution, $self->resolution_to_quality($resolution)]; # See if they specified a named format } elsif(my $resolution = eval { $self->format_to_resolution($quality) }) { return $resolution; } else { # Search backwards until we find the name they specified. for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) } values %format_map) { if($r->[2] eq lc $quality) { return $r; } } } die "Unknown quality '$quality'"; } sub resolution_to_quality { my($self, $resolution) = @_; my $quality = "high"; for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) } values %format_map) { $quality = $r->[2] if $r->[0] >= $resolution->[0]; } return $quality; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/VideoPreferences/Account.pm0000644000175000017500000000171711772753754025544 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::VideoPreferences::Account; use strict; sub new { my($class, $site, $prompt) = @_; require Net::Netrc; # Core since 5.8 my $record = Net::Netrc->lookup($site); my($user, $pass) = $record ? $record->lpa : (); # Allow only setting user in .netrc if wanted if(!$user) { print $prompt; print "Username: "; chomp($user = ); } if(!$pass) { print "Ok, need your password"; if(eval { require Term::ReadKey }) { print ": "; Term::ReadKey::ReadMode(2); chomp($pass = ); Term::ReadKey::ReadMode(0); print "\n"; } else { print " (will be displayed): "; chomp($pass = ); } } return bless { username => $user, password => $pass, }, $class; } sub username { my($self) = @_; return $self->{username}; } sub password { my($self) = @_; return $self->{password}; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Search.pm0000644000175000017500000000513011772753754022116 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Search; use strict; use Carp; use FlashVideo::Utils; # Sites which support searching my @sites_with_search = ('4oD', 'GoogleVideoSearch'); sub search { my ($class, $search, $max_per_site, $max_results) = @_; # Preload search sites my @search_sites = map { FlashVideo::URLFinder::_load($_) } @sites_with_search; # If a user searches for "foo something", check to see if "foo" is a site # we support. If it is, only search that site. if ($search =~ /^(\w+) \w+/) { my $possible_site = ucfirst lc $1; debug "Checking to see if '$possible_site' in '$search' is a search-supported site."; my $possible_package = FlashVideo::URLFinder::_load($possible_site); if ($possible_package->can("search")) { # Only search this site debug "Search for '$search' will only search $possible_site."; # Remove the site name from the search string $search =~ s/^\w+ //; return search_site($possible_package, $search, "site", $max_results); } } # Check to see if any plugins have a search function defined. my @plugins = App::get_flash_videos::get_installed_plugins(); foreach my $plugin (@plugins) { $plugin =~ s/\.pm$//; my $plugin_package = FlashVideo::URLFinder::_load($plugin); if ($plugin_package->can("search")) { debug "Plugin '$plugin' has a search method."; unshift @search_sites, $plugin_package; } else { debug "Plugin '$plugin' doesn't have a search method."; } } # Call each site's search method - this includes plugins and sites # defined in @sites_with_search. my @results = map { search_site($_, $search, "all", $max_per_site) } @search_sites; # Return all results, trimming if necessary. trim_resultset(\@results, $max_results); return @results; } sub search_site { my($search_site, $search, $type, $max) = @_; debug "Searching '$search_site' for '$search'."; if (my @site_results = eval { $search_site->search($search, $type) }) { debug "Found " . @site_results . " results for $search."; trim_resultset(\@site_results, $max); return @site_results; } elsif($@) { info "Searching '$search_site' failed with: $@"; } else { debug "No results found for '$search'."; } return (); } sub trim_resultset { my ($results, $max) = @_; croak "Must be supplied a reference to resultset" unless ref($results) eq 'ARRAY'; croak "No max supplied" unless $max; if (@$results > $max) { debug "Found " . @$results . " results, trimming to $max."; splice @$results, $max; } } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Utils.pm0000644000175000017500000003063411772753754022020 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Utils; use strict; no warnings 'uninitialized'; use base 'Exporter'; use HTML::Entities; use HTML::TokeParser; use Encode; use constant FP_KEY => "Genuine Adobe Flash Player 001"; use constant EXTENSIONS => qr/\.(?:flv|mp4|mov|wmv|avi|m4v)/i; use constant MAX_REDIRECTS => 5; our @EXPORT = qw(debug info error extract_title extract_info title_to_filename get_video_filename url_exists swfhash swfhash_data EXTENSIONS get_user_config_dir get_win_codepage is_program_on_path get_terminal_width json_unescape convert_sami_subtitles_to_srt from_xml); sub debug(@) { # Remove some sensitive data my $string = "@_\n"; $string =~ s/\Q$ENV{HOME}\E/~/g; print STDERR $string if $App::get_flash_videos::opt{debug}; } sub info(@) { print STDERR "@_\n" unless $App::get_flash_videos::opt{quiet}; } sub error(@) { print STDERR "@_\n"; } sub extract_title { my($browser) = @_; return extract_info($browser)->{title}; } sub extract_info { my($browser) = @_; my($title, $meta_title); my $p = HTML::TokeParser->new(\$browser->content); while(my $token = $p->get_tag("title", "meta")) { my($tag, $attr) = @$token; if($tag eq 'meta' && $attr->{name} =~ /title/i) { $meta_title = $attr->{content}; } elsif($tag eq 'title') { $title = $p->get_trimmed_text; } } return { title => $title, meta_title => $meta_title, }; } sub swfhash { my($browser, $url) = @_; $browser->get($url); return swfhash_data($browser->content, $url); } sub swfhash_data { my ($data, $url) = @_; die "Must have Compress::Zlib and Digest::SHA for this RTMP download\n" unless eval { require Compress::Zlib; require Digest::SHA; }; $data = "F" . substr($data, 1, 7) . Compress::Zlib::uncompress(substr $data, 8); return swfsize => length $data, swfhash => Digest::SHA::hmac_sha256_hex($data, FP_KEY), swfUrl => $url; } sub url_exists { my($browser, $url) = @_; $browser->head($url); my $response = $browser->response; debug "Exists on $url: " . $response->code; return $url if $response->code == 200; my $redirects = 0; while ( ($response->code =~ /^30\d/) and ($response->header('Location')) and ($redirects < MAX_REDIRECTS) ) { $url = URI->new_abs($response->header('Location'), $url); $response = $browser->head($url); debug "Redirected to $url (" . $response->code . ")"; if ($response->code == 200) { return $url; } $redirects++; } return ''; } sub title_to_filename { my($title, $type) = @_; # no need to go any further if "--filename" option is passed if($App::get_flash_videos::opt{filename} ne '') { return $App::get_flash_videos::opt{filename}; } # Extract the extension if we're passed a URL. if($title =~ s/(@{[EXTENSIONS]})$//) { $type = substr $1, 1; } elsif ($type && $type !~ /^\w+$/) { $type = substr((URI->new($type)->path =~ /(@{[EXTENSIONS]})$/)[0], 1); } $type ||= "flv"; $title = decode_utf8($title); # We want \w below to match non-ASCII characters. utf8::upgrade($title); # Some sites have double-encoded entities, so handle this if ($title =~ /&(?:\w+|#(?:\d+|x[A-F0-9]+));/) { # Double-encoded - decode again $title = decode_entities($title); } $title =~ s/\s+/_/g; $title =~ s/[^\w\-,()&]/_/g; $title =~ s/^_+|_+$//g; # underscores at the start and end look bad $title = encode_utf8($title); # If we have nothing then return a filestamped filename. return get_video_filename($type) unless $title; return "$title.$type"; } sub get_video_filename { my($type) = @_; $type ||= "flv"; return "video" . get_timestamp_in_iso8601_format() . "." . $type; } sub get_timestamp_in_iso8601_format { use Time::localtime; my $time = localtime; return sprintf("%04d%02d%02d%02d%02d%02d", $time->year + 1900, $time->mon + 1, $time->mday, $time->hour, $time->min, $time->sec); } sub get_vlc_exe_from_registry { if ($^O !~ /MSWin/i) { die "Doesn't make sense to call this except on Windows"; } my $HAS_WIN32_REGISTRY = eval { require Win32::Registry }; die "Win32::Registry required for JustWorks(tm) playing on Windows" unless $HAS_WIN32_REGISTRY; require Win32::Registry; # This module, along with Win32::TieRegistry, is horrible and primarily # works by exporting various symbols into the calling package. # Win32::TieRegistry does not offer an easy way of getting the $Registry # object if you require the module rather than use-ing it. Win32::Registry->import(); # Ignoring the fact that polluting your caller's namespace is bad # practice, it's also evil because I now have to disable strict so that # Perl won't complain that $HKEY_LOCAL_MACHINE which is exported into my # package at runtime doesn't exist. my $local_machine; { no strict 'vars'; $local_machine = $::HKEY_LOCAL_MACHINE; } my $key = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'; $local_machine->Open($key, my $reg); # Believe it or not, this is Perl, not C my @applications; $reg->GetKeys(\@applications); my $vlc_binary; foreach my $application (@applications) { next unless $application =~ /VLC Media Player/i; $reg->Open($application, my $details); my %app_properties; $details->GetValues(\%app_properties); # These values are arrayrefs with value name, type and data. data is # what we care about. if ($app_properties{DisplayIcon}->[-1] =~ /\.exe$/i) { # Assume this is the VLC executable $vlc_binary = $app_properties{DisplayIcon}->[-1]; last; } } return $vlc_binary; } sub get_win_codepage { require Win32::API; # Hack for older versions of Win32::API::Type (which Win32::API->import # uses to parse prototypes) to avoid "unknown output parameter type" # warning. Older versions of this module have an INIT block for reading # type information from the DATA filehandle. This doesn't get called when # we require the module rather than use-ing it. More recent versions of # the module don't bother with an INIT block, and instead just have the # initialisation code at package level. if (! %Win32::API::Type::Known) { %Win32::API::Type::Known = (int => 'i'); } Win32::API->Import("kernel32", "int GetACP()"); return "cp" . GetACP(); } # Returns a path to the user's configuration data and/or plugins directory. sub get_user_config_dir { # On Windows, use "Application Data" and "get_flash_videos". On other # platforms, use the user's home directory (specified by the HOME # environment variable) and ".get_flash_videos". Note that on Windows, # the directory has no . prefix as historically, Windows and Windows # applications tend to make dealing with such directories awkward. # Note that older versions of Windows don't set an APPDATA environment # variable. return $^O =~ /MSWin/i ? ($ENV{APPDATA} || 'c:/windows/application data') . "/get_flash_videos" : "$ENV{HOME}/.get_flash_videos"; } # Is the specified program on the system PATH? sub is_program_on_path { my($program) = @_; my $win = $^O =~ /MSWin/i; for my $dir(split($win ? ";" : ":", $ENV{PATH})) { return 1 if -f "$dir/$program" . ($win ? ".exe" : ""); } return 0; } sub get_terminal_width { if(eval { require Term::ReadKey } && (my($width) = Term::ReadKey::GetTerminalSize())) { return $width - 1 if $^O =~ /MSWin|cygwin/i; # seems to be off by 1 on Windows return $width; } elsif($ENV{COLUMNS}) { return $ENV{COLUMNS}; } else { return 80; } } # Maybe should use a proper JSON parser, but want to avoid the dependency for now.. # (There is now one in FlashVideo::JSON, so consider that -- this is just here # until we have a chance to fix things using it). sub json_unescape { my($s) = @_; $s =~ s/\\u([0-9a-f]{1,4})/chr hex $1/ge; $s =~ s{(\\[\\/rnt"])}{"\"$1\""}gee; return $s; } sub convert_sami_subtitles_to_srt { my ($sami_subtitles, $filename, $decrypt_callback) = @_; die "SAMI subtitles must be provided" unless $sami_subtitles; die "Output SRT filename must be provided" unless $filename; # Use regexes to "parse" SAMI since HTML::TokeParser is too awkward. It # makes it hard to preserve linebreaks and other formatting in subtitles. # It's also quite slow. $sami_subtitles =~ s/[\r\n]//g; # flatten my @lines = split /| |g; # replace "&" with "&" s|&|&|g; # replace " " with " " s{&(?:nbsp|#160);}{ }g; # Start="2284698">

I won't have to drink it
in this crappy warehouse.

#($begin, $sub) = ($1, $2) if m{.*Start="(.+?)".+(.+?)<\/p>.*?<\/Sync>}i; ($begin, $sub) = ($1, $2) if m{[^>]*Start="(.+?)"[^>]*>(.*?)<\/Sync>}i; if (/^\s*Encrypted="true"\s*/i) { if ($decrypt_callback and ref($decrypt_callback) eq 'CODE') { $sub = $decrypt_callback->($sub); } } $sub =~ s@&@&@g; $sub =~ s@(?:]*>| | )@ @g; # Do some tidying up. # Note only

tags are removed-- tags are left in place since VLC # and others support this for formatting. $sub =~ s{]*?>}{}g; # remove

and similar # VLC is very sensitive to tag case. $sub =~ s{<(/)?([BI])>}{"<$1" . lc($2) . ">"}eg; decode_entities($sub); # in void context, this works in place if ($sub and ($begin or $begin == 0)) { # Convert milliseconds into HH:MM:ss,mmm format my $seconds = int( $begin / 1000.0 ); my $ms = $begin - ( $seconds * 1000.0 ); $begin = sprintf("%02d:%02d:%02d,%03d", (gmtime($seconds))[2,1,0], $ms ); # Don't strip simple HTML like - VLC and other players # support basic subtitle styling, see: # http://git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/subtitles/subsdec.c # Leading/trailing spaces $sub =~ s/^\s*(.*?)\s*$/$1/; # strip multispaces $sub =~ s/\s{2,}/ /g; # Replace
(and similar) with \n. VLC handles \n in SubRip files # fine. For
it is case and slash sensitive. $sub =~ s|
|\n|ig; $sub =~ s/^\s*|\s*$//mg; if ($count and !$subtitles[$count - 1]->{end}) { $subtitles[$count - 1]->{end} = $begin; } # SAMI subtitles are a bit crap. Only a start time is specified for # each subtitle. No end time is specified, so the subtitle is displayed # until the next subtitle is ready to be shown. This means that if # subtitles aren't meant to be shown for part of the video, a dummy # subtitle (usually just a space) has to be inserted. if (!$sub or $sub =~ /^\s+$/) { if ($count) { $last_proper_sub_end_time = $subtitles[$count - 1]->{end}; } # Gap in subtitles. next; # this is not a meaningful subtitle } push @subtitles, { start => $begin, text => $sub, }; $count++; } } # Ensure the end time for the last subtitle is correct. $subtitles[$count - 1]->{end} = $last_proper_sub_end_time; # Write subtitles open my $subtitle_fh, '>', $filename or die "Can't open subtitles file $filename: $!"; # Set filehandle to UTF-8 to avoid "wide character in print" warnings. # Note this does *not* double-encode data as UTF-8 (verify with hexdump). # As per the documentation for binmode: ":utf8 just marks the data as # UTF-8 without further checking". This will cause mojibake if # ISO-8859-1/Latin1 and UTF-8 and are mixed in the same file though. binmode $subtitle_fh, ':utf8'; $count = 1; foreach my $subtitle (@subtitles) { print $subtitle_fh "$count\n$subtitle->{start} --> $subtitle->{end}\n" . "$subtitle->{text}\n\n"; $count++; } close $subtitle_fh; return 1; } sub from_xml { my($xml, @args) = @_; if(!eval { require XML::Simple && XML::Simple::XMLin("") }) { die "Must have XML::Simple to download " . caller =~ /::([^:])+$/ . " videos\n"; } $xml = eval { XML::Simple::XMLin(ref $xml eq 'SCALAR' ? $xml : ref $xml ? $xml->content : $xml, @args); }; if($@) { die "$@ (from ", join("::", caller), ")\n"; } return $xml; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/VideoPreferences.pm0000644000175000017500000000121011772753754024134 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::VideoPreferences; use strict; use FlashVideo::VideoPreferences::Quality; use FlashVideo::VideoPreferences::Account; sub new { my($class, %opt) = @_; return bless { quality => $opt{quality} || "high", subtitles => $opt{subtitles} || 0, }, $class; } sub quality { my($self) = @_; return FlashVideo::VideoPreferences::Quality->new($self->{quality}); } sub subtitles { my($self) = @_; return $self->{subtitles}; } sub account { my($self, $site, $prompt) = @_; return FlashVideo::VideoPreferences::Account->new($site, $prompt); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/RTMPDownloader.pm0000644000175000017500000001313611772753754023517 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::RTMPDownloader; use strict; use base 'FlashVideo::Downloader'; use IPC::Open3; use Fcntl (); use Symbol qw(gensym); use FlashVideo::Utils; use constant LATEST_RTMPDUMP => 2.2; sub download { my ($self, $rtmp_data, $file) = @_; $self->{printable_filename} = $file; $file = $rtmp_data->{flv} = $self->get_filename($file); if (-s $file && !$rtmp_data->{live}) { info "RTMP output filename '$self->{printable_filename}' already " . "exists, asking to resume..."; $rtmp_data->{resume} = ''; } if(my $socks = FlashVideo::Mechanize->new->get_socks_proxy) { $rtmp_data->{socks} = $socks; } my($r_fh, $w_fh); # So Perl doesn't close them behind our back.. if ($rtmp_data->{live} && $self->action eq 'play') { # Playing live stream, we pipe this straight to the player, rather than # saving on disk. # XXX: The use of /dev/fd could go away now rtmpdump supports streaming to # STDOUT. pipe($r_fh, $w_fh); my $pid = fork; die "Fork failed" unless defined $pid; if(!$pid) { fcntl $r_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC(); exec $self->replace_filename($self->player, "/dev/fd/" . fileno $r_fh); die "Exec failed\n"; } fcntl $w_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC(); $rtmp_data->{flv} = "/dev/fd/" . fileno $w_fh; $self->{stream} = undef; } my $prog = $self->get_rtmp_program; if($prog eq 'flvstreamer' && ($rtmp_data->{rtmp} =~ /^rtmpe:/ || $rtmp_data->{swfhash})) { error "FLVStreamer does not support " . ($rtmp_data->{swfhash} ? "SWF hashing" : "RTMPE streams") . ", please install rtmpdump."; exit 1; } if($self->debug) { $rtmp_data->{verbose} = undef; } my($return, @errors) = $self->run($prog, $rtmp_data); if($return != 0 && "@errors" =~ /failed to connect/i) { # Try port 443 as an alternative info "Couldn't connect on RTMP port, trying port 443 instead"; $rtmp_data->{port} = 443; ($return, @errors) = $self->run($prog, $rtmp_data); } if($file ne '-' && (-s $file < 100 || !$self->check_file($file))) { # This avoids trying to resume an invalid file error "Download failed, no valid file downloaded"; unlink $rtmp_data->{flv}; return 0; } if($return == 2) { info "\nDownload incomplete -- try running again to resume."; return 0; } elsif($return) { info "\nDownload failed."; return 0; } return -s $file; } sub get_rtmp_program { if(is_program_on_path("rtmpdump")) { return "rtmpdump"; } elsif(is_program_on_path("flvstreamer")) { return "flvstreamer"; } # Default to rtmpdump return "rtmpdump"; } sub get_command { my($self, $rtmp_data, $debug) = @_; return map { my $arg = $_; (ref $rtmp_data->{$arg} eq 'ARRAY' # Arrayref means multiple options of the same type ? (map { ("--$arg" => $debug ? $self->shell_escape($_) : $_) } @{$rtmp_data->{$arg}}) # Single argument : ("--$arg" => (($debug && $rtmp_data->{$arg}) ? $self->shell_escape($rtmp_data->{$arg}) : $rtmp_data->{$arg}) || ())) } keys %$rtmp_data; } sub run { my($self, $prog, $rtmp_data) = @_; debug "Running $prog", join(" ", $self->get_command($rtmp_data, 1)); my($in, $out, $err); $err = gensym; my $pid = open3($in, $out, $err, $prog, $self->get_command($rtmp_data)); # Windows doesn't send signals to child processes, so we need to do it # manually to ensure that we don't have stray rtmpdump processes. local $SIG{INT}; if ($^O =~ /mswin/i) { $SIG{INT} = sub { kill 'TERM', $pid; exit; }; } my $complete = 0; my $buf = ""; my @error; while(sysread($err, $buf, 128, length $buf) > 0) { $buf =~ s/\015\012/\012/g; my @parts = split /\015/, $buf; $buf = ""; for(@parts) { # Hide almost everything from rtmpdump, it's less confusing this way. if(/^((?:DEBUG:|WARNING:|Closing connection|ERROR: No playpath found).*)\n/) { debug "$prog: $1"; } elsif(/^(ERROR: .*)\012/) { push @error, $1; info "$prog: $1"; } elsif(/^([0-9.]+) kB(?:\s+\/ \S+ sec)?(?: \(([0-9.]+)%\))?/i) { $self->{downloaded} = $1 * 1024; my $percent = $2; if($self->{downloaded} && $percent != 0) { # An approximation, but should be reasonable if we don't have the size. $self->{content_length} = $self->{downloaded} / ($percent / 100); } $self->progress; } elsif(/\012$/) { for my $l(split /\012/) { if($l =~ /^[A-F0-9]{,2}(?:\s+[A-F0-9]{2})*\s*$/) { debug $l; } elsif($l =~ /Download complete/) { $complete = 1; } elsif($l =~ /\s+filesize\s+(\d+)/) { $self->{content_length} = $1; } elsif($l =~ /\w/) { print STDERR "\r" if $self->{downloaded}; info $l; if($l =~ /^RTMPDump v([0-9.]+)/ && $1 < LATEST_RTMPDUMP) { error "==== Using the latest version of RTMPDump (version " . LATEST_RTMPDUMP . ") is recommended. ===="; } } } if(/open3/) { error "\nMake sure you have 'rtmpdump' or 'flvstreamer' installed and available on your PATH."; return 0; } } else { # Hack; assume lack of newline means it was an incomplete read.. $buf = $_; } } # Should be about enough.. if(defined $self->{stream} && $self->{downloaded} > 300_000) { $self->{stream}->(); } } waitpid $pid, 0; return $? >> 8, @error; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/URLFinder.pm0000644000175000017500000000527511772753754022515 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::URLFinder; use strict; use FlashVideo::Mechanize; use FlashVideo::Generic; use FlashVideo::Site; use FlashVideo::Utils; use URI; # The main issue is getting a URL for the actual video, so we handle this # here - a different package for each site, as well as a generic fallback. # Each package has a find_video method, which should return a URL, and a # suggested filename. # In some cases there isn't an obvious URL to find, so the following will be loaded and their 'can_handle' # method called. my @extra_can_handle = qw(Brightcove Mtvnservices Gawker Ooyala Gorillavid); sub find_package { my($class, $url, $browser) = @_; my $package = _find_package_url($url, $browser); if(!defined $package) { # Fairly lame heuristic, look for the first URL outside the # element (avoids grabbing things like codebase attribute). # Also look at embedded scripts for sites which embed their content that way. # TODO: extract all SWF URLs from the page and check to see if we've # got a package for those. for my $possible_url($browser->content =~ m!(?:]+>.*?|<(?:script|embed|iframe|param) [^>]*(?:src=["']?|name=["']src["']\ value=["']))(http://[^"'> ]+)!gixs) { $package = _find_package_url($possible_url, $browser); return _found($package, $possible_url) if defined $package; } } if(!defined $package) { for(@extra_can_handle) { my $possible_package = _load($_); $browser->get($url); my $r = $possible_package->can_handle($browser, $url); if($r) { $package = $possible_package; last; } } } if(!defined $package) { $package = "FlashVideo::Generic"; } return _found($package, $url); } # Split the URLs into parts and see if we have a package with this name. sub _find_package_url { my($url, $browser) = @_; my $package; foreach my $host_part (split /\./, URI->new($url)->host) { $host_part = lc $host_part; $host_part =~ s/[^a-z0-9]//i; my $possible_package = _load($host_part); if($possible_package->can("find_video")) { if($possible_package->can("can_handle")) { next unless $possible_package->can_handle($browser, $url); } $package = $possible_package; last; } } return $package; } sub _found { my($package, $url) = @_; info "Using method '" . lc((split /::/, $package)[-1]) . "' for $url"; return $package, $url; } sub _load { my($site) = @_; my $package = "FlashVideo::Site::" . ucfirst lc $site; if(eval "require $package") { no strict 'refs'; push @{$package . "::ISA"}, "FlashVideo::Site"; } return $package; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/JSON.pm0000644000175000017500000000345011772753754021465 0ustar junixjunixpackage FlashVideo::JSON; # Very simple JSON parser, loosely based on # http://code.google.com/p/json-sans-eval # Public domain. use strict; use base 'Exporter'; our @EXPORT = qw(from_json); my $number = qr{(?:-?\b(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b)}; my $oneChar = qr{(?:[^\0-\x08\x0a-\x1f\"\\]|\\(?:["/\\bfnrt]|u[0-9A-Fa-f]{4}))}; my $string = qr{(?:"$oneChar*")}; my $jsonToken = qr{(?:false|true|null|[\{\}\[\]]|$number|$string)}; my $escapeSequence = qr{\\(?:([^u])|u(.{4}))}; my %escapes = ( '\\' => '\\', '"' => '"', '/' => '/', 'b' => "\b", 'f' => "\f", 'n' => "\xA", 'r' => "\xD", 't' => "\t" ); sub from_json { my($in) = @_; my @tokens = $in =~ /$jsonToken/go; my $result = $tokens[0] eq '{' ? {} : []; # Handle something other than array/object at toplevel shift @tokens if $tokens[0] =~ /^[\[\{]/; my $key; # key to use for next value my @stack = $result; for my $t(@tokens) { my $ft = substr $t, 0, 1; my $cont = $stack[0]; if($ft eq '"') { my $s = substr $t, 1, length($t) - 2; $s =~ s/$escapeSequence/$1 ? $escapes{$1} : chr hex $2/geo; if(!defined $key) { if(ref $cont eq 'ARRAY') { $cont->[@$cont] = $s; } else { $key = $s; next; # need to save $key } } else { $cont->{$key} = $s; } } elsif($ft eq '[' || $ft eq '{') { unshift @stack, (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) = $ft eq '[' ? [] : {}; } elsif($ft eq ']' || $ft eq '}') { shift @stack; } else { (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) = $ft eq 'f' ? 0 # false : $ft eq 'n' ? undef # null : $ft eq 't' ? 1 # true : $t; # sign or digit } undef $key; } return $result; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/0000755000175000017500000000000011772753754021260 5ustar junixjunixget-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Techcast.pm0000644000175000017500000000130611772753754023354 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Techcast; use strict; use FlashVideo::Utils; use HTML::Entities; sub find_video { my ($self, $browser, $embed_url) = @_; my($clip_url) = $browser->content =~ /clip:\s*{\s*url:\s*['"]([^"']+)/; die "Unable to extract clip URL" unless $clip_url; $clip_url = URI->new_abs($clip_url, $browser->uri); my($talk) = $browser->content =~ /class="lecture_archive"[^>]+>([^<]+)/i; $talk = decode_entities($talk); my($author) = $browser->content =~ /class="speaker_archive"[^>]+>([^<]+)/i; $author = decode_entities($author); return $clip_url, title_to_filename($talk ? "$author - $talk" : $clip_url); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Brightcove.pm0000644000175000017500000001275711772753754023726 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Brightcove; use strict; use FlashVideo::Utils; use MIME::Base64; sub find_video { my ($self, $browser, $embed_url) = @_; my $metadata = { }; my ($video_id, $player_id); # URL params, JSON, etc.. $video_id = ($browser->content =~ /(?:clip|video)Id["'\] ]*[:=]["' ]*(\d+)/i)[0]; $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0]; # params $player_id ||= ($browser->content =~ /content =~ /) $player_id ||= ($browser->content =~ /flashVars.*playerID=(\d+)/i)[0]; $video_id ||= ($browser->content =~ /flashVars.*video(?:Player|ID)=(\d+)/i)[0]; # Brightcove JavaScript API if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) { $video_id = $1; $player_id = $2; } # Support direct links to videos for my $url($browser->uri->as_string, $embed_url) { if($url =~ /(?:videoID|bctid)=?(\d+)/i) { $video_id ||= $1; } if($url =~ /(?:playerID|bcpid)=?(\d+)/i) { $player_id ||= $1; } if($url =~ /(?:lineupID|bclid)=?(\d+)/i) { $metadata->{lineupId} ||= $1; } } debug "Extracted playerId: $player_id, videoId: $video_id, lineupID: $metadata->{lineupId}" if $player_id or $video_id; die "Unable to extract Brightcove IDs from page" unless $player_id; $metadata->{videoId} = $video_id; return $self->amfgateway($browser, $player_id, $metadata); } sub amfgateway { my($self, $browser, $player_id, $metadata) = @_; my $has_amf_packet = eval { require Data::AMF::Packet }; if (!$has_amf_packet) { die "Must have Data::AMF::Packet installed to download Brightcove videos"; } my $page_url = $browser->uri; my $packet = Data::AMF::Packet->deserialize(decode_base64(<messages->[0]->{value}->[0] = "$player_id"; } if (ref $metadata) { for(keys %$metadata) { $packet->messages->[0]->{value}->[1]->{$_} = "$metadata->{$_}"; } } my $data = $packet->serialize; $browser->post( "http://c.brightcove.com/services/amfgateway", Content_Type => "application/x-amf", Content => $data ); die "Failed to post to Brightcove AMF gateway" unless $browser->response->is_success; $packet = Data::AMF::Packet->deserialize($browser->content); if($self->debug) { require Data::Dumper; debug Data::Dumper::Dumper($packet); } if(ref $packet->messages->[0]->{value} ne 'ARRAY') { die "Unexpected data from AMF gateway"; } my @found; for (@{$packet->messages->[0]->{value}}) { if ($_->{data}->{videoDTO}) { push @found, $_->{data}->{videoDTO}; } if ($_->{data}->{videoDTOs}) { push @found, @{$_->{data}->{videoDTOs}}; } } my @rtmpdump_commands; for my $d (@found) { next if $metadata->{videoId} && $d->{id} != $metadata->{videoId}; my $host = ($d->{FLVFullLengthURL} =~ m!rtmp://(.*?)/!)[0]; my $file = ($d->{FLVFullLengthURL} =~ m!&([a-z0-9:]+/.*?)(?:&|$)!)[0]; my $app = ($d->{FLVFullLengthURL} =~ m!//.*?/(.*?)/&!)[0]; my $filename = ($d->{FLVFullLengthURL} =~ m!&.*?/([^/&]+)(?:&|$)!)[0]; $app .= "?videoId=$d->{id}&lineUpId=$d->{lineupId}&pubId=$d->{publisherId}&playerId=$player_id&playerTag=&affiliateId="; my $args = { app => $app, pageUrl => $page_url, swfUrl => "http://admin.brightcove.com/viewer/federated/f_012.swf?bn=590&pubId=$d->{publisherId}", tcUrl => "rtmp://$host:1935/$app", auth => ($d->{FLVFullLengthURL} =~ /^[^&]+&(.*)$/)[0], rtmp => "rtmp://$host/$app", playpath => $file, flv => "$filename.flv", }; # Use sane filename if ($d->{publisherName} and $d->{displayName}) { $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}"); } # In some cases, Brightcove doesn't use RTMP streaming - the file is # downloaded via HTTP. if (!$d->{FLVFullLengthStreamed}) { info "Brightcove HTTP download detected"; return ($d->{FLVFullLengthURL}, $args->{flv}); } push @rtmpdump_commands, $args; } if (@rtmpdump_commands > 1) { return \@rtmpdump_commands; } else { return $rtmpdump_commands[-1]; } } sub can_handle { my($self, $browser, $url) = @_; return 1 if $url && URI->new($url)->host =~ /\.brightcove\.com$/; return $browser->content =~ /(playerI[dD]|brightcove.player.create)/ && $browser->content =~ /brightcove/i; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Cnet.pm0000644000175000017500000000374311772753754022516 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Cnet; use strict; use FlashVideo::Utils; my $cnet_api_base = "http://api.cnet.com"; my $cnet_api_rest = $cnet_api_base . "/restApi/v1.0"; my $cnet_api_video_search = $cnet_api_rest . "/videoSearch"; # /restApi/v1.0/videoSearch?videoIds=50106980&showBroadcast=true&iod=images,videoMedia,relatedLink,breadcrumb,relatedAssets,broadcast%2Clowcache&videoMediaType=preferred&players=Download,RTMP sub find_video { my ($self, $browser, $embed_url) = @_; my $video_id; if($browser->content =~ //) { $video_id = $1; } elsif($browser->content =~ /assetId: '([0-9]+)',/) { $video_id = $1; } else { 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."; } return $self->get_video($browser, $video_id); } sub get_video { my ($self, $browser, $video_id) = @_; $browser->get($cnet_api_video_search . "?videoIds=" . $video_id . "&iod=videoMedia&players=RTMP"); my $xml = from_xml($browser->content, NoAttr => 1); my $video = $xml->{"Videos"}->{"Video"}; my $medias = $video->{"VideoMedias"}->{"VideoMedia"}; # my $media = @$medias[0]; my $max = 0; # my $max = (grep { $max = (( (int($_->{Width}) * int($_->{Height})) gt $max) ? $_ : $max) } @$medias); foreach (@{$video->{VideoMedias}->{VideoMedia}}) { if(int($_->{Width}) * int($_->{Height}) > $max){ $max = int($_->{Width}) * int($_->{Height}); } } my $media = (grep { (int($_->{Width}) * int($_->{Height})) eq $max } @$medias)[0]; my $delivery_url = $media->{DeliveryUrl}; my $title = $video->{FranchiseName} . ' - ' . $video->{Title}; if($media->{Player} eq 'RTMP'){ return { rtmp => $delivery_url, flv => title_to_filename($title) }; } elsif($media->{Player} eq 'Download'){ return $delivery_url, title_to_filename($title) } } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Pbs.pm0000644000175000017500000000634011772753754022345 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Pbs; use strict; use warnings; use FlashVideo::Utils; use MIME::Base64 qw(decode_base64); =pod Programs that work: - http://video.pbs.org/video/1623753774/ - http://www.pbs.org/wnet/nature/episodes/revealing-the-leopard/full-episode/6084/ - http://www.pbs.org/wgbh/nova/ancient/secrets-stonehenge.html - http://www.pbs.org/wnet/americanmasters/episodes/lennonyc/outtakes-jack-douglas/1718/ - http://www.pbs.org/wnet/need-to-know/video/need-to-know-november-19-2010/5189/ - http://www.pbs.org/newshour/bb/transportation/july-dec10/airport_11-22.html Programs that don't work yet: - http://www.pbs.org/wgbh/pages/frontline/woundedplatoon/view/ - http://www.pbs.org/wgbh/roadshow/rmw/RMW-003_200904F02.html TODO: - subtitles =cut sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; die "Must have Crypt::Rijndael installed to download from PBS" unless eval { require Crypt::Rijndael }; my ($media_id) = $browser->uri->as_string =~ m[ ^http://video\.pbs\.org/video/(\d+) ]x; unless (defined $media_id) { ($media_id) = $browser->content =~ m[ http://video\.pbs\.org/widget/partnerplayer/(\d+) ]x; } unless (defined $media_id) { ($media_id) = $browser->content =~ m[ /embed-player[^"]+\bepisodemediaid=(\d+) ]x; } unless (defined $media_id) { ($media_id) = $browser->content =~ m[var videoUrl = "([^"]+)"]; } unless (defined $media_id) { my ($pap_id, $youtube_id) = $browser->content =~ m[ \bDetectFlashDecision\ \('([^']+)',\ '([^']+)'\); ]x; if ($youtube_id) { debug "Youtube ID found, delegating to Youtube plugin\n"; my $url = "http://www.youtube.com/v/$youtube_id"; require FlashVideo::Site::Youtube; return FlashVideo::Site::Youtube->find_video($browser, $url, $prefs); } } die "Couldn't find media_id\n" unless defined $media_id; debug "media_id: $media_id\n"; $browser->get("http://video.pbs.org/videoPlayerInfo/$media_id"); my $xml = $browser->content; $xml =~ s/&/&/g; my $href = from_xml($xml); my $file = $href->{videoInfo}->{title}; my $release_url = $href->{releaseURL}; unless ($release_url =~ m[^https?://]) { debug "encrypted release url: $release_url\n"; my ($type, $iv, $ciphertext) = split '\$', $release_url, 3; $release_url = undef; # From http://www-tc.pbs.org/video/media/swf/PBSPlayer.swf my $key = 'RPz~i4p*FQmx>t76'; my $cipher = Crypt::Rijndael->new($key, Crypt::Rijndael->MODE_CBC); $iv = pack 'H*', $iv if 32 == length $iv; $cipher->set_iv($iv); $release_url = $cipher->decrypt(decode_base64($ciphertext)); $release_url =~ s/\s+$//; } debug "unencrypted release url: $release_url\n"; $browser->get($release_url); my $rtmp_url = $browser->res->header('location') || from_xml($browser->content)->{choice}{url} || die "Couldn't find stream url\n"; $rtmp_url =~ s///; if(!$file) { ($file) = $rtmp_url =~ m{([^/\?]+)$}; } return { rtmp => $rtmp_url, pageUrl => $embed_url, swfUrl => 'http://www-tc.pbs.org/video/media/swf/PBSPlayer.swf?18809', flv => title_to_filename($file), }; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/About.pm0000644000175000017500000000147311772753754022675 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::About; use strict; use FlashVideo::Utils; use base 'FlashVideo::Site::Brightcove'; my $JS_RE = qr/vdo_None\.js/; sub find_video { my($self, $browser, $embed_url) = @_; my($video_ref) = $browser->content =~ /zIvdoId=["']([^"']+)/; die "Unable to extract video ref" unless $video_ref; my($js_src) = $browser->content =~ /["']([^"']+$JS_RE)/; $browser->get($js_src); my($player_id) = $browser->content =~ /playerId.*?(\d+)/; die "Unable to extract playerId" unless $player_id; return $self->amfgateway($browser, $player_id, { videoRefId => $video_ref }); } sub can_handle { my($self, $browser, $url) = @_; # can only handle videos embedded with this javascript code. return $browser->content =~ $JS_RE; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Youtubenocookie.pm0000644000175000017500000000024211772753754024777 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Youtubenocookie; use strict; use base 'FlashVideo::Site::Youtube'; 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Abc.pm0000644000175000017500000000572711772753754022316 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Abc; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; # Clips are handled differently to full episodes if ($browser->uri->as_string =~ m'/watch/clip/[\w\-]+/(\w+)/(\w+)/(\w+)') { my $show_id = $1; my $playlist_id = $2; my $video_id = $3; return handle_abc_clip($browser, $show_id, $playlist_id, $video_id); } my $playpath; if ($browser->content =~ /http:\/\/cdn\.video\.abc\.com\/abcvideo\/video_fep\/thumbnails\/220x124\/([^"]*)220x124\.jpg/) { $playpath = "mp4:/abcvideo/video_fep/mov/" . lc($1) . "768x432_700.mov"; } $browser->content =~ /

([^<]*)<\/h2>/; my $title = $1; my $rtmpurl = "rtmp://abcondemandfs.fplive.net:1935/abcondemand"; return { rtmp => $rtmpurl, playpath => $playpath, flv => title_to_filename($title) }; } sub handle_abc_clip { my ($browser, $show_id, $playlist_id, $video_id) = @_; # Note 'limit' has been changed to 1 instead of the default of 12. This # ensures that only the desired video is returned. Otherwise unrelated # videos are returned too. my $abc_clip_rss_url_template = "http://ll.static.abc.com/vp2/ws/s/contents/1000/videomrss?" . "brand=001&device=001&width=644&height=362&clipId=%s" . "&start=0&limit=1&fk=CATEGORIES&fv=%s"; my $abc_clip_rss_url = sprintf $abc_clip_rss_url_template, $video_id, $playlist_id; $browser->get($abc_clip_rss_url); if (!$browser->success) { die "Couldn't download ABC clip RSS: " . $browser->response->status_line; } my $xml = from_xml($browser); my $video_url = $xml->{channel}->{item}->{'media:content'}->{url}; my $type = $video_url =~ /\.mp4$/ ? 'mp4' : 'flv'; if (!$video_url) { die "Couldn't determine ABC clip URL"; } # Try to get a decent filename my $episode_name; if ($video_url =~ /FLF_\d+[A-Za-z]{0,5}_([^_]+)/) { $episode_name = $1; } my $category = $xml->{channel}->{item}->{category}; my $title = $xml->{channel}->{item}->{'media:title'}->{content}; if (ref($category) eq 'HASH' and ! keys %$category) { $category = ''; } # Description isn't actually very long - see media:text for that for when # gfv has support for writing Dublin Core-compliant metadata. my $description = $xml->{channel}->{item}->{'media:description'}->{content}; # Remove HTML in evil way. for ($category, $description, $title) { s/<\/?\w+>//g; } my $video_title = make_title($category, $episode_name, $title, $description); return $video_url, title_to_filename($video_title, $type); } # Produces the title, taking into account items that don't exist sub make_title { return join " - ", grep /./, @_; } sub can_handle { my($self, $browser, $url) = @_; # This is only ABC as in the US broadcaster, not abc.net.au return $url && URI->new($url)->host =~ /\babc\.(?:go\.)?com$/; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Flickr.pm0000644000175000017500000000273611772753754023040 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Flickr; use strict; use FlashVideo::Utils; use URI::Escape; my $get_mtl = "http://www.flickr.com/apps/video/video_mtl_xml.gne?v=x"; sub find_video { my ($self, $browser, $embed_url) = @_; my($id) = $browser->content =~ /photo_id=(\d+)/; my($secret) = $browser->content =~ /photo_secret=(\w+)/; die "No video ID found\n" unless $id; $browser->get($get_mtl . "&photo_id=$id&secret=$secret&olang=en-us&noBuffer=null&bitrate=700&target=_self"); my $xml = from_xml($browser); my $guid = $self->make_guid; my $video_id = $xml->{Data}->{Item}->{id}->{content}; my $playlist_url = $xml->{Playlist}->{TimelineTemplates}->{Timeline} ->{Metadata}->{Item}->{playlistUrl}->{content}; die "No video ID or playlist found" unless $video_id and $playlist_url; $browser->get($playlist_url . "?node_id=$video_id&secret=$secret&tech=flash&mode=playlist" . "&lq=$guid&bitrate=700&rd=video.yahoo.com&noad=1"); $xml = eval { XML::Simple::XMLin($browser->content) }; die "Failed parsing XML: $@" if $@; $xml = $xml->{"SEQUENCE-ITEM"}; die "XML not as expected" unless $xml; my $filename = title_to_filename($xml->{META}->{TITLE}); my $url = $xml->{STREAM}->{APP} . $xml->{STREAM}->{FULLPATH}; return $url, $filename; } sub make_guid { my($self) = @_; my @chars = ('A' .. 'Z', 'a' .. 'z', 0 .. 9, '.', '_'); return join "", map { $chars[rand @chars] } 1 .. 22; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Ima.pm0000644000175000017500000000142111772753754022322 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Ima; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser) = @_; my($id) = $browser->uri =~ /id=(\d+)/; die "ID not found" unless $id; my $rpc = "http://www.ima.umn.edu/videos/video_rpc.php?id=$id"; $browser->get($rpc); my($title) = $browser->content =~ m{(.*)}; my($instance) = $browser->content =~ m{(.*)}; my($file) = $browser->content =~ m{(.*)}; return { rtmp => "rtmp://reel.ima.umn.edu/ima/$instance/$file", flv => title_to_filename($title) }; } sub can_handle { my($self, $browser) = @_; return $browser->uri->host =~ /ima\.umn\.edu/i; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Putlocker.pm0000644000175000017500000000355611772753754023577 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Putlocker; use strict; use FlashVideo::Utils; use HTML::Tree; sub find_video { my ($self, $browser, $embed_url) = @_; my ($filename) = title_to_filename(extract_title($browser)); $filename =~ s/[\s\|_]*PutLocker[\s_]*//; #get the "hash" value from the HTML my $tree = HTML::Tree->new(); $tree->parse($browser->content); my $hash = $tree->look_down( 'name' , 'hash' )->attr('value'); info 'Found hash: ' . $hash; #Construct a POST request to get the tell the server to serve real page content info "Confirming request to PutLocker."; $browser->add_header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $browser->add_header( 'Accept-Encoding' => 'text/html' ); $browser->add_header( Referer => $embed_url ); my $response = $browser->post($embed_url, [ 'confirm'=>"Continue as Free User", 'hash'=>$hash ]); #we will get a redirect, this is the cue to re-request the same page - die if not die 'Response code was ' . $response->code . '. Should be 302.' unless ($response->code == '302'); info "Re-fetching page, which will now have the video embedded."; $browser->delete_header( 'Content-Type'); my $page_html = $browser->get($embed_url)->content; #the stream ID is now embedded in the page. my ($streamID) = ($page_html =~ /get_file\.php\?stream=([A-Za-z0-9]+)/); info "Found the stream ID: " . $streamID; #request the url of the actual file my $uri = URI->new( "http://www.putlocker.com/get_file.php" ); $uri->query_form((stream=>$streamID)); #parse the url and title out of the response - much easier to regex it out, as the XML has dodgy &'s. my $contents = $browser->get($uri)->content; my ($url) = ($contents =~ /url="(.*?)"/); info "Got the video URL: " . $url; return $url, $filename; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Nicovideo.pm0000644000175000017500000000157111772753754023541 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Nicovideo; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; my $id = ($embed_url =~ /([ns]m\d+)/)[0]; die "No ID found\n" unless $id; my $base = "http://ext.nicovideo.jp/thumb_watch/$id"; if($embed_url !~ /ext\.nicovideo\.jp\/thumb_watch/) { $embed_url = "$base?w=472&h=374&n=1"; } $browser->get($embed_url); my $playkey = ($browser->content =~ /'thumbPlayKey': '([^']+)/)[0]; die "No playkey found\n" unless $playkey; my $title = ($browser->content =~ /title: '([^']+)'/)[0]; $title =~ s/\\u([a-f0-9]{1,5})/chr hex $1/eg; $browser->get($base . "/$playkey"); my $url = uri_unescape(($browser->content =~ /url=([^&]+)/)[0]); return $url, title_to_filename($title, $id =~ /^nm/ ? "swf" : "flv"); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Expertvillage.pm0000644000175000017500000000141611772753754024433 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Expertvillage; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my ($self, $browser) = @_; my($fn) = $browser->content =~ /SWFObject\(['"][^'"]+flv=([^'"]+)/; my $embedvars = uri_unescape($browser->content =~ /embedvars['"],\s*['"]([^'"]+)/); die "Unable to find video info" unless $fn and $embedvars; my($title) = $browser->content =~ m{]*>(.*)

}s; my $filename = title_to_filename($title); $browser->get("$embedvars?fn=$fn"); die "Unable to get emebdding info" if $browser->response->is_error; my $url = uri_unescape($browser->content =~ /source=([^&]+)/); die "Unable to find video URL" unless $url; return $url, $filename; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Bbc.pm0000644000175000017500000001444611772753754022315 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Bbc; use strict; use FlashVideo::Utils; use URI; sub find_video { my ($self, $browser, $page_url, $prefs) = @_; my $count = 0; while((my $location = $browser->response->header("Location")) && $count++ < 5) { $browser->get($location); } # Get playlist XML my $playlist_xml; if ($browser->content =~ /content =~ /empDivReady\s*\(([^)]+)/) { my @params = split /,\s*/, $1; my $id = $params[3]; my $path = $params[4]; $id =~ s/['"]//g; $path =~ s/['"]//g; $playlist_xml = URI->new_abs($path, $browser->uri) . "/media/emp/playlists/$id.xml"; } elsif($browser->content =~ /setPlaylist\s*\(([^)]+)/) { my $path = $1; $path =~ s/['"]//g; $playlist_xml = URI->new_abs($path, $browser->uri); } elsif($browser->content =~ /EmpEmbed.embed\s*\((.*?)\);/) { my $path = (split /,/, $1)[3]; $path =~ s/"//g; $playlist_xml = URI->new_abs($path, $browser->uri); } elsif($browser->uri =~ m!/(b[0-9a-z]{7})(?:/|$)!) { # Looks like a pid.. my @gi_cmd = (qw(get_iplayer -g --pid), $1); if($browser->content =~ /buildAudioPlayer/) { # Radio programme push @gi_cmd, "--type=radio"; } error "get_flash_videos does not support iplayer, but get_iplayer does.."; info "Attempting to run '@gi_cmd'"; exec @gi_cmd; # Probably not installed.. error "Please download get_iplayer from http://linuxcentre.net/getiplayer/\n" . "and install in your PATH"; exit 1; } else { die "Couldn't find BBC XML playlist URL in " . $browser->uri->as_string; } $browser->get($playlist_xml); if (!$browser->success) { die "Couldn't download BBC XML playlist $playlist_xml: " . $browser->response->status_line; } my $playlist = eval { from_xml($browser, KeyAttr => {item => 'kind'}) }; if ($@) { # Try to fix their potentially broken XML.. my $content = $browser->content; if ($content !~ m{}) { $content .= "\n\n"; } $playlist = from_xml($$content, KeyAttr => {item => 'kind'}) } my $sound = ($playlist->{item}->{guidance} !~ /has no sound/); my $info = ref $playlist->{item}->{media} eq 'ARRAY' ? $playlist->{item}->{media}->[0]->{connection} : $playlist->{item}->{media}->{connection}; $info = $playlist->{item}->{programme}->{media}->{connection} unless $info; $info->{application} ||= "ondemand"; # Different method for retrieving some BBC videos, for example: # http://news.bbc.co.uk/sport1/hi/motorsport/formula_one/8766344.stm if (!$info->{server}) { my $id = $playlist->{item}->{mediator}->{identifier}; if(!$id) { $id = $playlist->{item}->{programme}->{mediator}->{identifier}; } my $stream_info_url = sprintf "http://open.live.bbc.co.uk/mediaselector/4/mtis/stream/%s", $id; $browser->back(); $browser->get($stream_info_url); if (!$browser->success) { die "Couldn't get BBC stream info URL: " . $browser->response->status_line; } my $stream_info = from_xml($browser->content); if( ref $stream_info->{media} eq 'ARRAY' ){ my $q = $prefs->{quality}; my @media = sort { $a->{bitrate} <=> $b->{bitrate} } @{$stream_info->{media}}; my @q_media = grep { $_->{bitrate} == $q || "$_->{height}x$_->{width}x$_->{bitrate}" == $q || "$_->{height}x$_->{width}" == $q } @media; if( @q_media ){ @media = @q_media; } my $cnt = @media; my $num = {high => int($cnt)-1, medium => int($cnt/2), low => 0}->{$q}; $info = $media[$num]->{connection}; } else { $info = $stream_info->{media}->{connection}; } } # Some BBC videos seem to use plain HTTP if( $info->{href} ){ my $url = $info->{href}; my @path = URI->new($url)->path_segments(); return $url, @path[-1]; } my $data = { app => $info->{application}, tcUrl => "rtmp://$info->{server}/$info->{application}", swfUrl => "http://news.bbc.co.uk/player/emp/2.11.7978_8433/9player.swf", pageUrl => $page_url, rtmp => "rtmp://" . $info->{server} . "/$info->{application}", playpath => $info->{identifier}, flv => title_to_filename('BBC - ' . $playlist->{title} . ($sound ? '' : ' (no sound)')) }; # Different kind of 'secure' video. The auth string (or token) is already # provided in the XML. The auth string actually includes other RTMP # parameters as well - unlike in the case below, it's not just the actual # token. if ($info->{authString}) { my $token = $info->{authString}; $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}" . "&$token"; $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}" . "&$token"; $data->{playpath} .= "?$token"; } # 'Secure' items need to be handled differently - have to get a token to # pass to the rtmp server. if ($info->{identifier} =~ /^secure/ or $info->{tokenIssuer}) { my $url = "http://www.bbc.co.uk/mediaselector/4/gtis?server=$info->{server}" . "&identifier=$info->{identifier}&kind=$info->{kind}" . "&application=$info->{application}&cb=123"; debug "Got BBC auth URL for 'secure' video: $url"; $browser->get($url); # BBC redirects us to the original URL which is odd, but oh well. if (my $redirect = $browser->response->header('Location')) { debug "BBC auth URL redirects to: $url"; $browser->get($redirect); } my $stream_auth = from_xml($browser); my $token = $stream_auth->{token}; if (!$token) { die "Couldn't get token for 'secure' video download"; } $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}" . "&auth=$token" . "&aifp=v001&slist=" . $info->{identifier}; $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}" . "&auth=$token" . "&aifp=v001&slist=" . $info->{identifier}; $data->{playpath} .= "?auth=$token&aifp=v0001"; if($info->{application} eq 'live') { $data->{subscribe} = $data->{playpath}; $data->{live} = 1; } } return $data; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Googlevideosearch.pm0000644000175000017500000000153611772753754025254 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Googlevideosearch; use strict; no warnings 'uninitialized'; use FlashVideo::Mechanize; use URI::Escape; sub search { my($self, $search, $type) = @_; my $browser = FlashVideo::Mechanize->new; $browser->get('http://video.google.com/videoadvancedsearch'); $browser->submit_form( with_fields => { q => $search, } ); return unless $browser->success; my @links = map { chomp(my $name = $_->text); my $url = $_->url_abs->as_string; $url =~ /q=([^&]*)/; $url = uri_unescape($1); { name => $name, url => $url } } $browser->find_all_links(text_regex => qr/.+/, url_regex => qr/\/url/); return @links; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tv3play.pm0000644000175000017500000000435111772753754023163 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Tv3play; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; return $self->find_video_viasat($browser,$embed_url,$prefs); } sub find_video_viasat { my ($self, $browser, $embed_url, $prefs) = @_; my $video_id = ($browser->content =~ /id:([0-9]*),/)[0]; info "Got video_id: $video_id"; my $info_url = "http://viastream.viasat.tv/PlayProduct/$video_id"; $browser->get($info_url); my $variable = $browser->content; $variable =~ s/\n//g; my $title = ($variable =~ /<!\[CDATA\[(.*?)\]\]><\/Title>/)[0]; my $flv_filename = title_to_filename($title, "flv"); # Subtitle Format not supported # my $subtitle_url = ($variable =~ /<SamiFile>(.*)<\/SamiFile>/)[0]; # debug "Subtitle_url: $subtitle_url"; # if ($prefs->{subtitles} == 1) { # if (not $subtitle_url eq '') { # info "Found subtitles: $subtitle_url"; # $browser->get("$subtitle_url"); # my $srt_filename = title_to_filename($title, "srt"); # convert_sami_subtitles_to_srt($browser->content, $srt_filename); # } else { # info "No subtitles found!"; # } # } my @urls; my $count = 0; my $base = ($variable =~ /<Videos>(.*)<\/Videos>/)[0]; for ($count = 0; $count < 3; $count++){ my $video = ($base =~ /<Video>(.+)<\/Video>/p)[0]; if ($video eq ''){last;}; $base = ${^POSTMATCH}; my $bitrate = ($video =~ /<BitRate>([0-9]*)<\/BitRate>/)[0]; my $url = ($video =~ /<Url><!\[CDATA\[(.*)]]><\/Url>/)[0]; if (not (($url =~ /http:\/\//)[0] eq '')){ $browser->get($url); $variable = $browser->content; $variable =~ s/\n//g; $url = ($variable =~ /<Url>(.*)<\/Url>/)[0]; } $urls[$count++] = { 'bitrate' => $bitrate, 'rtmp' => $url }; } my $bitrate = 0; my $rtmp; my $new_bitrate; foreach (@urls) { $new_bitrate = int($_->{bitrate}); if($new_bitrate > $bitrate){ $bitrate = int($_->{bitrate}); $rtmp = $_->{rtmp}; } }; return{ rtmp => $rtmp, swfVfy => "http://flvplayer-viastream-viasat-tv.origin.vss.viasat.tv/play/swf/player110420.swf", flv => $flv_filename }; } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Ted.pm��������������������������������������0000644�0001750�0001750�00000006303�11772753754�022334� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Ted; use strict; use FlashVideo::Utils; use FlashVideo::JSON; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $basefilename; if ($browser->content =~ m{<noscript.*download.ted.com/talks/([^.]+)\.mp4.*noscript>}s) { $basefilename = $1; } else { die "Unable to find download link"; } # Get subtitles if requested. Use the LANG variable to choose the language. # There is an intro to the video which isn't included in the subtitle timing info if ($prefs->subtitles) { my $lang = ""; if ($browser->content =~ m{talkID = (\d+);}s) { my $talkID = $1; my $intro_time = 15000; if ($browser->content =~ m{introDuration:(\d+)}s) { $intro_time = int($1); } else { error "Can't find the intro duration, so guessing at 15 seconds."; } $ENV{LANG} =~ /^([^_]*)/; $lang = $1; if (!$lang) { info "Unable to determine your language, using English"; $lang = "en"; } info "Downloading subtitles"; get_subtitles($browser, $basefilename . ".srt", $intro_time, "http://www.ted.com/talks/subtitles/id/$talkID/lang/$lang/format/json"); } else { error "Unable to determine the talk ID, so can't get the subtitles"; } } my $quality = $prefs->{quality}; if ($quality eq "low") { $quality = "-light"; } elsif ($quality eq "medium") { $quality = ""; } elsif ($quality eq "high") { $quality = "-480p"; } else { die "Unknown quality setting"; } my $url = "http://download.ted.com/talks/" . $basefilename . $quality . ".mp4"; # the url will be redirected to the real one $browser->allow_redirects; return $url, $basefilename . ".mp4"; } sub get_subtitles { my ($browser, $filename, $intro_time, $url) = @_; $browser->get($url); if (!$browser->success) { error "Couldn't download subtitles: " . $browser->response->status_line; return; } json_to_srt($browser->content, $filename, $intro_time); } # JSON to SRT subtitle conversion from zakflash sub json_to_srt { my ($subdata, $filename, $intro_time) = @_; open (SRT, '>', $filename) or die "Can't open subtitles file $filename: $!"; my $subtitle_count = 0; my $subdata = from_json($subdata); foreach my $subtitle (@{ $subdata->{captions} }) { $subtitle_count++; # SubRip starts at 1 # SubRip format: # 1 # 00:00:05,598 --> 00:00:07,131 # (screaming) # # 2 # 00:00:07,731 --> 00:00:09,298 # D'oh! my ($srt_start, $srt_end) = convert_to_srt_time( $subtitle->{startTime} + $intro_time, $subtitle->{duration}, ); print SRT "$subtitle_count\n" . "$srt_start --> $srt_end\n" . "$subtitle->{content}\n\n"; } close SRT; } sub convert_to_srt_time { my ($start, $duration) = @_; return format_srt_time($start), format_srt_time($start + $duration); } sub format_srt_time { my $time = shift; my $seconds = int($time / 1000); my $milliseconds = $time - ($seconds * 1_000); return sprintf "%02d:%02d:%02d,%03d", (gmtime $seconds)[2, 1, 0], $milliseconds; } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Spiegel.pm����������������������������������0000644�0001750�0001750�00000002233�11772753754�023206� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Spiegel; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my ($video_id, $xmlurl, $filename, $videourl, $quality); debug "Spiegel::find_video called, embed_url = \"$embed_url\"\n"; $quality = { high => '.mp4', medium => 'VP6_928.flv', low => 'VP6_576.flv'}->{$prefs->{quality}}; if($embed_url =~ /.*?www.spiegel.de\/video\/video-(\d*).html/) { $video_id = $1; $xmlurl = "http://video.spiegel.de/flash/$video_id.xml"; } else { die "Only works for http://www.spiegel/de/video/video... urls\n"; } if($browser->content =~ /<title>(.*?) -Video/) { $filename = "Spiegel_$1_${video_id}_$quality"; $filename = title_to_filename($filename, $quality); $filename =~ s/__/_/g; } else { die "Unable to find <title> on page $embed_url\n"; } $browser->get($xmlurl); if($browser->content =~ /<filename>(.*?$quality)<\/filename>/) { $videourl = "http://video.spiegel.de/flash/$1"; } else { die "could not find video url\n"; } return $videourl, $filename; } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Cbs.pm��������������������������������������0000644�0001750�0001750�00000001411�11772753754�022322� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Cbs; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my $pid; if ($browser->uri->as_string =~ /pid=([^&]*)/) { $pid = $1; } $browser->get("http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&MBR=true&pid=$pid"); my $xml = from_xml($browser->content); my $items = $xml->{body}->{switch}; my $item = ref $items eq 'ARRAY' ? (grep { $_->{video}->{src} =~ /^rtmp:\/\// } @$items)[0] : $items; my $rtmpurl = $item->{video}->{src}; $rtmpurl =~ s/<break>.*//; my $title = $item->{ref}->{title}; return { rtmp => $rtmpurl, flv => title_to_filename($title) }; } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Seesaw.pm�����������������������������������0000644�0001750�0001750�00000017666�11772753754�023065� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Seesaw; use strict; use FlashVideo::Utils; use HTML::Entities qw(decode_entities); use URI::Escape qw(uri_escape); my @res = ( { name => "lowResUrl", resolution => [ 512, 288 ] }, { name => "stdResUrl", resolution => [ 672, 378 ] }, { name => "highResUrl", resolution => [ 1024, 576 ] } ); sub find_video { my ($self, $browser, $page_url, $prefs) = @_; # The videoplayerinfo info URL now appears as the Nth parameter to # player.init(), so just look for the videoplayerinfo directly, rather # than looking for player.init and the first parameter. my $player_info = ($browser->content =~ m{(/videoplayerinfo/\d+[^"]+)"})[0]; # Remove escaped slashes (my $content = $browser->content) =~ s{\\/}{/}g; # Grab title and normalise my %seen; # avoid duplication in filenames # Annoyingly it's no longer easy to find out the series/season and # episode number. my %metadata = map { $_ => '' } qw(brandTitle seriesTitle programmeTitle); my ($series, $episode); ($series, $episode) = ($browser->content =~ /Series (\d+) - Ep(?:isode)?\.? (\d+)/); # Try to get the series and episode numbers differently if required. if (!$series and !$episode) { ($series, $episode) = ($browser->content =~ /series_number: ["']?(\d+)["']?,\s+ep_number: ['"]?(\d+)['"]/); } if ($series and $episode) { $metadata{series_and_episode} = sprintf "S%02dE%02d", $series, $episode; } # Need to make this Dublin Core / ISO 15836 compliant. foreach my $metadata_item (keys %metadata) { if (my $value = ($content =~ m{<$metadata_item>(.*?)</$metadata_item>}isg)[0]) { $value = decode_entities($value); # Handle various metadata items being identical. next if $seen{$value}; $seen{$value}++; $metadata{$metadata_item} = $value; } } # If there's only a show title and series/episode details, make sure the # SnnEnn part of the filename is at the end of the file name. my @metadata_items; if ( (grep length, values %metadata) == 2 and $metadata{series_and_episode}) { # SnnEnn at end of filename. @metadata_items = ((grep { $_ ne 'series_and_episode' } keys %metadata), 'series_and_episode'); } elsif (!$metadata{brandTitle}) { # Programme name, SnnEnn, programme or episode title. @metadata_items = qw(seriesTitle series_and_episode programmeTitle); } else { @metadata_items = qw(brandTitle series_and_episode seriesTitle programmeTitle); } my $title = join "-", map { trim($_) } grep length, @metadata{@metadata_items}; # Grab player info $browser->get($player_info); debug "Got player info URL $player_info"; if (!$browser->success) { die "Couldn't get player info: " . $browser->response->status_line; } my @urls; for my $res(@res) { if($browser->content =~ /$res->{name}":\["([^"]+)/) { push @urls, { %$res, url => $1 }; } } die "No video URLs found" unless @urls; my $rtmp = $prefs->quality->choose(@urls); my($app, $playpath, $query) = $rtmp->{url} =~ m{^\w+://[^/]+/(\w+/\w+)(/[^?]+)(\?.*)}; my $prefix = "mp4"; $prefix = "flv" if $playpath =~ /\.flv$/; if ($prefs->subtitles) { if ($browser->content =~ m{"subtitleLocation":\["([^"]+)"\]}) { my $subtitles_url = $1; if ($subtitles_url =~ m{^/}) { $subtitles_url = "http://www.seesaw.com$subtitles_url"; } debug "Got Seesaw subtitles URL: $subtitles_url"; $browser->get($subtitles_url); if ($browser->success) { my $srt_filename = title_to_filename($title, "srt"); convert_sami_subtitles_to_srt($browser->content, $srt_filename); info "Wrote subtitles to $srt_filename"; } else { info "Couldn't download subtitles: " . $browser->response->status_line; } } else { debug "No Seesaw subtitles available (or couldn't extract URL)"; } } return { flv => title_to_filename($title, $prefix), rtmp => $rtmp->{url}, app => $app, playpath => "$prefix:$playpath$query" } } sub search { my($self, $search, $type) = @_; my $series = $search =~ s/(?:series |\bs)(\d+)//i ? int $1 : ""; my $episode = $search =~ s/(?:episode |\be)(\d+)//i ? int $1 : ""; my $browser = FlashVideo::Mechanize->new; _update_with_content($browser, "http://www.seesaw.com/start.layout.searchsuggest:inputtextevent?search=" . uri_escape($search)); # Find links to programmes my @urls = map { chomp(my $name = $_->text); { name => $name, url => $_->url_abs->as_string } } $browser->find_all_links(text_regex => qr/.+/); # Only use result which matched every word. # (Seesaw's search is useless, so this seems to be the best we can do). my @words = split " ", $search; @urls = grep { my $a = $_; @words == grep { $a->{name} =~ /\Q$_\E/i } @words } @urls; if(@urls == 1) { $browser->get($urls[0]->{url}); # We are now at the episode page. my $main_title = ($browser->content =~ m{<h1>(.*?)</h1>}s)[0]; $main_title =~ s/<[^>]+>//g; $main_title =~ s/\s+/ /g; # Parse the list of series my $cur_series = ($browser->content =~ /<li class="current">.*?>\w+ (\d+)/i)[0]; if($main_title =~ s/\s*series (\d+)\s*//i && !$cur_series) { $cur_series = $1; } my %series = reverse( ($browser->content =~ m{<ul class="seriesList">(.*?)</ul>}i)[0] =~ /<li.*?href="\?([^"]+)".*?>\s*(?:series\s*)?([^<]+)/gi); # Go to the correct series my $episode_list; if($series && $cur_series ne $series) { if(!$series{$series}) { error "No such series number ($series)."; return; } _update_with_content($browser, $series{$series}); $episode_list = $browser->content; $cur_series = $series; } elsif(!$series && keys %series > 1) { my @series = sort { $a <=> $b } map { s/series\s+//i; $_ } keys %series; info "Viewing series $cur_series; series " . join(", ", @series) . " also available."; info "Search for 'seesaw $main_title series $series[0]' to view a specific series."; } if(!$episode_list) { # Grab the episodes for the current series from the page $episode_list = ($browser->content =~ m{<table id="episodeListTble">(.*?)</table>}is)[0]; } # Parse list of episodes @urls = (); for my $episode_html($episode_list =~ m{<tr.*?</tr>}gis) { # Each table row here my %info; for(qw(number date title action)) { my $class = "episode" . ucfirst; $episode_html =~ m{<td class=['"]$class['"]>(.*?)</td>}gis && ($info{$_} = $1); } $info{number} = ($info{number} =~ /ep\.?\w*\s*(\d+)/i)[0]; $info{date} = ($info{date} =~ />(\w+[^<]+)/)[0]; $info{number} ||= ($info{title} =~ /ep\.?\w*\s*(\d+)/i)[0]; $info{title} = ($info{title} =~ />\s*([^<].*?)\s*</s)[0]; $info{url} = ($info{action} =~ /href=['"]([^'"]+)/)[0]; my $title = join " - ", $main_title, ($cur_series ? sprintf("S%02dE%02d", $cur_series, $info{number}) : $info{number} ? sprintf("E%02d", $info{number}) : ()), $info{title}; my $result = { name => $title, url => URI->new_abs($info{url}, $browser->uri) }; if($episode && $info{number} == $episode) { # Exact match return $result; } push @urls, $result; } } else { info "Please specify a more specific title to download a particular programme." if @urls > 1; } return @urls; } sub _update_with_content { my($browser, $url) = @_; $browser->get($url, X_Requested_With => 'XMLHttpRequest', X_Prototype_Version => '1.6.0.3'); my($content) = $browser->content =~ /content":\s*"(.*?)"\s*}/; $content = json_unescape($content); debug "Content is '$content'"; $browser->update_html($content); } sub trim { local $_ = shift; s/^\s+|\s+$//g; return $_; } 1; ��������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Nbc.pm��������������������������������������0000644�0001750�0001750�00000004653�11772753754�022330� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Nbc; use strict; use FlashVideo::Utils; use MIME::Base64; sub find_video { my ($self, $browser, $embed_url) = @_; my $has_amf_packet = eval { require Data::AMF::Packet }; if (!$has_amf_packet) { die "Must have Data::AMF::Packet installed to download Nbc videos"; } # http://www.nbc.com/30-rock/video/mothers-day/1225683/ my $video_id; if ($browser->uri->as_string =~ /\/([0-9]+)\//) { $video_id = $1; } # no decode base16? # 0000000000010016676574436C6970496E666F2E676574436C6970416C6C00022F310000001F0A000000040200073132323631303302000255530200033633320200022D31 my $packet = Data::AMF::Packet->deserialize(decode_base64("AAAAAAABABZnZXRDbGlwSW5mby5nZXRDbGlwQWxsAAIvMQAAAB8KAAAABAIABzEyMjc2MTECAAJVUwIAAzYzMgIAAi0xCg==")); $packet->messages->[0]->{value}->[0] = $video_id; #$packet->messages->[0]->{value}->[1] = "US"; #$packet->messages->[0]->{value}->[2] = "632"; #$packet->messages->[0]->{value}->[3] = "-1"; if($self->debug) { require Data::Dumper; debug Data::Dumper::Dumper($packet); } my $data = $packet->serialize; $browser->post( "http://video.nbcuni.com/amfphp/gateway.php", Content_Type => "application/x-amf", Content => $data ); die "Failed to post to Nbc AMF gateway" unless $browser->response->is_success; debug $browser->content; # AMF fails so just regex for now my($clipurl) = $browser->content =~ /clipurl.{0,5}(nbc[^\0]+)/; my($title) = $browser->content =~ /headline.{1,3}([^\0]+)/; debug $clipurl; debug $title; $browser->get("http://video.nbcuni.com/$clipurl"); my $xml = from_xml($browser); my $video_path = $xml->{body}->{switch}->{ref}->{src}; $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 my $xml = from_xml($browser); my $app = $xml->{akamaiAppName}; my $host = $xml->{akamaiHostName}; $browser->get("http://$host/fcs/ident"); my $xml = from_xml($browser); my $ip = $xml->{ip}; my $port = "1935"; my $rtmpurl = "rtmp://$ip:$port/$app/$video_path"; return { rtmp => $rtmpurl, swfUrl => "http://www.nbc.com/[[IMPORT]]/video.nbcuni.com/outlet/extensions/inext_video_player/video_player_extension.swf?4.5.3", tcUrl => "rtmp://$ip:$port/$app?_fcs_vhost=$host", flv => title_to_filename($title) }; } 1; �������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Scivee.pm�����������������������������������0000644�0001750�0001750�00000001770�11772753754�023041� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Scivee; # horrible casing :( # for use with Scivee.tv # use strict; use FlashVideo::Utils; use HTML::Entities; sub find_video { # print title_to_filename(decode_entities("The+Algorithmic+Lens%3A+How+the+Computational+Perspective+is+Transforming+the+Sciences.mp3")); # also /asset/audio/$vid my ($self, $browser) = @_; my $title; if ($browser->content =~ /title\>([^\|]+)/) { $title = $1; } else { #$title = extract_info($browser)->{meta_title}; $title = extract_info($browser)->{title}; } my $filename = title_to_filename($title); # since I can't figure how to get the request url my $vid; if ($browser->content =~ /\/ratings\/(\d+)/) { $vid = $1; } elsif ($browser->content =~ /flashvars="id=(\d+)/) { $vid = $1; } else { # print $browser->content; die "Could not find video!"; } my $url = "http://www.scivee.tv/asset/video/$vid"; return $url, $filename; } 1; ��������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Channel4.pm���������������������������������0000644�0001750�0001750�00000012064�11772753754�023255� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. # Thanks to Nibor for his XBMC 4od plugin - this is largely a Perl port of # it. package FlashVideo::Site::Channel4; use strict; use Crypt::Blowfish_PP; use FlashVideo::Utils; use MIME::Base64; use constant TOKEN_DECRYPT_KEY => 'STINGMIMI'; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $page_url = $browser->uri->as_string; # Determine series and episode. Channel 4 sometimes have these backwards, # but as long as they differ there's less risk of overwriting or # incorrectly resuming previous episodes from the same series. my $series_and_episode; if ($browser->content =~ /<meta\ property="og:image" \ content="\S+series-(\d+)\/episode-(\d+)/x) { $series_and_episode = sprintf "S%02dE%02d", $1, $2; } # get SWF player file my $swf_player; if ($browser->content =~ /fourodPlayerFile\s+=\s+\'(4od\S+\.swf)\'/i) { $swf_player = $1; } else { $swf_player = '4odplayer-11.21.2.swf'; } # Get asset ID from 4od programme URL, which can be in two different # formats: # # http://www.channel4.com/programmes/dispatches/4od#3220372 # http://www.channel4.com/programmes/dispatches/4od/player/3269465 my $asset_id; if ($page_url =~ m'(?:4od/player/|4od[^\/]*#)(\d+)') { $asset_id = $1; } else { die "Can't get asset ID"; } # Get programme XML. my $raw_xml = $browser->get("http://ais.channel4.com/asset/$asset_id"); if (!$browser->success) { die "Couldn't get asset XML: " . $browser->status_line; } my $xml = from_xml($raw_xml); my $stream_url = $xml->{assetInfo}->{uriData}->{streamUri}; my $token = $xml->{assetInfo}->{uriData}->{token}; my $cdn = $xml->{assetInfo}->{uriData}->{cdn}; my $decoded_token = decode_4od_token($token); # RTMP authentication - varies depending on which CDN is in use. my $auth; # Different CDNs require different handling. if ($cdn eq 'll') { # Limelight my $ip = $xml->{assetInfo}->{uriData}->{ip}; my $e = $xml->{assetInfo}->{uriData}->{e}; if (defined $ip) { $auth = sprintf "e=%s&ip=%s&h=%s", $e, $ip, $decoded_token; } else { $auth = sprintf "e=%s&h=%s", $e, $decoded_token; } } else { # Akamai presumably my $fingerprint = $xml->{assetInfo}->{uriData}->{fingerprint}; my $slist = $xml->{assetInfo}->{uriData}->{slist}; $auth = sprintf "auth=%s&aifp=%s&slist=%s", $decoded_token, $fingerprint, $slist; } # Get filename to use. my $title; my @title_components = grep defined, map { $xml->{assetInfo}->{$_} } qw(brandTitle episodeTitle); if ($series_and_episode) { push @title_components, $series_and_episode; } if (@title_components) { $title = join " - ", @title_components; } my $filename = title_to_filename($title, "mp4"); # Get subtitles if necessary. if ($prefs->subtitles) { if (my $subtitles_url = $xml->{assetInfo}->{subtitlesFileUri}) { $subtitles_url = "http://ais.channel4.com$subtitles_url"; $browser->get($subtitles_url); if (!$browser->success) { info "Couldn't download 4od subtitles: " . $browser->status_line; } my $subtitles_file = title_to_filename($title, "srt"); convert_sami_subtitles_to_srt($browser->content, $subtitles_file); info "Saved subtitles to $subtitles_file"; } else { debug("Subtitles requested for '$title' but none available."); } } # Create the various options for rtmpdump. my $rtmp_url; if ($stream_url =~ /(.*?)mp4:/) { $rtmp_url = $1; } $rtmp_url =~ s{\.com/}{.com:1935/}; $rtmp_url .= "?ovpfv=1.1&$auth"; my $app; if ($stream_url =~ /.com\/(.*?)mp4:/) { $app = $1; $app .= "?ovpfv=1.1&$auth"; } my $playpath; if ($stream_url =~ /.*?(mp4:.*)/) { $playpath = $1; $playpath .= "?$auth"; } # swf url could be relocated, url_exists returns relocated url. my $swf_player_url = url_exists($browser, "http://www.channel4.com/static/programmes/asset/flash/swf/$swf_player"); if (!$swf_player_url) { die "swf url not found"; } return { flv => $filename, rtmp => $rtmp_url, flashVer => '"WIN 11,0,1,152"', swfVfy => "$swf_player_url", conn => 'Z:', playpath => $playpath, pageUrl => $page_url, app => $app, }; } sub decode_4od_token { my $encrypted_token = shift; $encrypted_token = decode_base64($encrypted_token); my $blowfish = Crypt::Blowfish_PP->new(TOKEN_DECRYPT_KEY); my $decrypted_token = ''; # Crypt::Blowfish_PP only decrypts 8 bytes at a time. my $position = 0; while ( $position < length $encrypted_token) { $decrypted_token .= $blowfish->decrypt(substr $encrypted_token, $position, 8); $position += 8; } # remove padding.. PKCS7/RFC5652.. my $npad = unpack("c", substr($decrypted_token, -1)); if ($npad > 0 && $npad < 9) { $decrypted_token = substr($decrypted_token, 0, length($decrypted_token)-$npad); } return $decrypted_token; } 1; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Sbs.pm��������������������������������������0000644�0001750�0001750�00000004372�11772753754�022353� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Sbs; use strict; use FlashVideo::Utils; use FlashVideo::JSON; use File::Basename; use HTML::Entities; use URI::Escape; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $smil; my $baseurl; my($id) = $browser->content =~ /firstVidId = '([^']*)';/; ($smil) = decode_entities($browser->content =~ /player\.releaseUrl = "([^"]*)";/); if( $id ){ ($baseurl) = $browser->content =~ m{so\.addVariable\("nielsenLaunchURL", *"([^"]*)"\);}s ; my($menu) = $browser->content =~ m{loadVideo\('([^']*)', '', [^\)]\);}s ; if( !$menu ){ $menu = $baseurl . '/video/menu/inline/id/' . $id; } else { $menu = 'http://www.sbs.com.au' . $menu; } $menu =~ s/' *\+ *firstVidId *\+ *'/$id/g; die "No menu URL found" unless $menu; $browser->get($menu); ($smil) = $browser->content =~ m{<video *name="[^"]*" *id="[^"]*" *src="([^"]*)">}s ; } die "no smil" unless $smil; $browser->get($smil); ($baseurl) = decode_entities($browser->content =~ m'<meta base="([^"]*)"/>'s); my @tmp = $browser->content =~ m'<video src="([^"]*)" system-bitrate="([^"]*)"/>'gs; my %tmp = reverse @tmp; my $filename; my $q = $prefs->{quality}; if( grep {$_ eq $q || $_ == $q || $_ == ($q * 100000)} keys(%tmp) ){ $filename = decode_entities($tmp{$q}); if(!$filename){ my @bitrates = grep {$_ == $q || $_ == ($q * 100000)} keys(%tmp); $filename = decode_entities($tmp{$bitrates[0]}); } } else { my @filenames = (); foreach (sort { $a <=> $b } keys(%tmp) ) { push @filenames, $tmp{$_}; } my $cnt = @filenames; my $num = {high => int($cnt/3)*2, medium => int($cnt/3)*1, low => int($cnt/3)*0}->{$q}; $filename = decode_entities($filenames[$num]); } die "no filenames" unless $filename; if( $baseurl =~ /^rtmp:/ ){ my($flvname) = $filename =~ m'[^/]*/(.*)'s; return { rtmp => $baseurl, playpath => $filename, flv => $flvname, swfUrl => 'http://www.sbs.com.au/vod/theplatform/core/4_4_3/swf/flvPlayer.swf', }; } elsif ($baseurl) { my $url = $baseurl . $filename; return $url, $filename; } else { return $filename, File::Basename::basename($filename); } } 1; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Videobb.pm����������������������������������0000644�0001750�0001750�00000001735�11772753754�023176� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Videobb; use strict; use FlashVideo::Utils; use FlashVideo::JSON; use MIME::Base64; sub find_video { my ($self, $browser) = @_; if($browser->status == 302) { # in case we get a redirect $browser->allow_redirects; $browser->get; } my $flash_settings_b64 = ($browser->content =~ /<param value="setting=([^"]+)" name="FlashVars">/s)[0]; my $flash_settings = decode_base64($flash_settings_b64); $browser->get($flash_settings); if (!$browser->success) { die "Couldn't download video settings: " . $browser->response->status_line; } my $settings_data = from_json($browser->content); # assuming that the last in the list is the highest res my $url = decode_base64($settings_data->{settings}{res}->[-1]->{u}); my $title = $settings_data->{settings}{video_details}{video}{title}; my $filename = title_to_filename($title); return $url, $filename; } 1; �����������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Youtu.pm������������������������������������0000644�0001750�0001750�00000000333�11772753754�022742� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Youtu; # youtu.be is just an alias for youtube; everything else is handled further up use base 'FlashVideo::Site::Youtube'; 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Mtvnservices.pm�����������������������������0000644�0001750�0001750�00000014173�11772753754�024314� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Mtvnservices; # The following should work: # - clip: http://www.thedailyshow.com/watch/wed-february-23-2011/exclusive---donald-rumsfeld-extended-interview-pt--1 # - clip: http://www.colbertnation.com/the-colbert-report-videos/381484/april-12-2011/jon-kyl-tweets-not-intended-to-be-factual-statements # - full_episode: http://www.thedailyshow.com/full-episodes/wed-february-16-2011-brian-williams # - full_episode: http://www.colbertnation.com/full-episodes/tue-march-1-2011-evan-osnos use strict; use FlashVideo::Utils; use URI::Escape; my $MTVN_URL = qr{http://\w+.mtvnservices.com/(?:\w+/)?mgid:[a-z0-9:.\-_]+}; my $MTVN_ALT_URL = qr{mgid:[a-z0-9:.\-_]+}; sub find_video { my ($self, $browser, $embed_url) = @_; my $page_url = $browser->uri->as_string; if($embed_url !~ $MTVN_URL) { if($browser->content =~ m!($MTVN_URL)!) { $embed_url = $1; } elsif($browser->content =~ m!($MTVN_ALT_URL)!) { $embed_url = "http://media.mtvnservices.com/$1"; } else { die "Unable to find embedding URL"; } } $browser->get($embed_url); die "Unable to get embed URL" unless $browser->response->code =~ /^30\d$/; my %param; my $location = $browser->response->header("Location"); for(split /&/, (split /\?/, $location)[-1]) { my($n, $v) = split /=/; $param{$n} = uri_unescape($v); } die "No config_url/id found\n" unless $param{CONFIG_URL}; $browser->get($param{CONFIG_URL}); my $xml = from_xml_urlfix($browser); if($xml->{player}->{feed} && !ref $xml->{player}->{feed}) { my $feed = uri_unescape($xml->{player}->{feed}); $feed =~ s/\{([^}]+)\}/$param{$1}/g; $browser->get($feed); return $self->handle_feed($browser->content, $browser, $page_url, $param{uri}); } elsif(ref $xml->{player}->{feed}->{rss}) { # We must already have a feed embedded.. return $self->handle_feed($xml->{player}->{feed}->{rss}, $browser, $page_url, $param{uri}); } else { die "Unable to find feed\n"; } } sub handle_full_episode { my($self, $items, $filename, $browser, $page_url, $uri) = @_; my @rtmpdump_commands; debug "Handling full episode"; foreach (@$items) { my $item = $_; my $affect_counters = (grep { $_->{scheme} eq "urn:mtvn:affect_counters" } @{$item->{"media:group"}->{"media:category"}})[0]; my $iscommercial = 0; if (defined $affect_counters && $affect_counters->{content} eq 'false') { $iscommercial = 1; } # I suppose we could add a setting to "enable" commercials, but for someone reason every rtmp download, they fail at 99%. # if ($isepisodesegment && !$iscommercial) { if (!$iscommercial) { my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url}; die "Unable to find mediagen URL\n" unless $mediagen_url; $browser->get($mediagen_url); my $xml = from_xml_urlfix($browser); my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY' ? @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition}; $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY'; my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src}; my $mediagen_id; if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){ $mediagen_id = $1; } else { $mediagen_id = $mediagen_url; } # I want to follow redirects now. $browser->allow_redirects; push @rtmpdump_commands, { flv => title_to_filename($item->{"media:group"}->{"media:title"}), rtmp => $url, pageUrl => $item->{"link"}, swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id) }; } } return \@rtmpdump_commands; } sub handle_clip { my($self, $items, $filename, $browser, $page_url, $uri) = @_; debug "Handling clip"; my $item = ref $items eq 'ARRAY' ? (grep { $_->{guid}->{content} eq $uri } @$items)[0] : $items; my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url}; die "Unable to find mediagen URL\n" unless $mediagen_url; $browser->get($mediagen_url); my $xml = from_xml_urlfix($browser); my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY' ? @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition}; $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY'; my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src}; my $mediagen_id; if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){ $mediagen_id = $1; } else { $mediagen_id = $mediagen_url; } # I want to follow redirects now. $browser->allow_redirects; if($url =~ /^rtmpe?:/) { return { flv => $filename, rtmp => $url, pageUrl => $page_url, swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id) }; } else { return $url, $filename; } } sub handle_feed { my($self, $feed, $browser, $page_url, $uri) = @_; my $xml = ref $feed ? $feed : from_xml_urlfix($feed); my $filename = title_to_filename($xml->{channel}->{title}); my $items = $xml->{channel}->{item}; my $categories = ref $items eq 'ARRAY' ? @$items[0]->{"media:group"}->{"media:category"} : $items->{"media:group"}->{"media:category"}; if (ref $categories eq 'ARRAY' && ( (grep { $_->{scheme} eq "urn:mtvn:display:seo" } @$categories)[0]->{content} eq "" || (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "Full Episode" || (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "full_episode_segment")) { return $self->handle_full_episode($items, $filename, $browser, $page_url, $uri); } else { return $self->handle_clip($items, $filename, $browser, $page_url, $uri); } } sub can_handle { my($self, $browser, $url) = @_; return $browser->content =~ /mtvnservices\.com/i; } # Filter to avoid XML::Simple "not well-formed (invalid token)" error # caused by '&' instead of '&' inside url="..." values. sub from_xml_urlfix { my($xmltext) = @_; $xmltext =~ s/&(?!amp;)/&/g; # too lax? return from_xml($xmltext); } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Xhamster.pm���������������������������������0000644�0001750�0001750�00000001324�11772753754�023411� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Xhamster; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser) = @_; my $server; if ($browser->content =~ m{'srv': '(http://[^'"]+)'}) { $server = $1; } else { die "Couldn't determine xhamster server"; } my $video_file; if ($browser->content =~ m{'file': '([^'"]+\.flv)'}) { $video_file = $1; } else { die "Couldn't determine xhamster video filename"; } my $filename = title_to_filename(extract_title($browser)); my $url = sprintf "%s/flv2/%s", $server, $video_file; # I want to follow redirects now $browser->allow_redirects; return $url, $filename; } 1; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Thirteen.pm���������������������������������0000644�0001750�0001750�00000004061�11772753754�023401� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Thirteen; use strict; use FlashVideo::Utils; use FlashVideo::JSON; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $iframe; if ($browser->content =~ /<iframe src="([^"]*)" /) { $iframe = $1; } else { die "Couln't find iframe in " . $browser->uri->as_string; } my $url = 'http://www.thirteen.org' . $iframe; $browser->get($url); if (!$browser->success) { die "Couldn't download iframe $url: " . $browser->response->status_line; } # my $mediaID; # if ($browser->content =~ /var episodeMediaID = "([^"]*)";/) { # $mediaID = $1; # } else { # die "Couldn't find mediaID $url"; # } # my $feed_url; # if ($browser->content =~ /var feedURL = "([^"]*)" + episodeMediaID + "([^"]*)";/) { # $feed_url = $1 . $mediaID;# . $2; # } else { # $feed_url = "http://feeds.theplatform.com/ps/JSON/PortalService/2.2/getReleaseList?PID=vbnrH_ew_gqKA2Npq_EbJQJKqOxpBnQA&query=KeywordsSearch|" . $mediaID; # } my $pid; if ($browser->content =~ /var pid = "([^"]*)";/) { $pid = $1; } elsif ($browser->uri->as_string =~ /&pid=([^&]*)&/) { $pid = $1; } else { die "Could not find pid for $url"; } my $release_url; if ($browser->content =~ /so.addVariable\("releaseURL", "([^"]*)"+pid+"([^"]*)"\);/) { $release_url = $1 . $pid . $2; } else { $release_url = "http://release.theplatform.com/content.select?pid=" . $pid . "&format=SMIL&Tracking=true"; } $browser->get($release_url); my $rtmp_url; if ($browser->response->is_redirect) { $rtmp_url = $browser->response->header("Location"); } else { die "No redirect found for $release_url"; } $rtmp_url =~ s/<break>//; my $filename; if ($rtmp_url =~ /mp4:(.*)\.mp4$/) { $filename = title_to_filename($1); } else { $filename = title_to_filename(""); } # $browser->get($feed_url); # my $feed_data = from_json($browser->content); # debug($feed_data->{title}); return { rtmp => $rtmp_url, flv => $filename, }; } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tudou.pm������������������������������������0000644�0001750�0001750�00000020054�11772753754�022717� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package FlashVideo::Site::Tudou; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my $check_response = sub { my ( $message ) = @_; return if $browser->success; die sprintf $message, $browser->response->code; }; =for comment SD video Watch: http://www.tudou.com/programs/view/wo2YLr4sc44 Embed: http://www.tudou.com/v/wo2YLr4sc44 which redirects to: http://www.tudou.com/player/outside/player_outside.swf?iid=30599813&default_skin=http://js.tudouui.com/bin/player2/outside/Skin_outside_12.swf&autostart=false&rurl= HD video Watch: http://hd.tudou.com/program/15950/ Embed: http://www.tudou.com/v/elcIFKbSjno which redirects to: http://www.tudou.com/player/outside/player_outside.swf?iid=21170065&default_skin=http://js.tudouui.com/bin/player2/outside/Skin_outside_12.swf&autostart=false&rurl= =cut my $videoID = 0; # HD video web page URL, need to extract video ID via javascript variable if ( $embed_url =~ m`hd.tudou.com/program/\w+` ) { ( $videoID ) = ( $browser->content =~ /iid: "(\w+)"/ ); } # Otherwise, get the video from the external player URL else { # SD video web page URL, forward to embedded URL to extract location redirect if ( $embed_url =~ m`tudou.com/programs/view/(.+)$` ) { $embed_url = sprintf "http://www.tudou.com/v/%s", $1; $browser->get( $embed_url ); } # Embedded URL should be a redirect, use that as the current URL if ( $browser->response->code eq 302 and $embed_url =~ m`tudou.com/v/(.+)$` ) { $embed_url = $browser->response->header( 'Location' ); } # Video ID is in the URL if we are either at the redirected URL # or at the embedded link that sends the redirect ( $videoID ) = ( $embed_url =~ m`\.swf\?iid=(\d+)` ); } die "Couldn't extract video ID, we are out probably out of date" unless $videoID; debug "Using video ID $videoID"; # Get video info; safe keys seen: YouNeverKnowThat, IAlsoNeverKnow # but they're not even verifying either safekey or noCatch # (maybe noCatch means no cache?) $browser->get( sprintf "http://v2.tudou.com/v2/kili?safekey=%s&id=%s&noCatch=%d", 'YouNeverKnowThat', $videoID, rand( 10000 ) ); # Fallback URL in case the first one doesn't have our video information if ( not $browser->success ) { debug 'Using fallback tudou link for video info'; $browser->get( sprintf "http://v2.tudou.com/v2/cdn?safekey=%s&id=%s&noCatch=%d", 'YouNeverKnowThat', $videoID, rand( 10000 ) ); } $check_response->( "Couldn't grab video informaton from tudou, server response was %s" ); # Response is a plain XML document return parse_video_info( $browser->content ); } # Video info is in XML format sub parse_video_info { my ( $raw_xml ) = @_; =for comment SD XML structure: <v time="101300" vi="1" ch="5" nls="0" title="上海地铁里跳钢管舞" code="wo2YLr4sc44" enable="1" logo="0" band="1"> <a></a> <b> <f w="1" h="0" sha1="46c7a7a5f8953b0c7e07423bfaa7e6cc80c11ee6" size="3110483"> http://121.12.103.35/flv/030/599/453/30599453.flv?key=7b63b43d51e29716ec4a7c4a218127cb4054c3 </f> <f w="1" h="0" sha1="46c7a7a5f8953b0c7e07423bfaa7e6cc80c11ee6" size="3110483"> http://125.64.131.8/flv/030/599/453/30599453.flv?key=7b63b43d51e29716ec4a7c4a218127cb4054c3 </f> <f w="1" h="0" sha1="46c7a7a5f8953b0c7e07423bfaa7e6cc80c11ee6" size="3110483"> http://124.232.132.4/flv/030/599/453/30599453.flv?key=7b63b43d51e29716ec4a7c4a218127cb4054c3 </f> <f w="1" h="0" sha1="46c7a7a5f8953b0c7e07423bfaa7e6cc80c11ee6" size="3110483"> http://123.134.67.76/flv/030/599/453/30599453.flv?key=7b63b43d51e29716ec4a7c4a218127cb4054c3 </f> <f w="1" h="0" sha1="46c7a7a5f8953b0c7e07423bfaa7e6cc80c11ee6" size="3110483"> http://125.211.196.8/flv/030/599/453/30599453.flv?key=7b63b43d51e29716ec4a7c4a218127cb4054c3 </f> </b> </v> HD XML structure: <v time="2566570" vi="" ch="22" nls="0" title="我的青春谁做主(1-3)AA" code="elcIFKbSjno" enable="1" logo="0" band="0"> <a></a> <b> <f w="1" h="0" sha1="5aa07d5920dbc600e1d7256e2a9f90c9a3e05870" size="155830642"> http://121.12.103.43/mp4/021/170/065/21170065.f4v?key=1d0399b5a9fa36b8b7f8004a21a241cb4054c3 </f> <f w="1" h="0" sha1="5aa07d5920dbc600e1d7256e2a9f90c9a3e05870" size="155830642"> http://123.134.67.67/mp4/021/170/065/21170065.f4v?key=1d0399b5a9fa36b8b7f8004a21a241cb4054c3 </f> <f w="1" h="0" sha1="5aa07d5920dbc600e1d7256e2a9f90c9a3e05870" size="155830642"> http://124.232.132.18/mp4/021/170/065/21170065.f4v?key=1d0399b5a9fa36b8b7f8004a21a241cb4054c3 </f> <f w="1" h="0" sha1="5aa07d5920dbc600e1d7256e2a9f90c9a3e05870" size="155830642"> http://218.61.197.4/mp4/021/170/065/21170065.f4v?key=1d0399b5a9fa36b8b7f8004a21a241cb4054c3 </f> <f w="1" h="0" sha1="5aa07d5920dbc600e1d7256e2a9f90c9a3e05870" size="155830642"> http://125.211.196.4/mp4/021/170/065/21170065.f4v?key=1d0399b5a9fa36b8b7f8004a21a241cb4054c3 </f> <f w="1" h="0" sha1="b79b115953b0b999c836f294abfb1a47dc6c714a" size="107871014"> http://124.232.132.2/m4v/021/170/065/21170065.m4v?key=eaf4b1b43c1f371d7a4cb64a21a241cb4054c3 </f> <f w="1" h="0" sha1="b79b115953b0b999c836f294abfb1a47dc6c714a" size="107871014"> http://121.12.103.44/m4v/021/170/065/21170065.m4v?key=eaf4b1b43c1f371d7a4cb64a21a241cb4054c3 </f> <f w="1" h="0" sha1="b79b115953b0b999c836f294abfb1a47dc6c714a" size="107871014"> http://123.134.67.68/m4v/021/170/065/21170065.m4v?key=eaf4b1b43c1f371d7a4cb64a21a241cb4054c3 </f> <f w="1" h="0" sha1="b79b115953b0b999c836f294abfb1a47dc6c714a" size="107871014"> http://125.211.196.5/m4v/021/170/065/21170065.m4v?key=eaf4b1b43c1f371d7a4cb64a21a241cb4054c3 </f> <f w="1" h="0" sha1="b79b115953b0b999c836f294abfb1a47dc6c714a" size="107871014"> http://218.61.197.5/m4v/021/170/065/21170065.m4v?key=eaf4b1b43c1f371d7a4cb64a21a241cb4054c3 </f> </b> </v> =cut # Force the 'f' tag to be always parsed as a multi-element # even when there is only one element my $xml = from_xml($raw_xml, forcearray => [ 'f' ] ); # The video is usually available on multiple servers # and sometimes in multiple video formats my %streams; foreach my $file ( @{$xml->{b}->{f}} ) { my $url = $file->{content}; # Attempt to extract file format my ( $format ) = ( $url =~ m`http://[^/]+/([^/]+)/` ); debug "Unable to extract file format for $url" and next unless $format; push @{$streams{$format}{urls}}, $url; $streams{$format}{size} = $file->{size}; } # Acceptable streams (in preferred order): mp4, m4v, flv, phoneMp4 my $stream = ( exists $streams{mp4} ? 'mp4' : exists $streams{m4v} ? 'm4v' : exists $streams{flv} ? 'flv' : exists $streams{wwwFlv} ? 'wwwFlv' : exists $streams{f4v} ? 'f4v' : exists $streams{phoneMp4} ? 'phoneMp4' : '' ); my $stream_formats = join ', ', ( keys %streams ); die "Video is only available in unknown file formats ($stream_formats)", unless $stream; # Choose random server to download from debug "Choosing to use the $stream stream (available: $stream_formats)"; my $stream_choice = int rand( 1 + $#{$streams{$stream}{urls}} ); my $url = @{$streams{$stream}{urls}}[$stream_choice]; # Source ID, this identifies where the request is coming from my $sourceID = ( $stream eq 'flv' ? '11000' : '18000' ); $url =~ s/\?key=/?$sourceID&key=/; # Use the video title as the filename when available; always use flv # file extension though as no matter what stream format we choose, it # is still wrapped inside an flv video container my $title = $xml->{title}; my $filename = title_to_filename( $title, 'flv' ); my $stream_duration = $xml->{time}; my $stream_size = $streams{$stream}{size}; debug sprintf "%s, %d seconds, %s bytes", $title, $stream_duration / 1000, $stream_size if ( $title and $stream_duration and $stream_size ); return ( $url, $filename ); } 1; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Cartoonnetwork.pm���������������������������0000644�0001750�0001750�00000002316�11772753754�024637� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Cartoonnetwork; use strict; use FlashVideo::Utils; use POSIX(); sub find_video { my ($self, $browser, $embed_url) = @_; my $video_id; if ($browser->uri->as_string =~ /episodeID=([a-z0-9]*)/) { $video_id = $1; } $browser->get("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeSearch/getEpisodesByIDs?ids=$video_id"); my $xml = from_xml($browser); my $episodes = $xml->{episode}; my $episode = ref $episodes eq 'ARRAY' ? (grep { $_->{id} eq $video_id } @$episodes)[0] : $episodes; my $title = $episode->{title}; # as seen in http://www.cartoonnetwork.com/video/tools/js/videoConfig_videoPage.js my @gmtime = gmtime; $gmtime[1] = 15 * int($gmtime[1] / 15); my $date = POSIX::strftime("%m%d%Y%H%M", @gmtime); my $url; foreach my $key (keys (%{$episode->{segments}->{segment}})){ my $content_id = $key; $browser->post("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeservices/getVideoPlaylist", Content => "id=$content_id&r=$date" ); if ($browser->content =~ /<ref href="([^"]*)" \/>/){ $url = $1; } } return $url, title_to_filename($title); } 1; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Pennyarcade.pm������������������������������0000644�0001750�0001750�00000001135�11772753754�024047� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Pennyarcade; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my $id; my $title; if ($browser->content =~/<h2>(.*?)<\/h2>/) { $title = $1; $title =~ s/<[^>]*>//g; } if ($browser->content =~/http:\/\/blip.tv\/play\/(.*).html/) { $id = $1; } else { die "No ID found\n"; } # They actually check this... $browser->add_header("User-Agent" => "Android"); $browser->allow_redirects; return "http://blip.tv/play/$id.mp4", title_to_filename($title); } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Gorillavid.pm�������������������������������0000644�0001750�0001750�00000001660�11772753754�023715� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. #This package handles sites such as GorillaVid.in, DaClips.in and # MovPod.in package FlashVideo::Site::Gorillavid; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my $filename; for my $form ($browser->forms) { if ($form->find_input('#btn_download')){ $filename = $form->value('fname'); #extract the filename from the form info 'Submitting form to get real video page.'; $browser->request($form->click()); #submit to get the real page } } my ($url) = ($browser->content =~ /file: *"(https?:\/\/.*?)"/); #derive extension from the filename, if there is one my ($ext) = ($url =~ /(\.[a-z0-9]{2,4})$/); return $url, $filename.$ext; } sub can_handle { my($self, $browser, $url) = @_; return 1 if $url && URI->new($url)->host =~ /(gorillavid|daclips|movpod)\.in$/; } 1; ��������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Ringtv.pm�����������������������������������0000644�0001750�0001750�00000000231�11772753754�023063� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Ringtv; use strict; use base 'FlashVideo::Site::Grindtv'; 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Channel5.pm���������������������������������0000644�0001750�0001750�00000016167�11772753754�023266� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Channel5; use strict; use FlashVideo::Utils; use MIME::Base64; my $encode_rates = { "low" => 480, "medium" => 800, "medium2" => 1200, "high" => 1500 }; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $metadata = { }; my ($video_id, $player_id); # URL params, JSON, etc.. $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0]; $metadata->{videoplayer} = ($browser->content =~ /videoPlayer=ref:(C\d+)/i)[0]; $metadata->{publisherId} = ($browser->content =~ /publisherID=(\d+)/i)[0]; # <object> params $player_id ||= ($browser->content =~ /<param name=["']?playerID["']? value=["'](\d+) ?["']/i)[0]; $metadata->{videoplayer} ||= ($browser->content =~ /param name=["']?\@videoPlayer["']? value=["']?(\d+)["']?/i)[0]; $metadata->{publisherId} ||= ($browser->content =~ /param name=["']?publisherID["']? value=["']?(\d+)["']?/i)[0]; # flashVar params (e.g. <embed>) $player_id ||= ($browser->content =~ /flashVars.*playerID=(\d+)/i)[0]; # Brightcove JavaScript API if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) { $player_id = $2; } $metadata->{sessionId} = ($browser->cookie_jar->as_string =~ /session=([0-9a-f]*);/)[0]; # Support direct links to videos for my $url($browser->uri->as_string, $embed_url) { if($url =~ /(?:playerID|bcpid)=?(\d+)/i) { $player_id ||= $1; } } debug "Extracted playerId: $player_id, sessionId: $metadata->{sessionId} videoplayer: $metadata->{videoplayer} publisherId: $metadata->{publisherId} " if $player_id or $video_id; die "Unable to extract Brightcove IDs from page" unless $player_id; return $self->amfgateway($browser, $player_id, $metadata, $prefs); } sub amfgateway { my($self, $browser, $player_id, $metadata, $prefs) = @_; my $has_amf_packet = eval { require Data::AMF::Packet }; if (!$has_amf_packet) { die "Must have Data::AMF::Packet installed to download Brightcove videos"; } my $page_url = $browser->uri; my $base_url = "" . $page_url; # AMF3 incompatable between Data::AMF and Brightcove # results in Brightcove rejecting message # create message without deserialize/serialize. my $amf0_formatter = Data::AMF::Formatter->new(version =>0); my $amf3_formatter = Data::AMF::Formatter->new(version =>3); my @amf_pkt; $amf_pkt[0] = decode_base64(<<EOF1); AAMAAAABAEZjb20uYnJpZ2h0Y292ZS5leHBlcmllbmNlLkV4cGVyaWVuY2VSdW50aW1lRmFjYWRl LmdldERhdGFGb3JFeHBlcmllbmNlAAIvMQAA EOF1 $amf_pkt[2] = decode_base64(<<EOF2); CgAAAAI= EOF2 $amf_pkt[3] = $amf0_formatter->format($metadata->{sessionId}); $amf_pkt[4] = decode_base64(<<EOF3); EQpjY2NvbS5icmlnaHRjb3ZlLmV4cGVyaWVuY2UuVmlld2VyRXhwZXJpZW5jZVJlcXVlc3QhY29u dGVudE92ZXJyaWRlcwdVUkwZZXhwZXJpZW5jZUlkEVRUTFRva2VuE3BsYXllcktleRlkZWxpdmVy eVR5cGUJAwEKgQNTY29tLmJyaWdodGNvdmUuZXhwZXJpZW5jZS5Db250ZW50T3ZlcnJpZGUXY29u dGVudFR5cGUTY29udGVudElkGWNvbnRlbnRSZWZJZBtmZWF0dXJlZFJlZklkG2NvbnRlbnRSZWZJ ZHMVZmVhdHVyZWRJZBVjb250ZW50SWRzDXRhcmdldAQABX/////gAAAA EOF3 $amf_pkt[5] = $amf3_formatter->format($metadata->{videoplayer}); $amf_pkt[6] = decode_base64(<<EOF4); AQEFf////+AAAAABBhd2aWRlb1BsYXllcg== EOF4 $amf_pkt[7] = $amf3_formatter->format($base_url); $amf_pkt[8] = decode_base64(<<EOF5); BUI4gZvSwQAABgEGAQV/////4AAAAA== EOF5 my $experianceid = $amf3_formatter->format($player_id); $amf_pkt[8] = $experianceid . substr($amf_pkt[8], 7); $amf_pkt[1] = pack('n', length(join('',@amf_pkt[2..8]))); my $data = join('',@amf_pkt[0..8]); # my $packet = Data::AMF::Packet->deserialize($data); # if (defined $player_id) { # $packet->messages->[0]->{value}->[0] = "$player_id"; # } # if (ref $metadata) { # for(keys %$metadata) { # $packet->messages->[0]->{value}->[1]->{$_} = "$metadata->{$_}"; # } # } # my $data = $packet->serialize; $browser->post( "http://c.brightcove.com/services/messagebroker/amf?playerid=$player_id", Content_Type => "application/x-amf", Content => $data ); die "Failed to post to Brightcove AMF gateway" unless $browser->response->is_success; my $packet = Data::AMF::Packet->deserialize($browser->content); if($self->debug) { require Data::Dumper; # my $data1 = Data::AMF::Packet->deserialize($data); # debug Data::Dumper::Dumper($data1); debug Data::Dumper::Dumper($packet); } # renditions Array contains the rtmpe URL. if ( ref $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions} ne 'ARRAY') { die "Unexpected data from AMF gateway"; } my @found; for (@{$packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions}}) { if ($_->{defaultURL}) { push @found, $_; } } # other information returned in message. my $mediaId = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaId}; my $seasonnumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{seasonnumber}; my $episodenumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{episodenumber}; my $show = ($page_url =~ m!/shows/([^/]+)/!i)[0]; my $episode = ($page_url =~ m!/episodes/([^/]+)!i)[0]; my $filehead = $show . "_Series" . $seasonnumber; if ( $show ne $episode ) { $filehead = $filehead . "_Episode" . $episodenumber . "_" . $episode; } my $encode_rate = $encode_rates->{$prefs->{quality}}; if (! defined $encode_rate ) { $encode_rate = $prefs->{quality}; } my @rtmpdump_commands; for my $d (@found) { my $rate = ($d->{defaultURL} =~ /H264-(\d+)-16x9/i)[0]; next if $encode_rate != $rate; my $host = ($d->{defaultURL} =~ m!rtmpe://(.*?)/!)[0]; my $file = ($d->{defaultURL} =~ /^[^&]+&(.*)$/)[0]; my $app = ($d->{defaultURL} =~ m!//.*?/(.*?)/&!)[0]; my $filename = $filehead . "_" . $rate; $app .= "?videoId=$mediaId&lineUpId=&pubId=$metadata->{publisherId}&playerId=$player_id&affiliateId="; my $args = { app => $app, pageUrl => $page_url, swfVfy => "http://admin.brightcove.com/viewer/us1.24.04.08.2011-01-14072625/connection/ExternalConnection_2.swf", tcUrl => "rtmpe://$host:1935/$app", rtmp => "$d->{defaultURL}", playpath => $file, flv => "$filename.flv", }; # Use sane filename if ($d->{publisherName} and $d->{displayName}) { $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}"); } # In some cases, Brightcove doesn't use RTMP streaming - the file is # downloaded via HTTP. # if (!$d->{FLVFullLengthStreamed}) { # info "Brightcove HTTP download detected"; # return ($d->{}, $args->{flv}); # } push @rtmpdump_commands, $args; } if (@rtmpdump_commands > 1) { return \@rtmpdump_commands; } else { return $rtmpdump_commands[-1]; } } sub can_handle { my($self, $browser, $url) = @_; return 1 if $url && URI->new($url)->host =~ /\.channel5\.com$/; return $browser->content =~ /(playerI[dD]|brightcove.player.create)/ && $browser->content =~ /brightcove/i; } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Mitworld.pm���������������������������������0000644�0001750�0001750�00000001104�11772753754�023413� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Mitworld; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser) = @_; my($title) = $browser->content =~ m{id="video-meta">\s*<h2>(.*?)</h2>}s; if(!$title) { $title = extract_title($browser); $title =~ s/\|.*//; } my($host) = $browser->content =~ m{host:\s*"(.*?)"}; my($flv) = $browser->content =~ m{flv:\s*"(.*?)"}; return { rtmp => "rtmp://$host/ondemand/ampsflash/$flv?_fcs_vhost=$host", flv => title_to_filename($title) }; } 1; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tv.pm���������������������������������������0000644�0001750�0001750�00000002411�11772753754�022205� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Tv; use strict; use FlashVideo::Utils; use FlashVideo::JSON; sub find_video { my($self, $browser, $embed_url, $prefs) = @_; # this is very similar to Cbs.pm... maybe they could be merged my $pid; if ($browser->content =~ /so.addVariable\("pid", "([^"]*)"\);/) { $pid = $1; } else { die "Could not find PID for video! " . $browser->uri->as_string; } my $url = "http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&pid=$pid"; $browser->get($url); if (!$browser->success) { die "Couldn't download content.select $url: " . $browser->response->status_line; } my $xml = from_xml($browser); my $items = $xml->{body}->{ref}; my $item = ref $items eq 'ARRAY' ? (grep { $_->{src} =~ /^rtmp:\/\// } @$items)[0] : $items; my $filename = title_to_filename($item->{title}); my $playpath = ""; my $rtmpurl = $item->{src}; $rtmpurl =~ s/<break>.*//; return { flv => $filename, # playpath => $playpath, rtmp => $rtmpurl, }; } sub can_handle { my($self, $browser, $url) = @_; # Only trigger for tv.com (not all sites in the .tv TLD for example) return $browser->uri->host =~ /(^|\.)tv\.com$/; } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Fora.pm�������������������������������������0000644�0001750�0001750�00000001267�11772753754�022513� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Fora; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my($clip_id) = $browser->content =~ /clipid=(\d+)/; die "Unable to extract clipid" unless $clip_id; $browser->get("http://fora.tv/fora/fora_player_full?cid=$clip_id&h=1&b=0"); my $xml = from_xml($browser); my $filename = title_to_filename($xml->{clipinfo}->{clip_title}); my $playpath = $xml->{encodeinfo}->{encode_url}; $playpath =~ s/\.flv$//; return { flv => $filename, app => "a953/o10", rtmp => "rtmp://foratv.fcod.llnwd.net", playpath => $playpath, }; } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Zshare.pm�����������������������������������0000644�0001750�0001750�00000001443�11772753754�023054� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# A get-flash-videos module for the zshare.net website # Copyright (C) 2011 Rudolf Olah <rolah@goaugust.com> # Licensed under the GNU GPL v3 or later # Created using the instructions from: http://code.google.com/p/get-flash-videos/wiki/AddingSite package FlashVideo::Site::Zshare; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; # $browser is a WWW::Mechanize object # $embed_url will normally be the same as the page, but in the case # of embedded content it may differ. $embed_url = ($browser->content =~ /iframe src="(.*videoplayer.*?)"/i)[0]; $browser->get($embed_url); my $url = ($browser->content =~ /file:.*"(.*?)"/i)[0]; my $filename = ($browser->content =~ /<title>.*?- (.*)<\/title>/i)[0]; return $url, $filename; } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/4od.pm��������������������������������������0000644�0001750�0001750�00000004152�11772753754�022306� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::4od; # Search support for 4oD (Channel 4 On Demand) on YouTube. # Downloading is handled by FlashVideo::Site::Youtube. use strict; use FlashVideo::Utils; use URI::Escape; sub search { my ($self, $search, $type) = @_; unless(eval { from_xml("<foo/>") }) { if($type eq 'site') { die $@; } else { debug $@; return; } } # Use GData API to search # Note that 50 is the maximum value for max-results. my $gdata_template_url = "http://gdata.youtube.com/feeds/api/videos?q=%s&orderby=published&start-index=1&max-results=50&v=2"; my $search_url = sprintf $gdata_template_url, uri_escape($search); my $browser = FlashVideo::Mechanize->new(); $browser->get($search_url); if (!$browser->success) { die "Couldn't get YouTube search Atom XML: " . $browser->response->status_line(); } # XML::Simple keys on 'id' and some other things by default which is # annoying. my $xml = from_xml($browser, KeyAttr => [], ForceArray => ['entry']); # Only care about actual 4od videos, where the author starts with '4od'. # (Channel 4 uses multiple authors or usernames depending on the type of # the video, for example 4oDDrama, 4oDFood and so on.) # Can't use the "author" search because specifying multiple authors # (comma separated) does not work, contrary to the GData documentation. my @matches = map { _process_4od_result($_) } grep { $_->{author}->{name} =~ /^4oD\w+$/i } @{ $xml->{entry} }; return @matches; } sub _process_4od_result { my $feed_entry = shift; my $url = $feed_entry->{'media:group'}->{'media:player'}->{url}; $url =~ s/&feature=youtube_gdata//; my $published_date = $feed_entry->{published}; $published_date =~ s/T.*$//; # only care about date, not time my $title = $feed_entry->{'media:group'}->{'media:title'}->{content}; my $description = $feed_entry->{'media:group'}->{'media:description'}->{content}; my $result_name = "$title ($published_date)"; return { name => $result_name, url => $url, description => $description }; } 1; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Filebox.pm����������������������������������0000644�0001750�0001750�00000001517�11772753754�023212� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Filebox; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my $pause = 5; #if we don't pause, we don't get the proper video page info 'Pausing for '.$pause.' seconds (or the server won\'t respond)...'; sleep($pause); my $btn_id = 'btn_download'; #the ID of the button to submit the form for my $form ($browser->forms) { if ($form->find_input('#'.$btn_id)){ info 'Submitting form to get real video page.'; $browser->request($form->click('#'.$btn_id)); #submit to get the real page } } my ($filename) = ($browser->content =~ /product_file_name=(.*?)[&'"]/); my ($url) = ($browser->content =~ /product_download_url=(.*?)[&'"]/); return $url, $filename; } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Sevenload.pm��������������������������������0000644�0001750�0001750�00000001730�11772753754�023537� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Sevenload; use strict; use FlashVideo::Utils; use HTML::Entities; use URI::Escape; sub find_video { my ($self, $browser) = @_; die "Could not find configPath" unless $browser->content =~ /configPath=([^"']+)/; my $configpath = uri_unescape(decode_entities($1)); $browser->get($configpath); my $config = from_xml($browser); my($title, $location); eval { my $item = $config->{playlists}->{playlist}->{items}->{item}; $title = title_to_filename($item->{title}); my $streams = $item->{videos}->{video}->{streams}->{stream}; $streams = [ $streams ] unless ref $streams eq 'ARRAY'; # Attempt to get the highest definition content $location = (sort { $b->{width} <=> $a->{width} } @$streams)[0] ->{locations}->{location}->{content}; }; return $location, $title if $location; die "Unable to get stream location" . ($@ ? ": $@" : ""); } 1; ����������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Msn.pm��������������������������������������0000644�0001750�0001750�00000000223�11772753754�022350� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Msn; use strict; use base 'FlashVideo::Site::Bing'; 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Break.pm������������������������������������0000644�0001750�0001750�00000003053�11772753754�022643� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Break; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my($self, $browser, $embed_url) = @_; # Need to get additional ID, otherwise video download returns 403 my $video_id; if ($browser->content =~ /flashVars\.icon = ["'](\w+)["']/) { $video_id = $1; } else { die "Couldn't get Break video ID"; } if($browser->content =~ /<meta name=['"]embed_video_url['"] content=["']([^'"]*)["']/) { $browser->get($1); } if(URI->new($embed_url)->host eq "embed.break.com") { $browser->get($embed_url); } if($browser->uri->host eq "embed.break.com") { # Embedded video if(!$browser->success && $browser->response->header('Location') !~ /sVidLoc/) { $browser->get($browser->response->header('Location')); } if($browser->response->header("Location") =~ /sVidLoc=([^&]+)/) { my $url = uri_unescape($1).'?'.$video_id; my $filename = title_to_filename((split /\//, $url)[-1]); return $url, $filename; } } my $path = ($browser->content =~ /sGlobalContentFilePath='([^']+)'/)[0]; my $filename = ($browser->content =~ /sGlobalFileName='([^']+)'/)[0]; die "Unable to extract path and filename" unless $path and $filename; my $video_path = ($browser->content =~ /videoPath\s*(?:',|=)\s*['"]([^'"]+)/)[0]; # I want to follow redirects now. $browser->allow_redirects; return $video_path . $path . "/" . $filename . ".flv" . "?" . $video_id, title_to_filename($filename); } 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Megaporn.pm���������������������������������0000644�0001750�0001750�00000000235�11772753754�023366� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Megaporn; use strict; use base 'FlashVideo::Site::Megavideo'; 1; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Aniboom.pm����������������������������������0000644�0001750�0001750�00000001347�11772753754�023207� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Aniboom; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; my ($id, $url, $title); if ($browser->uri->as_string =~ /\/animation-video\/(\d*)\/([^\/]*)/) { $id = $1; $title = $2; $title =~ s/-/ /g; } else { die "Could not detect video ID!"; } $browser->get("http://www.aniboom.com/animations/player/handlers/animationDetails.aspx?mode=&movieid=$id"); if ($browser->content =~ /(?:mp4|flv)=([^&]*)/) { $url = $1; $url =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; } else { die "Could not get flv/mp4 location!"; } return $url, title_to_filename($title); } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tv4play.pm����������������������������������0000644�0001750�0001750�00000003427�11772753754�023167� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Tv4play; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $vid = ($embed_url =~ /videoid=([0-9]*)/)[0]; my $smi_url = "http://premium.tv4play.se/api/web/asset/$vid/play"; my $title = ($browser->content =~ /property="og:title" content="(.*?)"/)[0]; my $flv_filename = title_to_filename($title, "flv"); $browser->get($smi_url); my $content = from_xml($browser); my $i = 0; my @dump; my $subtitle_url; for ($i = 0; $i < 5; $i++){ my $format = $content->{items}->{item}[$i]->{mediaFormat}; my $bitrate = $content->{items}->{item}[$i]->{bitrate}; my $rtmp = $content->{items}->{item}[$i]->{base}; my $mp4 = $content->{items}->{item}[$i]->{url}; @dump[$i] = { 'rtmp' => $rtmp, 'bitrate' => $bitrate, 'mp4' => $mp4, 'format' => $format }; } foreach (@dump) { if($_->{format} eq 'smi'){ $subtitle_url = $_->{mp4};} } debug "Subtitle_url: $subtitle_url"; # Subtitle not supported # if ($prefs->{subtitles} == 1) { # if (not $subtitle_url eq '') { # info "Found subtitles: $subtitle_url"; # $browser->get("$subtitle_url"); # my $srt_filename = title_to_filename($title, "srt"); # if(!eval { require XML::Simple && XML::Simple::XMLin("<foo/>") }) { # die "Must have XML::Simple to download " . caller =~ /::([^:])+$/ . " videos\n"; # } # convert_sami_subtitles_to_srt($browser->content, $srt_filename); # } else { # info "No subtitles found!"; # } # } return { rtmp => $dump[0]->{rtmp}, swfVfy => "http://www.tv4play.se/flash/tv4playflashlets.swf", playpath => $dump[0]->{mp4}, flv => $flv_filename }; } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tou.pm��������������������������������������0000644�0001750�0001750�00000010746�11772753754�022375� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. # tou.tv # # Reverse-engineering details at http://store-it.appspot.com/tou/tou.html # by Sylvain Fourmanoit # # un grand merci a Sylvain qui a tout debrousaille! # # Stavr0 # package FlashVideo::Site::Tou; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my ($self, $browser) = @_; # Get the video ID # on cherche: "idMedia":"T7AYXvq2l5DZy578Zj_c0LGWurfWkQs_" my $video_id; if ($browser->content =~ /"idMedia":"(\w+)"/i) { $video_id = $1; } debug "Video ID = " . $video_id; die "Couldn't find TOU.TV video ID" unless $video_id; my $filename; # on cherche: <meta content="les-chefs" name="src.emission" /> if ($browser->content =~ /<meta\s+content="(\S+)"\s+name="\w+.emission"/i) { $filename = $1 ; } # on cherche: <meta content="1513429386.S03E02" name="ProfilingEmisodeToken" if ($browser->content =~ /<meta\s+content="(\S+)"\s+name="ProfilingEmisodeToken"/i) { my $episode = $1; if($episode =~ /\S+\.(\S+)/) { $episode = $1; } $filename = $filename . "." . $episode ; } debug "Filename = " . $filename; # On va chercher le XML qui contient le lien RTMP # $browser->get("http://release.theplatform.com/content.select?pid=$video_id"); die "Couldn't download TOU.TV XML: " . $browser->response->status_line if !$browser->success; # on cherche: rtmp://medias-flash.tou.tv/ondemand/?auth=daEdwc5 etc...52_hr.mov my $url; if ($browser->content =~ /(rtmp:[^\<]+)/i) { $url = uri_unescape($1); } debug "URL = " . $url; # on cherche: auth=daEdrbRdbbtcYbUb3bQbzacdOaIbNczbva9-blS.uA-cOW-9rqBvkLqxBB my $auth; if ($url =~ /auth=([^&]+)/i) { $auth = uri_unescape($1); } debug "AUTH = " . $auth; # on decoupe a partir de 'ondemand/' my $app; if ($url =~ /(ondemand\/.+)/i) { $app = uri_unescape($1); } debug "APP = " . $app; # on decoupe apres <break> my $playpath; if ($url =~ /<break>(.+)/i) { $playpath = uri_unescape($1); } debug "PLAYPATH = " . $playpath; =for comment # et ca donne.... # # rtmpdump.exe # --app ondemand/?auth=daEcCamaRcPbCczdabkaRdkbSa8b8aec7bl-blS.4u-cOW-aqpyxlDpFCA&aifp=v0001&slist=002/MOV/HR/2010-03-29_CA_0052_hr;002/MOV/MR/2010-03-29_CA_0052_mr;002/MOV/BR/2010-03-29_CA_0052_br # --flashVer WIN 10,0,22,87 # --swfVfy http://static.tou.tv/lib/ThePlatform/4.1.2/swf/flvPlayer.swf # --auth daEcCamaRcPbCczdabkaRdkbSa8b8aec7bl-blS.4u-cOW-aqpyxlDpFCA # --tcUrl rtmp://medias-flash.tou.tv/ondemand/?auth=daEcCamaRcPbCczdabkaRdkbSa8b8aec7bl-blS.4u-cOW-aqpyxlDpFCA&aifp=v0001&slist=002/MOV/HR/2010-03-29_CA_0052_hr;002/MOV/MR/2010-03-29_CA_0052_mr;002/MOV/BR/2010-03-29_CA_0052_br # --rtmp rtmp://medias-flash.tou.tv/ondemand/?auth=daEcCamaRcPbCczdabkaRdkbSa8b8aec7bl-blS.4u-cOW-aqpyxlDpFCA&aifp=v0001&slist=002/MOV/HR/2010-03-29_CA_0052_hr;002/MOV/MR/2010-03-29_CA_0052_mr;002/MOV/BR/2010-03-29_CA_0052_br # --playpath mp4:002/MOV/HR/2010-03-29_CA_0052_hr.mov # -o 2010-03-29_CA_0052_hr.flv =cut return { app => $app, pageUrl => $url, swfUrl => "http://static.tou.tv/lib/ThePlatform/4.1.2/swf/flvPlayer.swf", tcUrl => $url, auth => $auth, rtmp => $url, playpath => $playpath, flv => "$filename.flv", }; } sub search { my($self, $search, $type) = @_; my $browser = FlashVideo::Mechanize->new; $browser->get("http://www.tou.tv/recherche?q=" . uri_escape($search)); return unless $browser->success; my $results = $browser->content; =for comment <a href="/les-invincibles" id="MainContent_ctl00_ResultsEmissionsRepeater_TousLesEpisodesLink_0" class="tousEpisodes"></a> <a href="/c-est-ca-la-vie" id="MainContent_ctl00_ResultsEmissionsRepeater_TousLesEpisodesLink_1" class="tousEpisodes"></a> =cut my @emissions; my @links; while($results =~ /<a\s+href="([^"]+)"\s+id="[^"]+"\s+class="([^"]+)/g) { debug $1; if($2 eq "tousEpisodes") { push @emissions, $1; } } for my $emission (@emissions) { $browser->get($emission); my $liste = $browser->content; # <a id="MainContent__ffd5dd30f7cc3406_ctl00_ctl90_DetailsViewTitreEpisodeHyperLink" class="episode" onclick="CTItem('Episode_titre',this)" href="/c-est-ca-la-vie/S2009E04"><b>+pisode 4 : Club de boxe pour Úviter le dÚcrochage scolaire </b></a> while($liste =~ /<a.+class="episode".+href="([^"]+)".+>(.+)<\/a>/g) { push @links, { name => $1, url => "http://www.tou.tv$1", description => $2 }; } } return @links; } 1; ��������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Svtplay.pm����������������������������������0000644�0001750�0001750�00000003351�11772753754�023262� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Svtplay; use strict; use warnings; use FlashVideo::Utils; use FlashVideo::JSON; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my @rtmpdump_commands; if ($browser->uri->as_string !~ m/video\/([0-9]*)/) { die "No video id found in url"; } my $video_id = $1; my $info_url = "http://www.svtplay.se/video/$video_id?output=json"; $browser->get($info_url); if (!$browser->success) { die "Couldn't download $info_url: " . $browser->response->status_line; } my $video_data = from_json($browser->content); my $name = $video_data->{context}->{title}; my $bitrate = 0; my $rtmp_url; foreach my $video (@{ $video_data->{video}->{videoReferences} }) { my $rate = int $video->{bitrate}; if ($bitrate < $rate && $video->{playerType} eq "flash") { $rtmp_url = $video->{url}; $bitrate = $rate; } } if ($prefs->{subtitles}) { if (my $subtitles_url = $video_data->{video}->{subtitleReferences}[0]->{url}) { info "Found subtitles URL: $subtitles_url"; $browser->get($subtitles_url); if (!$browser->success) { info "Couldn't download subtitles: " . $browser->status_line; } my $srt_filename = title_to_filename($name, "srt"); open my $srt_fh, '>', $srt_filename or die "Can't open subtitles file $srt_filename: $!"; binmode $srt_fh, ':utf8'; print $srt_fh $browser->content; close $srt_fh; } else { info "No subtitles found!"; } } return { flv => title_to_filename($name, "flv"), rtmp => $rtmp_url, swfVfy => "http://www.svtplay.se/public/swf/video/svtplayer-2012.15.swf", }; } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Daum.pm�������������������������������������0000644�0001750�0001750�00000007751�11772753754�022516� 0����������������������������������������������������������������������������������������������������ustar �junix���������������������������junix������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Daum; use strict; use FlashVideo::Utils; use HTML::Entities qw(decode_entities); sub find_video { my ($self, $browser) = @_; # Step 1: Get video ID my $video_id = get_video_id($browser); debug "Video ID: $video_id"; # Step 2: Get video title my $video_title = get_video_title($browser, $video_id); debug "Video title: $video_title"; # Step 3: Get video URL my $video_url = get_video_url($browser, $video_id); debug "Video URL: $video_url"; return $video_url, title_to_filename($video_title); } # Internal subroutines sub is_valid_video_id { my ($video_id) = @_; return if !defined $video_id; return if length $video_id != 12; return if $video_id !~ /\$$/xms; return 1; } sub get_video_id { my ($browser) = @_; my $singer_url = quotemeta 'http://media.daum.net/entertain/showcase/singer/'; my $singer_url_pattern = qr{^ $singer_url .* [#] (\d+) $}xmsi; if ( $browser->uri()->as_string() =~ $singer_url_pattern ) { my $id = $1; return get_video_id_for_singer($browser, $id); } # http://tvpot.daum.net/best/Top.do?from=gnb#clipid=31946003 if ( $browser->uri()->as_string() =~ /[#] clipid = (\d+)/xmsi ) { my $url = 'http://tvpot.daum.net/clip/ClipView.do?clipid=' . $1; $browser->get($url); if ( !$browser->success() ) { die "Cannot fetch the document identified by the given URL: $url\n"; } } my $document = $browser->content(); # "http://flvs.daum.net/flvPlayer.swf?vid=FlVGvam5dPM$" my $flv_player_url = quotemeta 'http://flvs.daum.net/flvPlayer.swf'; my $video_id_pattern_1 = qr{['"] $flv_player_url [?] vid = ([^'"&]+)}xmsi; # Story.UI.PlayerManager.createViewer('2oHFG_aR9uA$'); my $function_name = quotemeta 'Story.UI.PlayerManager.createViewer'; my $video_id_pattern_2 = qr{$function_name [(] '(.+?)' [)]}xms; if ( $document !~ $video_id_pattern_1 && $document !~ $video_id_pattern_2 ) { die "Cannot find video ID from the document.\n"; } my $video_id = $1; # Remove white spaces in video ID. $video_id =~ s/\s+//xmsg; die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id); return $video_id; } sub get_video_id_for_singer { my ($browser, $id) = @_; my $document = $browser->content(); # id:'16', vid:'HZYz4R8qUEU$' my $video_id_pattern = qr{id:'$id', \s* vid:'(.+?)'}xms; if ( $document !~ $video_id_pattern ) { die "Cannot find video ID from the document.\n"; } my $video_id = $1; # Remove white spaces in video ID. $video_id =~ s/\s+//xmsg; die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id); return $video_id; } sub get_video_title { my ($browser, $video_id) = @_; my $query_url = "http://tvpot.daum.net/clip/ClipInfoXml.do?vid=$video_id"; $browser->get($query_url); if ( !$browser->success() ) { die "Cannot fetch the document identified by the given URL: $query_url\n"; } my $document = $browser->content(); # <TITLE><![CDATA[Just The Way You Are]]> my $video_title_pattern = qr{ <!\[CDATA \[ (.+?) \] \]> }xmsi; if ( $document !~ $video_title_pattern ) { die "Cannot find video title from the document.\n"; } my $video_title = $1; # & => & $video_title = decode_entities($video_title); return $video_title; } sub get_video_url { my ($browser, $video_id) = @_; my $query_url = 'http://stream.tvpot.daum.net/fms/pos_query2.php' . '?service_id=1001&protocol=http&out_type=xml' . "&s_idx=$video_id"; $browser->get($query_url); if ( !$browser->success() ) { die "Cannot fetch the document identified by the given URL: $query_url\n"; } my $document = $browser->content(); # movieURL="http://stream.tvpot.daum.net/swxwT-/InNM6w/JgEM-E/OxDQ$$.flv" my $video_url_pattern = qr{movieURL = "(.+?)"}xmsi; if ( $document !~ $video_url_pattern ) { die "Cannot find video URL from the document.\n"; } my $video_url = $1; return $video_url; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Redbull.pm0000644000175000017500000000263211772753754023212 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Redbull; use strict; use FlashVideo::Utils; use URI; use HTML::Entities; sub find_video { my ($self, $browser, $page_url) = @_; my $video_info_url; my $host = $browser->uri->host; if ( ($browser->content =~ /data_url:\s+'([^']+)'/) or ($browser->content =~ m{displayVideoPlayer\('([^']+)'\)})) { $video_info_url = $1; $video_info_url = "http://$host$video_info_url"; } if (!$video_info_url) { die "Couldn't find video info URL"; } $browser->get($video_info_url); if ($browser->response->is_redirect) { $browser->get($browser->response->header('Location')); } if (!$browser->success) { die "Couldn't download Red Bull video info XML: " . $browser->response->status_line; } # Red Bull's XML is screwed up: # content; $xml =~ s/&//g; $xml = decode_entities($xml); my $video_info = from_xml($xml); my $file_type = "flv"; if ($video_info->{high_video_url} =~ /\.mp4$/) { $file_type = "mp4"; } return { flv => title_to_filename($video_info->{title}, $file_type), rtmp => $video_info->{high_video_url}, }; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Todaysbigthing.pm0000644000175000017500000000143011772753754024573 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Todaysbigthing; use strict; use FlashVideo::Utils; my $base = "http://www.todaysbigthing.com/betamax"; sub find_video { my ($self, $browser, $embed_url) = @_; my $id; if($browser->content =~ /item_id=(\d+)/) { $id = $1; } elsif($embed_url =~ m![/:](\d+)!) { $id = $1; } die "No ID found\n" unless $id; $browser->get("$base:$id"); my $xml = from_xml($browser); my $title = $xml->{title}; $title = extract_title($browser) if ref $title; my $filename = title_to_filename($title); my $url = $xml->{flv}; die "No FLV location" unless $url; return $url, $filename; } sub can_handle { my($self, $browser, $url) = @_; return $browser->content =~ $base; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Stickam.pm0000644000175000017500000000315711772753754023217 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Stickam; use strict; use FlashVideo::Utils; sub find_video { my($self, $browser, $embed_url, $prefs) = @_; my $perfomer_id; if ($browser->content =~ /profileUserId=(\d+)/) { $perfomer_id = $1; } else { die "Can't get performer ID"; } my $filename; if ($browser->content =~ /userName=([^&]+)/) { $filename = $1; } else { $filename = $perfomer_id; } my $stream_info_url = sprintf "http://player.stickam.com/servlet/flash/getChannel?" . "type=join&performerID=%d", $perfomer_id; $browser->get($stream_info_url); if (!$browser->success) { die "Couldn't get stream info: " . $browser->response->status_line; } my %stream_info; foreach my $pair (split /&/, $browser->content) { my ($name, $value) = split /=/, $pair; # Special handling for server IP, as multiple can be specified. if ($name eq 'freeServerIP') { $value = (split /,/, $value)[0]; } $stream_info{$name} = $value; } if ($stream_info{errorCode}) { die "Stickam returned error $stream_info{errorCode}: $stream_info{errorMessage}"; } my $rtmp_stream_url = sprintf "rtmp://%s/video_chat2_stickam_peep/%d/public/mainHostFeed", $stream_info{freeServerIP}, $stream_info{channelID}; return { rtmp => $rtmp_stream_url, flv => title_to_filename($filename), live => '', conn => [ 'O:1', "NS:channel:$perfomer_id", 'O:1', ], swfhash($browser, "http://player.stickam.com/flash/stickam/stickam_simple_video_player.swf") }; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Youtube.pm0000644000175000017500000003324211772753754023256 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Youtube; use strict; use Encode; use HTML::Entities; use FlashVideo::Utils; use FlashVideo::JSON; use URI::Escape; my @formats = ( { id => 38, resolution => [4096, 2304] }, { id => 37, resolution => [1920, 1080] }, { id => 22, resolution => [1280, 720] }, { id => 35, resolution => [854, 480] }, { id => 34, resolution => [640, 360] }, { id => 18, resolution => [480, 270] }, { id => 5, resolution => [400, 224] }, { id => 17, resolution => [176, 144] }, { id => 13, resolution => [176, 144] }, ); sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; if($embed_url !~ m!youtube\.com/watch!) { $browser->get($embed_url); if ($browser->response->header('Location') =~ m!/swf/.*video_id=([^&]+)! || $browser->content =~ m!\]*src="http://www.youtube.com/embed/([^"]+)"!i || $embed_url =~ m!/v/([-_a-z0-9]+)!i || $browser->uri =~ m!v%3D([-_a-z0-9]+)!i) { # We ended up on a embedded SWF or other redirect page $embed_url = "http://www.youtube.com/watch?v=$1"; $browser->get($embed_url); } } if (!$browser->success) { verify_age($browser, $prefs); } my $title = extract_info($browser)->{meta_title}; if (!$title and $browser->content =~ /
\s+(.+?)<\/span>/ or $browser->content =~ /
\s*
(.+?)<\/div>/) { $title = $1; } # If the page contains fmt_url_map, then process this. With this, we # don't require the 't' parameter. if ($browser->content =~ /["']fmt_url_map["']:\s{0,3}(["'][^"']+["'])/) { my $fmt_map = $1; if ($fmt_map !~ /\|/) { # $fmt_map is double escaped. We should unescape it here just # once. Be careful not to unescape ',' in the URL. $fmt_map = uri_unescape($fmt_map); } debug "Using fmt_url_map method from page ($fmt_map)"; return $self->download_fmt_map($prefs, $browser, $title, {}, @{from_json $fmt_map}); } my $video_id; if ($browser->content =~ /(?:var pageVideoId =|(?:CFG_)?VIDEO_ID'?\s*:)\s*'(.+?)'/ || $browser->content =~ /"video_id": "([^"]+)"/ || $embed_url =~ /v=([^&]+)/ || $browser->content =~ /&video_id=([^&]+)&/) { $video_id = $1; } else { check_die($browser, "Couldn't extract video ID"); } my $t; if ($browser->content =~ /\W['"]?t['"]?: ?['"](.+?)['"]/) { $t = $1; } # Try to get Youtube's info for this video - needed for some types of # video. my $video_page_url = $browser->uri->as_string; if (my %info = get_youtube_video_info($browser->clone, $video_id, $video_page_url, $t)) { if($self->debug) { require Data::Dumper; debug Data::Dumper::Dumper(\%info); } # Check for rtmp downloads if ($info{conn} =~ /^rtmp/) { # Get season and episode my ($season, $episode); if ($browser->content =~ m{]*>Season ?(\d+)}i) { $season = $1; } if ($browser->content =~ m{]*>[^<]+Ep\.?\w* ?(\d+)\W*\s*}i) { $episode = $1; } if ($season and $episode) { $title .= sprintf " S%02dE%02d", $season, $episode; } # Need flash URL for SWF verification my $swf_url; if ($browser->content =~ /SWF_URL['"] ?: ?.{0,90}?(http:\/\/[^ ]+\.swf)/) { $swf_url = $1; } elsif($browser->content =~ /swfConfig\s*=\s*(\{.*?\});/ && (my $swf = from_json($1))) { $swf_url = $swf->{url}; } elsif($browser->content =~ /src=\\['"]([^'"]+\.swf)/) { $swf_url = json_unescape($1); } else { die "Couldn't extract SWF URL"; } my $rtmp_url = $info{conn}; if($info{fmt_stream_map}) { my $fmt_stream_map = parse_youtube_format_url_map($info{fmt_stream_map}, 1); # Sort by quality... my $preferred_quality = $prefs->quality->choose(map { $fmt_stream_map->{$_->{id}} ? { resolution => $_->{resolution}, url => $fmt_stream_map->{$_->{id}} } : () } @formats); $rtmp_url = $preferred_quality->{url}; } return { flv => title_to_filename($title), rtmp => $rtmp_url, swfhash($browser, $swf_url) }; } elsif($info{fmt_url_map}) { debug "Using fmt_url_map method from info"; return $self->download_fmt_map($prefs, $browser, $title, \%info, $info{fmt_url_map}); } elsif($info{url_encoded_fmt_stream_map}) { debug "Using url_encoded_fmt_stream_map method from info"; if ($info{title}) { $title=$info{title}; } return $self->download_url_encoded_fmt_stream_map($prefs, $browser, $title, \%info, $info{url_encoded_fmt_stream_map}); } } # Try old get_video method, just incase. return download_get_video($browser, $prefs, $video_id, $title, $t); } sub download_url_encoded_fmt_stream_map { my($self, $prefs, $browser, $title, $info, $fmt_map) = @_; my $fmt_url_map = parse_youtube_url_encoded_fmt_stream_map($fmt_map); if (!$title and $browser->uri->as_string =~ m'/user/.*?#') { my $video_id = (split /\//, $browser->uri->fragment)[-1]; my %info = get_youtube_video_info($browser->clone, $video_id); $title = $info->{title}; } my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}} ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} } : () } @formats); $browser->allow_redirects; return $preferred_quality->{url}, title_to_filename($title, "mp4"); } sub parse_youtube_url_encoded_fmt_stream_map { my($raw_map) = @_;; my $map = {}; foreach my $params (split /,/, $raw_map) { my $format = ""; my $url = ""; foreach my $pair (split /&/, $params) { my ($name, $value) = split /=/, $pair; if ($name eq "itag"){ $format = $value; } elsif ($name eq "url") { $url = uri_unescape($value); } } $map->{$format} = $url; } return $map; } sub download_fmt_map { my($self, $prefs, $browser, $title, $info, $fmt_map) = @_; my $fmt_url_map = parse_youtube_format_url_map($fmt_map); if (!$title and $browser->uri->as_string =~ m'/user/.*?#') { # This is a playlist and getting the video title without the ID is # practically impossible because multiple videos are referenced in the # page. However, the encrypted (apparently) video ID is included in the # URL. my $video_id = (split /\//, $browser->uri->fragment)[-1]; my %info = get_youtube_video_info($browser->clone, $video_id); $title = $info->{title}; } # Sort by quality... my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}} ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} } : () } @formats); $browser->allow_redirects; return $preferred_quality->{url}, title_to_filename($title, "mp4"); } sub download_get_video { my($browser, $prefs, $video_id, $title, $t) = @_; my $fetcher = sub { my($url, $filename) = @_; $url = url_exists($browser->clone, $url, 1); return $url, $filename if $url; return; }; my @formats_to_try = @formats; while(my $fmt = $prefs->quality->choose(@formats_to_try)) { # Remove from the list @formats_to_try = grep { $_ != $fmt } @formats_to_try; # Try it.. my @ret = $fetcher->("http://www.youtube.com/get_video?fmt=$fmt->{id}&video_id=$video_id&t=$t", title_to_filename($title, "mp4")); return @ret if @ret; } # Otherwise try without an ID my @ret = $fetcher->("http://www.youtube.com/get_video?video_id=$video_id&t=$t", title_to_filename($title)); check_die($browser, "Unable to find video URL") unless @ret; $browser->allow_redirects; return @ret; } sub check_die { my($browser, $message) = @_; if($browser->content =~ m{class="yt-alert-content">([^<]+)}) { my $alert = $1; $alert =~ s/(^\s+|\s+$)//g; $message .= "\nYouTube: $alert"; error $message; exit 1; } else { die "$message\n"; } } sub verify_age { my($browser, $prefs) = @_; my $orig_uri = $browser->uri; if ($browser->response->code == 303 && $browser->response->header('Location') =~ m!/verify_age|/accounts/!) { my $confirmation_url = $browser->response->header('Location'); $browser->get($confirmation_url); if($browser->content =~ /has_verified=1/) { my($verify_url) = $browser->content =~ /href="(.*?has_verified=1)"/; $verify_url = decode_entities($verify_url); $browser->get($verify_url); # Great that worked, otherwise probably does want a login return if $browser->response->code == 200; } # Lame age verification page - yes, we are grown up, please just give # us the video! my $account = $prefs->account("youtube", <username and $account->password) { error "You must supply Youtube account details."; exit 1; } $browser->get("http://www.youtube.com/login"); if ($browser->response->code != 303) { die "Unexpected response from Youtube login.\n"; } my $real_login_url = $browser->response->header('Location'); $browser->get($real_login_url); $browser->form_with_fields('Email', 'Passwd'); $browser->set_fields( Email => $account->username, Passwd => $account->password, ); $browser->submit(); if ($browser->content =~ /your login was incorrect/) { error "Couldn't log you in, check your username and password."; exit 1; } elsif ($browser->response->code == 302) { # expected, next step in login process my $check_cookie_url = $browser->response->header('Location'); $browser->get($check_cookie_url); # and then another, html-only, non-http, redirection... if ($browser->content =~ /get($redirected); # If we weren't redirected to YouTube we might have a regional Google # site. if(URI->new($redirected)->host !~ /youtube/i) { if($browser->response->code == 302) { $browser->get($browser->response->header("Location")); } else { die "Did not find expected redirection"; } } } else { die "Did not find expected redirection"; } } else { die "Unexpected response during login"; } # Now we go back to the video page, hopefully logged in... $browser->get($orig_uri); # the confirmation url will always fail to show the video these days # AND it'll fail to show the button apparently. if ($browser->response->code == 303) { # this account hasn't been enabled for grownup videos yet my $real_confirmation_url = $browser->response->header('Location'); $browser->get($real_confirmation_url); if ($browser->form_with_fields('next_url', 'action_confirm')) { $browser->field('action_confirm' => 'Confirm Birth Date'); $browser->click_button(name => "action_confirm"); if ($browser->response->code != 303) { die "Unexpected response from Youtube"; } $browser->get($browser->response->header('Location')); } } } else { # Lame Youtube redirection to uk.youtube.com and so on. if ($browser->response->code == 302) { $browser->get($browser->response->header('Location')); } if ($browser->response->code == 303) { debug "Video not available (303), trying " . $browser->response->header('Location'); $browser->get($browser->response->header('Location')); } if (!$browser->success) { die "Couldn't download URL: " . $browser->response->status_line; } } } # Returns YouTube video information as key/value pairs for the specified # video ID. The page that the video appears on can also be supplied. If not # supplied, the function will create a suitable one. sub get_youtube_video_info { my ($browser, $video_id, $url, $t) = @_; $url ||= "http://www.youtube.com/watch?v=$video_id"; for my $el(qw(profilepage detailpage)) { my $video_info_url_template = "http://www.youtube.com/get_video_info?&video_id=%s&el=$el&ps=default&eurl=%s&hl=en_US&t=%s"; my $video_info_url = sprintf $video_info_url_template, uri_escape($video_id), uri_escape($url), uri_escape_utf8($t); debug "get_youtube_video_info: $video_info_url"; $browser->get($video_info_url); next unless $browser->success; my %info = parse_youtube_video_info($browser->content); next if $info{status} eq 'fail'; return %info; } error "Unable to get YouTube video information."; } # Decode form-encoded key-value pairs into a hash for convenience. sub parse_youtube_video_info { my $raw_info = shift; my %video_info; foreach my $raw_pair (split /&/, $raw_info) { my ($key, $value) = split /=/, $raw_pair; $value = uri_unescape($value); $value =~ s/\+/ /g; $video_info{$key} = $value; } return %video_info; } # Some YouTube pages contain a "fmt_url_map", a mapping of quality codes # (or "formats") to URLs from where the video can be downloaded. This # function returns a hash reference keyed on the format number. sub parse_youtube_format_url_map { my($raw_map, $param_idx) = @_; $param_idx = 0 unless defined $param_idx; my $map = {}; # Now split on comma as the record is structured like # $quality|$url,$quality|$url foreach my $pair (split /,/, $raw_map) { my ($format, @params) = split /\|/, $pair; my $url = $params[$param_idx]; # $url is double escaped so unescape again. $url = uri_unescape($url); $map->{$format} = $url; } return $map; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Tva.pm0000644000175000017500000000244311772753754022353 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. =for comment Uses TVA/Canoe-Specific way to get the brightcove metadata, then forwards to the brightcove module. TVA/Canoe live streaming expects URL of the form http://tva.canoe.ca/dws/?emission=xxxxxxx =cut package FlashVideo::Site::Tva; use strict; use FlashVideo::Utils; use base 'FlashVideo::Site::Brightcove'; sub find_video { my ($self, $browser, $embed_url) = @_; # look inside script that generates CanoeVideoStandalone object my $video_id = ($browser->content =~ /player.SetVideo.(\d+)/i)[0]; my $player_id = ($browser->content =~ /player.SetPlayer.(\d+)/i)[0]; debug "Extracted playerId: $player_id, videoId: $video_id" if $player_id or $video_id; if(!$video_id) { # Some pages use more complex video[x][3] type code.. my $video_offset = ($browser->content =~ /player.SetVideo.\w+\[(\d+)/i)[0]; $video_id = ($browser->content =~ /videos\[$video_offset\].+'(\d+)'\s*\]/)[0]; } die "Unable to extract Brightcove IDs from page" unless $player_id and $video_id; return $self->amfgateway($browser, $player_id, { videoId => $video_id, } ); } sub can_handle { my($self, $browser, $url) = @_; return $browser->content =~ /player = CanoeVideoStandalone\.create\(\);/i; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Bing.pm0000644000175000017500000000144711772753754022503 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Bing; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $count = 0; while((my $location = $browser->response->header("Location")) && $count++ < 5) { $browser->get($location); } my $title; if ($browser->content =~ /sourceFriendly:\s*'([^']+)'[\s\S]+?\s*title:\s*'([^']+)'/) { $title = "$1 - $2"; } my $url; if ($browser->content =~ /formatCode:\s*1003,\s*url:\s*'([^']+)'/) { $url = $1; # Unencode the url $url =~ s/\\x([0-9a-f]{2})/chr hex $1/egi; } die "Unable to extract video url" unless $url; # MSNBC hosted videos use 302 redirects $browser->allow_redirects; return $url, title_to_filename($title); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Divxstage.pm0000644000175000017500000000267611772753754023567 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Divxstage; use strict; use FlashVideo::Utils; use URI; sub find_video { my ($self, $browser, $embed_url) = @_; #Extract the file and filekey variables from the flash variable in the HTML my ($file) = ($browser->content =~ /flashvars.file\s*=\s*"([a-f0-9]+)"/); my ($filekey) = ($browser->content =~ /flashvars.filekey\s*=\s*"([.\-a-f0-9]+)"/); #cleanest title source is the page title my ($filename) = title_to_filename(extract_title($browser)); $filename =~ s/_-_DivxStage//i; #Construct a request to the player.api PHP interface, which returns the actual location of the file my %query_params = ( 'codes'=>'1', 'file'=>$file, 'key'=>$filekey, 'pass'=>'undefined', 'user'=>'undefined',); info "Sending query to DivxStage Player API."; my $uri = URI->new( "http://www.divxstage.eu/api/player.api.php" ); $uri->query_form(%query_params); #parse the url and title out of the response my $contents = $browser->get($uri)->content; my ($url) = ($contents =~ /url=(.*?)&/); die "Couldn't find video URL from the player API." unless $url; info "Got the real video URL: ".$url; # use the API-given title if we need $filename ||= ($contents =~ /title=(.*?)&/)[0]; #probably the most reliable source of title #fallback to a default name $filename ||= get_video_filename(); return $url, $filename; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Joemonster.pm0000644000175000017500000000761611772753754023755 0ustar junixjunix# Author: paczesiowa@gmail.com # # This plugin works for videos from www.joemonster.org using 'Monster Player' # # Most (~70%) of them are single embedded youtube videos: # http://www.joemonster.org/filmy/28773/Sposob_na_Euro_2012 # This plugin doesn't directly support them, # so get_flash_videos fallbacks to youtube method, which works just fine. # Pages with multiple youtube videos are also supported by youtube method, # but only the first embedded video is downloaded: # http://www.joemonster.org/filmy/4551/Terapia_masazem # # This plugin claims to support a page when it contains at least one video # embedded with Monster Player. # Pages with mixed providers, like this (Monster Player+youtube): # http://www.joemonster.org/filmy/5496/Kolo_Smierci # only downloads Monster Player movies, the rest is discarded, # because I don't know how to provide links AND fallback to a different method. # # There are two versions of Monster Player: # * old/fat # http://www.joemonster.org/filmy/28784/Genialny_wystep_mlodego_iluzjonisty_w_Mam_talent (single video) # http://www.joemonster.org/filmy/28693/Dave_Chappelle_w_San_Francisco_ (multi videos) # # * new/slim # http://www.joemonster.org/filmy/28372/Wszyscy_kochamy_Polske_czesc_ (single video) # # Currently multiple videos are unsupported, only the first one is downloaded, # I have no idea how to return multiple links # # About 5% of videos are embedded from external providers (different than youtube), # they should work if get_flash_videos has appropriate method. package FlashVideo::Site::Joemonster; use strict; use FlashVideo::Utils; use URI::Escape; use URI::QueryParam; # Warning! This is the only perl code I've ever written. # We have to find dummy embedded urls, that contain the real url in the file param of the dummy url # e.g. content =~ m/$new_monster_player_regex/; } sub get_new_monster_player_url { my($self, $browser) = @_; $browser->content =~ m/$new_monster_player_regex/; return URI->new($1)->query_param('file') or die "no file key in player link"; } # Old player is as easy to detect: # e.g. content =~ m/$old_monster_player_regex/; } # But harder to download, matched url redirects to url, similar to what new player matches sub get_old_monster_player_url { my($self, $browser) = @_; $browser->content =~ m/$old_monster_player_regex/; my $embedded_url = $1; $browser->get($embedded_url); my $url = $browser->uri; return URI->new($url)->query_param('file') or die "no file key in player link"; } sub can_handle { my($self, $browser, $url) = @_; return $self->is_new_monster_player($browser) || $self->is_old_monster_player($browser); } sub find_video { my($self, $browser, $url) = @_; my $real_url; if ($self->is_new_monster_player($browser)) { $real_url = $self->get_new_monster_player_url($browser); } else { $real_url = $self->get_old_monster_player_url($browser); } my $title; if ($browser->title =~ m/(.*) - Joe Monster/ ) { $title = $1; } else { $title = $browser->title; } return $real_url, title_to_filename($title); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Nasa.pm0000644000175000017500000000446311772753754022507 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Nasa; use strict; use FlashVideo::Utils; use FlashVideo::JSON; sub find_video { my ($self, $browser, $embed_url) = @_; # setup and get javascript that identifies the video server and video path my $uri = $browser->uri(); my $path = $uri->path(); $path =~ s/index\.html//; # strip the index.htm at the end of the path. $path = $path . "vmixVideoLanding2.js"; # specify the javascript src # extract the site's action and media_id from the url debug "Nasa videogallery query is " . $uri->query(); my ($media_id) = $uri->query() =~ m/media_id=(\d+)/; # Site support for NASA videogallery specifying video by media_id (at this time). die "Nasa support requires 'media_id=nnnnnnnn' in the query" unless $media_id; $uri->path($path); # Change path to javascript src $uri->query(undef()); # Remove the query info "Downloading video source instructions at " . $uri; $browser->get($uri); die "Could not locate video source" unless $browser->success(); my $videojs = $browser->content(); # content is javascript # extract the video source host my ($api_url_host) = $browser->content() =~ m{var +api_url *= *'([^']*)' *;}; die "Could not extract video server" unless $api_url_host; # extract atoken required for JSON request my ($atoken) = $browser->content() =~ m{var +atoken *= *'([^']*)' *;}; # format query to get video details in JSON my $query = 'http://' . $api_url_host . '/apis/media.php?action=getMedia&export=JSONP&media_id=' . $media_id . '&atoken=' . $atoken . '&callback=loadCurrentVideo1'; info "Downloading video details from http://" . $api_url_host; $browser->get($query); die "Could not get video details" unless $browser->success(); # Content is JSON fomatted my $result = from_json($browser->content()); # Get the video's url my $url = $result->{url}; die "Could not extract video url" unless $url; # Hack: not sure why/where the "core" in the url is mutated to "core-dl" so just hacking it here $url =~ s/\/core\//\/core-dl\//; # Get the video's title from the JSON my $filename = $result->{title}; $filename = title_to_filename($filename, "mp4"); return $url, $filename; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Mylifetime.pm0000644000175000017500000000120711772753754023722 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Mylifetime; use strict; use FlashVideo::Utils; use base 'FlashVideo::Site::Brightcove'; my $JS_RE = qr/displayFlash\(/; sub find_video { my($self, $browser, $embed_url) = @_; my($player_id, $video_id) = $browser->content =~ /$JS_RE\s*"(\d+)",\s*"(\d+)"/; die "Unable to extract video ids" unless $video_id; return $self->amfgateway($browser, $player_id, { videoId => $video_id }); } sub can_handle { my($self, $browser, $url) = @_; # can only handle videos embedded with this javascript code. return $browser->content =~ $JS_RE; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Sapo.pm0000644000175000017500000000115311772753754022520 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Sapo; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser) = @_; my ($video_url, $type); if ($browser->content =~ m{flvplayer-sapo\.swf\?file=(http://[^&"]+)}) { $video_url = $1; if ($video_url =~ m{/mov}) { $type = "mp4"; } } else { die "Couldn't extract Sapo video URL"; } (my $title = extract_title($browser)) =~ s/ - SAPO V\x{ed}deos//; my $filename = title_to_filename($title, $type); $browser->allow_redirects(1); return $video_url, $filename; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Cbsnews.pm0000644000175000017500000000105311772753754023221 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Cbsnews; use strict; use FlashVideo::Utils; use base 'FlashVideo::Site::Cnet'; sub find_video { my ($self, $browser, $embed_url) = @_; my $video_id; if($browser->content =~ /CBSVideo\.setVideoId\(["']([0-9]+)["']\)/) { $video_id = $1; } else { 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"; } return $self->get_video($browser, $video_id); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Last.pm0000644000175000017500000000125311772753754022522 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Last; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; my($artist, $id) = $embed_url =~ m{/([^/]+)/\+videos/(\d+)}; my($title) = $browser->content =~ /

([^<]+)/; die "No video ID found" unless $id; $browser->get("http://ext.last.fm/1.0/video/getplaylist.php?&vid=$id&artist=$artist"); return $browser->content =~ /([^<]+)/, title_to_filename($title); } sub can_handle { my($self, $browser, $url) = @_; # Don't trigger on YouTube IDs return $url =~ /last\.fm/ && $url =~ m{\+video/\d{2,}}; } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Msnbc.pm0000644000175000017500000000353611772753754022667 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Msnbc; use strict; use FlashVideo::Utils; sub find_video { my ($self, $browser, $embed_url) = @_; # allow 302 redirects $browser->allow_redirects; # http://today.msnbc.msn.com/id/$cat/vp/$playlist#$id # http://today.msnbc.msn.com/id/$cat/vp/#$id # http://nbcsports.msnbc.com/id/$cat/vp/$playlist#$id # http://nbcsports.msnbc.com/id/$cat/vp/#$id # http://www.msnbc.msn.com/id/$cat/$playlist#$id # http://www.msnbc.msn.com/id/$cat/#$id my $id; my $location; if ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/.+#([0-9]+)/) { $location = $1; $id = $3; } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/([0-9]+)/) { $location = $1; $id = $3; } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/.+#([0-9]+)/) { $location = $1; $id = $3; } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/#([0-9]+)/) { $location = $1; $id = $3; } die "Unable to find location and videoid" unless $location and $id; $browser->get($location . $id . '/displaymode/1219/'); # http://today.msnbc.msn.com/id/$id/displaymode/1219/ my $xml = from_xml($browser->content); my $title; my $url; if ($xml->{video}->{docid} eq $id) { $title = $xml->{video}->{title}; foreach my $media (@{$xml->{video}->{media}}) { if ($media->{type} =~ /flashVideo$/i) { $url = $media->{content}; last; #prefer http get over rtmp } elsif ($media->{type} =~ /flashVideoStream$/i) { $browser->get($media->{content}); if ($browser->content =~ /(.+)<\/FlashLink>/i) { $url = $1; #rtmp } } } } die "Unable to extract video url" unless $url; if ($url =~ /^rtmp/i) { return { rtmp => $url, flv => title_to_filename($title) }; } return $url, title_to_filename($title); } 1; get-flash-videos-1.25~git2012.06.27/lib/FlashVideo/Site/Nick.pm0000644000175000017500000000270711772753754022510 0ustar junixjunix# Part of get-flash-videos. See get_flash_videos for copyright. package FlashVideo::Site::Nick; use strict; use FlashVideo::Utils; use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; #/mgid:cms:video:spongebob.com:895944 my $page_url = $browser->uri->as_string; my $title; if($browser->content =~ //) { $title = $1; } else { $title = "nothing"; } my $cmsId; if($browser->content =~ /KIDS\.add\("cmsId", "(\d+)"\);/) { $cmsId = $1; } else { die "Couldn't get the cmsId."; } my $site; if($browser->content =~ /KIDS\.add\(["']site["'], ["']([\w\.]+)["']\);/) { $site = lc($1); } else { die "Couldn't get the site."; } my $type; if($browser->content =~ /KIDS\.add\(["']type["'], ["']([a-z]+)["']\);/) { $type = $1; } else { $type = "video"; } my $uri = "mgid:cms:$type:$site:$cmsId"; $browser->get("http://www.nick.com/dynamo/video/data/mediaGen.jhtml?mgid=$uri"); my $xml = from_xml($browser->content); my $rtmp_url = $xml->{video}->{item}[0]->{rendition}[0]->{src}; return { rtmp => $rtmp_url, flv => title_to_filename($title), pageUrl => $page_url, swfhash($browser, "http://media.nick.com/" . $uri) }; } sub can_handle { my($self, $browser) = @_; return $browser->content =~ /