#!/usr/bin/env perl ################################################# # # This file was automatically generated by utils/combine-perl.pl # You should edit the original files, not this # combined version. # # The original files are available at: # http://code.google.com/p/get-flash-videos/source/checkout # ################################################# # # 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. ##{ utils/combine-header { package main; $::SCRIPT_NAME = 'get_flash_videos'; } ##} utils/combine-header BEGIN { $INC{'FlashVideo/Site/5min.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/Utils.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Utils.pm { package FlashVideo::Utils; use strict; use Exporter;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)/; 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); sub debug(@) { my $string = "@_\n"; $string =~ s/\Q$ENV{HOME}\E/~/g; print STDERR $string if $::opt{debug}; } sub info(@) { print STDERR "@_\n" unless $::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) = @_; $type ||= "flv"; $type = substr $1, 1 if $title =~ s/(@{[EXTENSIONS]})$//; $type = substr $1, 1 if $type =~ s/(@{[EXTENSIONS]})$//; utf8::upgrade($title); if ($title =~ /&(?:\w+|#(?:\d+|x[A-F0-9]+));/) { $title = decode_entities($title); } $title =~ s/\s+/_/g; $title =~ s/[^\w\-,()&]/_/g; $title =~ s/^_+|_+$//g; # underscores at the start and end look bad 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; Win32::Registry->import(); my $local_machine; { no strict 'vars'; $local_machine = $::HKEY_LOCAL_MACHINE; } my $key = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'; $local_machine->Open($key, my $reg); 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); if ($app_properties{DisplayIcon}->[-1] =~ /\.exe$/i) { $vlc_binary = $app_properties{DisplayIcon}->[-1]; last; } } return $vlc_binary; } sub get_win_codepage { require Win32::API; if (! %Win32::API::Type::Known) { %Win32::API::Type::Known = (int => 'i'); } Win32::API->Import("kernel32", "int GetACP()"); return "cp" . GetACP(); } sub get_user_config_dir { return $^O =~ /MSWin/i ? ($ENV{APPDATA} || 'c:/windows/application data') . "/get_flash_videos" : "$ENV{HOME}/.get_flash_videos"; } 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; } 1; } ##} ./FlashVideo/Utils.pm ##{ ./FlashVideo/Site/5min.pm { package FlashVideo::Site::5min; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser) = @_; my $filename = title_to_filename(extract_info($browser)->{meta_title}); my $url = (FlashVideo::Generic->find_video($browser, $browser->uri))[0]; return $url, $filename; } 1; } ##} ./FlashVideo/Site/5min.pm BEGIN { $INC{'FlashVideo/Site/About.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/Site/Brightcove.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Brightcove.pm { package FlashVideo::Site::Brightcove; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use MIME::Base64; sub find_video { my ($self, $browser, $embed_url) = @_; my $metadata = { }; my ($video_id, $player_id); $video_id = ($browser->content =~ /(?:clip|video)Id["'\] ]*[:=]["' ]*(\d+)/i)[0]; $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0]; $player_id ||= ($browser->content =~ /content =~ /content =~ /flashVars.*playerID=(\d+)/i)[0]; $video_id ||= ($browser->content =~ /flashVars.*video(?:Player|ID)=(\d+)/i)[0]; if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) { $video_id = $1; $player_id = $2; } 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 unless $metadata->{lineupId}; 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($::opt{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", }; if ($d->{publisherName} and $d->{displayName}) { $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}"); } 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; } ##} ./FlashVideo/Site/Brightcove.pm ##{ ./FlashVideo/Site/About.pm { package FlashVideo::Site::About; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl) 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) = @_; return $browser->content =~ $JS_RE; } 1; } ##} ./FlashVideo/Site/About.pm BEGIN { $INC{'FlashVideo/Site/Amazon.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Amazon.pm { package FlashVideo::Site::Amazon; use strict; use Encode; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; my $playlist_url_template = 'http://%s/gp/mpd/getplaylist-v2/%s/%s'; sub find_video { my ($self, $browser) = @_; my $amazon_host = $browser->uri()->host(); if ($browser->content =~ /swfParams\.xmlUrl = ["'](http:.*?)["']/) { debug "Getting Amazon URL direct URL $1"; $browser->get($1); } else { my ($video_id, $session_id); if ($browser->content =~ /swfParams\.mediaObjectId = ["'](.*?)["']/) { $video_id = $1; } else { die "Couldn't find video ID / media object ID in Amazon page"; } if ($browser->content =~ /swfParams\.sessionId = ["'](.*?)["']/) { $session_id = $1; } else { die "Couldn't find session ID in Amazon page"; } my $playlist_url = sprintf($playlist_url_template, $amazon_host, $video_id, $session_id); $browser->get($playlist_url); } my ($title, @video_urls) = parse_smil_like_xml($browser->content); my $filename = title_to_filename($title); return $video_urls[0], $filename; } sub parse_smil_like_xml { my $smil = shift; die "Must have XML::Simple installed to parse SMIL" unless eval { require XML::Simple }; my $parsed_smil = eval { XML::Simple::XMLin($smil) }; if ($@) { die "Couldn't parse SMIL: $@"; } my $title; my $video_ref = $parsed_smil->{videoObject}->{smil}->{body}->{switch}->{video}; if (ref($video_ref) ne 'ARRAY') { my $id; my %videos = %{ $parsed_smil->{videoObject} }; foreach my $video (keys %videos) { next unless ref $videos{$video}; if ($videos{$video}->{index} == 0) { $id = $video; $title = $videos{$video}->{title}; last; } } $video_ref = $parsed_smil->{videoObject}->{$id}->{smil}->{body}->{switch}->{video}; } my @different_quality_videos = map { $_->{src} } sort { $b->{'system-bitrate'} <=> $a->{'system-bitrate'} } @$video_ref; $title ||= $parsed_smil->{videoObject}->{title}; if ($title !~ /\s/) { $title = uri_unescape($title); } return ($title, @different_quality_videos); } 1; } ##} ./FlashVideo/Site/Amazon.pm BEGIN { $INC{'FlashVideo/Site/Apple.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Apple.pm { package FlashVideo::Site::Apple; use strict; sub find_video { my ($self, $browser) = @_; if(!FlashVideo::Downloader->check_file($browser->content)) { my @urls = sort { ($b =~ /(\d+)p\.mov/)[0] <=> ($a =~ /(\d+)p\.mov/)[0] } $browser->content =~ /['"]([^'"]+\.mov)['"]/g; die "No .mov URLs found on page" unless @urls; $browser->get($urls[0]); } my $url = $self->handle_mov($browser); my $filename = ($url->path =~ m{([^/]+)$})[0]; return $url, $filename; } sub handle_mov { my ($self, $browser) = @_; $browser->agent("Apple iPhone OS v2.0.1 CoreMedia v1.0.0.5B108"); if($browser->content =~ /url\s*\0+[\1-,]*(.*?)\0/) { return URI->new_abs($1, $browser->uri) } else { die "Cannot find link in .mov"; } } sub can_handle { my($self, $browser, $url) = @_; return $url =~ m{apple\.com/trailers/} || $url =~ m{movies\.apple\.com}; } 1; } ##} ./FlashVideo/Site/Apple.pm BEGIN { $INC{'FlashVideo/Site/Bbc.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Bbc.pm { package FlashVideo::Site::Bbc; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $page_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download BBC videos"; } 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})(?:/|$)!) { my @gi_cmd = (qw(get_iplayer -g --pid), $1); if($browser->content =~ /buildAudioPlayer/) { 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; 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 { XML::Simple::XMLin($browser->content, KeyAttr => {item => 'kind'}) }; if ($@) { eval { my $content = $browser->content; if ($content !~ m{}) { $content .= "\n\n"; } $playlist = XML::Simple::XMLin($content, KeyAttr => {item => 'kind'}) }; if ($@) { die "Couldn't parse BBC XML playlist: $@"; } } 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"; 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)')) }; 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); if (my $redirect = $browser->response->header('Location')) { debug "BBC auth URL redirects to: $url"; $browser->get($redirect); } my $stream_auth = eval { XML::Simple::XMLin($browser->content); }; if ($@) { die "Couldn't parse BBC stream auth XML for 'secure' stream.\n" . "XML is apparently:\n" . $browser->content() . "\n" . "XML::Simple said: $@"; } 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; } ##} ./FlashVideo/Site/Bbc.pm BEGIN { $INC{'FlashVideo/Site/Blip.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Blip.pm { package FlashVideo::Site::Blip; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $base = "http://blip.tv"; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Blip videos"; } my $id; if($embed_url =~ m{flash/(\d+)}) { $id = $1; } else { $browser->get($embed_url); if($browser->response->is_redirect && $browser->response->header("Location") =~ m!(?:/|%2f)(\d+)!i) { $id = $1; } else { $id = ($browser->content =~ m!/rss/flash/(\d+)!)[0]; } } die "No ID found\n" unless $id; $browser->get("$base/rss/flash/$id"); my $xml = eval { XML::Simple::XMLin($browser->content) }; if ($@) { die "Couldn't parse Blip XML : $@"; } my $content = $xml->{channel}->{item}->{"media:group"}->{"media:content"}; my $url = ref $content eq 'ARRAY' ? $content->[0]->{url} : $content->{url}; my $filename = title_to_filename($xml->{channel}->{item}->{title}, $url); $browser->allow_redirects; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Blip.pm BEGIN { $INC{'FlashVideo/Site/Break.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Break.pm { package FlashVideo::Site::Break; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my($self, $browser, $embed_url) = @_; if(URI->new($embed_url)->host eq "embed.break.com") { $browser->get($embed_url); } if($browser->uri->host eq "embed.break.com") { 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); 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]; $browser->allow_redirects; return $video_path . $path . "/" . $filename . ".flv", title_to_filename($filename); } 1; } ##} ./FlashVideo/Site/Break.pm BEGIN { $INC{'FlashVideo/Site/Channel4.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Channel4.pm { package FlashVideo::Site::Channel4; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Channel4/4oD videos"; } my $page_url = $browser->uri->as_string; my $asset_number; if($page_url =~ /catch-up#(\d+)/) { $asset_number = $1; } else { die "Couldn't get Channel 4 asset number"; } my $metadata_url = URI->new( 'http://www.channel4.com/services/catchup-availability/asset-info/' . $asset_number . '?' . time); my $host = $metadata_url->host; my $path = $metadata_url->path_query; my $request = join "\r\n", "GET $path HTTP/1.1", "Host: $host", "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language: en-gb,en;q=0.5", "Accept-Encoding: gzip,deflate", "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7", "Connection: close", "\r\n"; my $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => 80) or die $!; print $sock $request; my $response = HTTP::Response->parse(join '', <$sock>); if(!$response->is_success) { error "Couldn't download: " . $response->status_line; error "Content:\n" . $response->content; } return _process_xml($browser, $response->content); } sub _process_xml { my($browser, $xml_string) = @_; $xml_string =~ s/(?:\r\n)?\s*[a-f0-9]{1,5}\r\n//igm; $xml_string =~ s/^\s*//s; debug $xml_string; my $xml = eval { XML::Simple::XMLin($xml_string) }; die "Couldn't parse XML: $@" if $@; my($server, $playpath); my $uriData = $xml->{assetInfo}->{uriData}; if($uriData->{streamUri} =~ m{rtmpe://([^/]+)/\w+/(.*)}) { $server = $1; $playpath = $2; } my $app = "ondemand?_fcs_vhost=$server&ovpfv=1.1&auth=$uriData->{token}&" . "aifp=$uriData->{fingerprint}&slist=$uriData->{slist}"; $server = Socket::inet_ntoa(scalar gethostbyname($server)); my $url = "rtmpe://$server:1935/$app"; return { rtmp => $url, tcUrl => $url, app => $app, playpath => $playpath, auth => $uriData->{token}, pageUrl => (split /#/, $browser->uri->as_string)[0], flv => _generate_filename($xml->{assetInfo}), swfhash($browser, "http://www.channel4.com/static/programmes/asset/flash/swf/4odplayer-4.3.2.swf"), }; } sub _generate_filename { my($asset) = @_; my $title = $asset->{brandTitle}; if($asset->{episodeTitle} =~ /\Q$title\E/i) { $title = $asset->{episodeTitle}; } else { $title .= " - $asset->{episodeTitle}"; } my $episode = ""; if($asset->{seriesNumber}) { $episode = sprintf "S%02d", $asset->{seriesNumber}; } if($asset->{episodeNumber}) { $episode .= sprintf "E%02d", $asset->{episodeNumber}; } $title .= " - $episode" if $episode; return title_to_filename($title); } sub can_handle { my($self, $browser) = @_; return $browser->content =~ /catch-up.*(\d+)/; } 1; } ##} ./FlashVideo/Site/Channel4.pm BEGIN { $INC{'FlashVideo/Site/Collegehumor.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Collegehumor.pm { package FlashVideo::Site::Collegehumor; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $base = "http://www.collegehumor.com/moogaloop"; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Collegehumor videos"; } my $id; if($browser->content =~ /clip_id=(\d+)/) { $id = $1; } elsif($embed_url =~ m![/:](\d+)!) { $id = $1; } die "No ID found\n" unless $id; $browser->get("$base/video:$id"); my $xml = eval { XML::Simple::XMLin($browser->content) }; if ($@) { die "Couldn't parse Collegehumor XML: $@"; } my $title = $xml->{video}->{caption}; $title = extract_title($browser) if ref $title; my $filename = title_to_filename($title); my $url = $xml->{video}->{file}; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Collegehumor.pm BEGIN { $INC{'FlashVideo/Site/Dailymotion.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Dailymotion.pm { package FlashVideo::Site::Dailymotion; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; if ($browser->content =~ /content.is.not.available.for.your.country/i) { error "Can't (yet) download this video because it's not available " . "in your area"; exit 1; } $browser->allow_redirects; $browser->content =~ /]*>(.*?)<\//; my $filename = title_to_filename($1); my $video; if ($browser->content =~ /"video", "([^"]+)/) { $video = uri_unescape($1); } else { if ($embed_url !~ m!/swf/!) { $browser->uri =~ m!video(?:%2F|/)([^_]+)!; $embed_url = "http://www.dailymotion.com/swf/$1"; } $browser->get($embed_url); die "Must have Compress::Zlib for embedded Dailymotion videos\n" unless eval { require Compress::Zlib; }; my $data = Compress::Zlib::uncompress(substr $browser->content, 8); $data =~ /\{\{video\}\}\{\{(.*?)\}\}/; $video = $1; if($data =~ /videotitle=([^&]+)/) { $filename = title_to_filename(uri_unescape($1)); } } die "Couldn't find video parameter." unless $video; my @streams; for(split /\|\|/, $video) { my($path, $type) = split /@@/; my($width, $height) = $path =~ /(\d+)x(\d+)/; push @streams, { width => $width, height => $height, url => URI->new_abs($path, $browser->uri)->as_string }; } my $url = (sort { $b->{width} <=> $a->{width} } @streams)[0]->{url}; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Dailymotion.pm BEGIN { $INC{'FlashVideo/Site/Ehow.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Ehow.pm { package FlashVideo::Site::Ehow; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser) = @_; my $video_id; if ($browser->content =~ /flashvars=(?:"|'|")id=(\w+)&/) { $video_id = $1; } else { die "Couldn't extract video ID from page"; } my $embed_url = "http://www.ehow.com/embedvars.aspx?isEhow=true&show_related=true&" . "from_url=" . uri_escape($browser->uri->as_string) . "&id=" . $video_id; my $title; if ($browser->content =~ / (.*?)<\/h1>/x) { $title = $1; } $browser->get($embed_url); if ($browser->content =~ /&source=(http.*?flv)&/) { return uri_unescape($1), title_to_filename($title); } else { die "Couldn't extract Flash video URL from embed page"; } } 1; } ##} ./FlashVideo/Site/Ehow.pm BEGIN { $INC{'FlashVideo/Site/Expertvillage.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Expertvillage.pm { package FlashVideo::Site::Expertvillage; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } 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; } ##} ./FlashVideo/Site/Expertvillage.pm BEGIN { $INC{'FlashVideo/Site/Flickr.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Flickr.pm { package FlashVideo::Site::Flickr; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } 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 $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Flickr videos"; } 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 = eval { XML::Simple::XMLin($browser->content) }; die "Failed parsing XML: $@" if $@; 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; } ##} ./FlashVideo/Site/Flickr.pm BEGIN { $INC{'FlashVideo/Site/Fliqz.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Fliqz.pm { package FlashVideo::Site::Fliqz; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $id; if ($browser->content =~ /content =~ /\Q$embed_url\E.*?([a-f0-9]{32})/) { $id = $1; } $browser->post("http://services.fliqz.com/mediaassetcomponentservice/20071201/service.svc", Content_Type => "text/xml; charset=utf-8", SOAPAction => '"urn:fliqz.s.mac.20071201/IMediaAssetComponentService/ad"', Referer => $embed_url, Content => _get_soap_xml($id) ); my $flv_url = ($browser->content =~ />(http:[^<]+\.flv)post("http://services.fliqz.com/LegacyServices/Services/MediaAsset/Component/R20071201/service.svc", Content_Type => "text/xml; charset=utf-8", SOAPAction => '"urn:fliqz.s.mac.20071201/IMediaAssetComponentService/ad"', Referer => $embed_url, Content => _get_soap_xml($id) ); $flv_url = ($browser->content =~ />(http:[^<]+\.flv)content =~ /]+>([^<]+)/)[0]; $filename = title_to_filename($filename); $browser->allow_redirects; return $flv_url, $filename; } sub _get_soap_xml { my $id = shift; return < $id 1F866AF1-1DB0-4864-BCA1-6236377B518F EOF } 1; } ##} ./FlashVideo/Site/Fliqz.pm BEGIN { $INC{'FlashVideo/Site/Fora.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Fora.pm { package FlashVideo::Site::Fora; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Fora videos"; } 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 = eval { XML::Simple::XMLin($browser->content) }; die "Couldn't parse Fora XML: $@" if $@; 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; } ##} ./FlashVideo/Site/Fora.pm BEGIN { $INC{'FlashVideo/Site/Freevideo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Freevideo.pm { package FlashVideo::Site::Freevideo; # .ru use strict; use Encode; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser) = @_; my $ticket; if ($browser->uri->as_string =~ /\?id=(.*?)$/) { $ticket = $1; } $browser->post( "http://freevideo.ru/video/view/url/-/" . int(rand 100_000), [ onLoad => '[type Function]', highquality => 0, getvideoinfo => 1, devid => 'LoadupFlashPlayer', after_adv => 0, before_adv => 1, frame_url => 1, 'ref' => $browser->uri->as_string, video_url => 1, ticket => $ticket, ] ); if (!$browser->success) { die "Posting to Freevideo failed: " . $browser->response->status_line(); } my $video_data = uri_unescape($browser->content); my $url; if ($video_data =~ m'vidURL=(http://.*?\.flv)') { $url = $1; } else { die "Couldn't find Freevideo URL"; } my $title; if ($video_data =~ /title=(.*?)&userNick/) { $title = $1; } $title = decode('utf-8', $title); return $url, title_to_filename($title); } 1; } ##} ./FlashVideo/Site/Freevideo.pm BEGIN { $INC{'FlashVideo/Site/Gawker.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Gawker.pm { package FlashVideo::Site::Gawker; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser) = @_; my $title = extract_title($browser); $title =~ s/^\w+\s+-\s*//; $title =~ s/\s*-\s+\w+$//; my $filename = title_to_filename($title); my $url = "http://cache." . $browser->uri->host . "/assets/video/" . ($browser->content =~ /newVideoPlayer\("([^"]+)/)[0]; return $url, $filename; } sub can_handle { my($self, $browser, $url) = @_; return $browser->content =~ /newVideoPlayer/; } 1; } ##} ./FlashVideo/Site/Gawker.pm BEGIN { $INC{'FlashVideo/Site/Google.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Google.pm { package FlashVideo::Site::Google; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser) = @_; if (!$browser->success) { $browser->get($browser->response->header('Location')); die "Couldn't download URL: " . $browser->response->status_line unless $browser->success; } my $url; if ($browser->content =~ /googleplayer\.swf\?&?videoUrl(.+?)\\x26/) { $url = uri_unescape($1); $url =~ s/\\x([A-F0-9]{2})/chr(hex $1)/egi; $url =~ s/^=//; } my $filename = title_to_filename(extract_title($browser)); $browser->allow_redirects; return $url, $filename; } sub can_handle { my($self, $browser, $url) = @_; return $browser->response->header('Location') =~ /google/i || $browser->content =~ /googleplayer\.swf/; } 1; } ##} ./FlashVideo/Site/Google.pm BEGIN { $INC{'FlashVideo/Site/Grindtv.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Grindtv.pm { package FlashVideo::Site::Grindtv; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } my %sites = ( Grindtv => "http://videos.grindtv.com/1/", Stupidvideos => "http://videos.stupidvideos.com/2/", Ringtv => "http://videos.ringtv.com/7/" ); sub find_video { my ($self, $browser, $embed_url) = @_; my $site = ($self =~ /::([^:]+)$/)[0]; my $base = $sites{$site}; my $id; if($browser->content =~ /(?:baseID|video(?:ID)?)\s*=\s*['"]?(\d+)/) { $id = $1; } die "No ID found\n" unless $id; my $title = ($browser->content =~ /name="title" content="([^"]+)/i)[0]; $title = extract_title($browser) unless $title; my $filename = title_to_filename($title); $browser->allow_redirects; my $str = sprintf "%08d", $id; my $url = $base . join("/", map { substr $str, $_*2, 2 } 0 .. 3) . "/$id.flv"; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Grindtv.pm BEGIN { $INC{'FlashVideo/Site/Last.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Last.pm { package FlashVideo::Site::Last; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } 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) = @_; return $url =~ /last\.fm/ && $url =~ m{\+video/\d{2,}}; } 1; } ##} ./FlashVideo/Site/Last.pm BEGIN { $INC{'FlashVideo/Site/Megaporn.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/Site/Megavideo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Megavideo.pm { package FlashVideo::Site::Megavideo; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; my %sites = ( Megavideo => "megavideo.com", Megaporn => "megaporn.com/video", ); sub find_video { my ($self, $browser) = @_; my $site = $sites{($self =~ /::([^:]+)$/)[0]}; my $v; if ($browser->content =~ /\.v\s*=\s*['"]([^"']+)/ || $browser->uri =~ /v=([^&]+)/ || $browser->response->header("Location") =~ /v=([^&]+)/) { $v = $1; } else { die "Couldn't extract video ID from page"; } my $xml = "http://www.$site/xml/videolink.php?v=$v"; $browser->get($xml); die "Unable to get video infomation" unless $browser->response->is_success; my $k1 = ($browser->content =~ /k1="(\d+)/)[0]; my $k2 = ($browser->content =~ /k2="(\d+)/)[0]; my $un = ($browser->content =~ /un="([^"]+)/)[0]; my $s = ($browser->content =~ /\ss="(\d+)/)[0]; my $title = uri_unescape(($browser->content =~ /title="([^"]+)/)[0]); my $filename = title_to_filename($title); my $url = "http://www$s.$site/files/" . _decrypt($un, $k1, $k2) . "/"; return $url, $filename; } sub _decrypt { my($un, $k1, $k2) = @_; my @c = split //, join "", map { substr unpack("B8", pack "h", $_), 4 } split //, $un; my @iv; my $i = 0; while($i < 384) { $k1 = ($k1 * 11 + 77213) % 81371; $k2 = ($k2 * 17 + 92717) % 192811; $iv[$i] = ($k1 + $k2) % 128; $i++; } $i = 256; while($i >= 0) { my $a = $iv[$i]; my $b = $i-- % 128; ($c[$a], $c[$b]) = ($c[$b], $c[$a]); } $i = 0; while($i < 128) { $c[$i] ^= $iv[$i + 256] & 1; $i++; } $i = 0; my $c = ""; while($i < @c) { $c .= unpack "h", pack "B8", "0000" . join "", @c[$i .. ($i + 4)]; $i += 4; } return $c; } 1; } ##} ./FlashVideo/Site/Megavideo.pm ##{ ./FlashVideo/Site/Megaporn.pm { package FlashVideo::Site::Megaporn; use strict; BEGIN { FlashVideo::Site::Megavideo->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Site::Megavideo'; 1; } ##} ./FlashVideo/Site/Megaporn.pm BEGIN { $INC{'FlashVideo/Site/Metacafe.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Metacafe.pm { package FlashVideo::Site::Metacafe; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser) = @_; my $url; if ($browser->content =~ m'mediaURL=(http.+?)&') { $url = uri_unescape($1); } else { die "Couldn't find mediaURL parameter."; } if ($browser->content =~ m'gdaKey=(.+?)&') { $url .= "?__gda__=" . uri_unescape($1); } else { } my $filename = title_to_filename(extract_title($browser)); return ($url, $filename); } 1; } ##} ./FlashVideo/Site/Metacafe.pm BEGIN { $INC{'FlashVideo/Site/Mtvnservices.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Mtvnservices.pm { package FlashVideo::Site::Mtvnservices; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; my $MTVN_URL = qr{http://\w+.mtvnservices.com/(?:\w+/)?mgid:[a-z0-9:.-_]+}; sub find_video { my ($self, $browser, $embed_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Mtvnservices videos"; } my $page_url = $browser->uri->as_string; if($embed_url !~ $MTVN_URL) { if($browser->content =~ m!($MTVN_URL)!) { $embed_url = $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 = XML::Simple::XMLin($browser->content); 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}) { return $self->handle_feed($xml->{player}->{feed}->{rss}, $browser, $page_url, $param{uri}); } else { die "Unable to find feed\n"; } } sub handle_feed { my($self, $feed, $browser, $page_url, $uri) = @_; my $xml = ref $feed ? $feed : XML::Simple::XMLin($feed); my $filename = title_to_filename($xml->{channel}->{title}); my $items = $xml->{channel}->{item}; 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); $xml = XML::Simple::XMLin($browser->content); 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}; $browser->allow_redirects; if($url =~ /^rtmpe?:/) { return { flv => $filename, rtmp => $url, pageUrl => $page_url, swfhash($browser, "http://media.mtvnservices.com/player/release/") }; } return $url, $filename; } sub can_handle { my($self, $browser) = @_; return $browser->content =~ /mtvnservices\.com/i; } 1; } ##} ./FlashVideo/Site/Mtvnservices.pm BEGIN { $INC{'FlashVideo/Site/Muzu.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Muzu.pm { package FlashVideo::Site::Muzu; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use HTML::Entities; sub find_video { my ($self, $browser) = @_; $browser->content =~ /id="trackHeading">(.*?)content =~ m'flashvars:"([^"]+)')[0]; die "Unable to extract flashvars" unless $flashvars; my %map = ( networkId => "id", assetId => "assetId", startChannel => "playlistId", ); my $playAsset = "http://www.muzu.tv/player/playAsset/?"; for(split /&/, $flashvars) { my($n, $v) = split /=/; $playAsset .= "$map{$n}=$v&" if exists $map{$n}; } $browser->get($playAsset); die "Unable to get $playAsset" if $browser->response->is_error; my $url = ($browser->content =~ /src="([^"]+)/)[0]; $url = decode_entities($url); die "Unable to find video URL" unless $url; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Muzu.pm BEGIN { $INC{'FlashVideo/Site/Mylifetime.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Mylifetime.pm { package FlashVideo::Site::Mylifetime; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl) 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) = @_; return $browser->content =~ $JS_RE; } 1; } ##} ./FlashVideo/Site/Mylifetime.pm BEGIN { $INC{'FlashVideo/Site/Nfb.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ################################################# # # This file was automatically generated by utils/combine-perl.pl # You should edit the original files, not this # combined version. # # The original files are available at: # http://code.google.com/p/get-flash-videos/source/checkout # ################################################# # Except the CCR bits, thanks to Fogerty for those. ##{ ./FlashVideo/Site/Nfb.pm { package FlashVideo::Site::Nfb; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use MIME::Base64; sub find_video { my ($self, $browser) = @_; my($mid) = $browser->content =~ /mID=(\w+)/; if (!eval { require Data::AMF::Packet; }) { die "Must have Data::AMF installed to download NFB videos"; } my $packet = decode_base64(<new->deserialize($packet); $data->messages->[0]->{value}->[1] = $data->messages->[1]->{value}->[1] = $mid; $data = $data->serialize; $browser->post( "http://www.nfb.ca/gwplayer/", Content_Type => "application/x-amf", Content => $data, ); if (!$browser->success) { die "Posting AMF to NFB failed: " . $browser->response->status_line(); } $data = $browser->content; my($title) = $data =~ m'title.{3}([^\0]+)'; my @rtmp_urls = sort { _get_quality_from_url($b) <=> _get_quality_from_url($a) } ($data =~ m'(rtmp://.*?)\0'g); if (!@rtmp_urls) { die "Didn't find any rtmp URLs in the packet, our hacky 'parsing' " . "code has probably broken"; } my $rtmp_url = $rtmp_urls[0]; my($host, $app, $playpath) = $rtmp_url =~ m'rtmp://([^/]+)/(\w+)(/[^?]+)'; if($host eq 'flash.onf.ca') { $playpath =~ s{^(/[^/]+)/}{}; $app .= $1; $playpath =~ s{\.\w+$}{}; } else { $playpath = "mp4:$playpath"; } return { flv => title_to_filename($title), rtmp => $rtmp_url, app => $app, playpath => $playpath }; } sub _get_quality_from_url { my($url) = @_; if ($url =~ m'/streams/[A-Z](\d+)([A-Z])') { my ($size, $units) = ($1, $2); $size *= 1024 if $units eq 'M'; return $size; } } 1; } ##} ./FlashVideo/Site/Nfb.pm BEGIN { $INC{'FlashVideo/Site/Nicovideo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Nicovideo.pm { package FlashVideo::Site::Nicovideo; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } 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; } ##} ./FlashVideo/Site/Nicovideo.pm BEGIN { $INC{'FlashVideo/Site/Redtube.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Redtube.pm { package FlashVideo::Site::Redtube; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use List::Util qw(sum); my @map = qw(R 1 5 3 4 2 O 7 K 9 H B C D X F G A I J 8 L M Z 6 P Q 0 S T U V W E Y N); my @sites = ( "http://j71p.redtube.com/467f9bca32b1989277b48582944f325afa3374/", "http://dl.redtube.com/_videos_t4vn23s9jc5498tgj49icfj4678/" ); sub find_video { my($self, $browser, $embed_url) = @_; my($title) = $browser->content =~ /]*>([^<]+)content =~ /hash_$_=([^&"]+)/) { my $hash = $1; $type = $_; my($split, $file) = decode_id($id); $url = "$sites[0]$split/$file.$type$hash"; last if url_exists($browser->clone, $url); } } return $url, title_to_filename($title, $type); } sub decode_id { my($id) = @_; my $split = sprintf "%0.7d", int $id / 1000; $id = sprintf "%0.7d", $id; my @id = split //, $id; my $i = 0; my $s1 = sum(split //, sum(map { $i++; $_ * $i } @id)); my @s = split //, sprintf "%0.2d", $s1; my $file = join "", map { $_->[1] ? $map[ord($id[$_->[0]]) - 48 + $s1 + $_->[1]] : $s[$_->[0]] } [3, 3], [1], [0, 2], [2, 1], [5, 6], [1, 5], [0], [4, 7], [6, 4]; return($split, $file); } 1; } ##} ./FlashVideo/Site/Redtube.pm BEGIN { $INC{'FlashVideo/Site/Ringtv.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Ringtv.pm { package FlashVideo::Site::Ringtv; use strict; BEGIN { FlashVideo::Site::Grindtv->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Site::Grindtv'; 1; } ##} ./FlashVideo/Site/Ringtv.pm BEGIN { $INC{'FlashVideo/Site/Sevenload.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Sevenload.pm { package FlashVideo::Site::Sevenload; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use HTML::Entities; use URI::Escape; sub find_video { my ($self, $browser) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Sevenload videos"; } die "Could not find configPath" unless $browser->content =~ /configPath=([^"']+)/; my $configpath = uri_unescape(decode_entities($1)); $browser->get($configpath); my $config = eval { XML::Simple::XMLin($browser->content) }; if($@) { die "Error parsing config XML: $@"; } 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'; $location = (sort { $b->{width} <=> $a->{width} } @$streams)[0] ->{locations}->{location}->{content}; }; return $location, $title if $location; die "Unable to get stream location" . ($@ ? ": $@" : ""); } 1; } ##} ./FlashVideo/Site/Sevenload.pm BEGIN { $INC{'FlashVideo/Site/Spike.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Spike.pm { package FlashVideo::Site::Spike; use strict; BEGIN { FlashVideo::Site::Mtvnservices->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Site::Mtvnservices'; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Spike videos"; } my $page_url = $browser->uri->as_string; my $config_url; if($browser->content =~ /config_url\s*=\s*["']([^"']+)/) { $config_url = $1; } elsif($browser->content =~ /(?:ifilmId|flvbaseclip)=(\d+)/) { $config_url = "/ui/xml/mediaplayer/config.groovy?ifilmId=$1"; } die "No config_url/id found\n" unless $config_url; $browser->get(uri_unescape($config_url)); my $xml = XML::Simple::XMLin($browser->content); my $feed = uri_unescape($xml->{player}->{feed}); die "Unable to find feed URL\n" unless $feed; $browser->get($feed); return $self->handle_feed($browser->content, $browser, $page_url); } 1; } ##} ./FlashVideo/Site/Spike.pm BEGIN { $INC{'FlashVideo/Site/Stupidvideos.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Stupidvideos.pm { package FlashVideo::Site::Stupidvideos; use strict; BEGIN { FlashVideo::Site::Grindtv->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Site::Grindtv'; 1; } ##} ./FlashVideo/Site/Stupidvideos.pm BEGIN { $INC{'FlashVideo/Site/Ted.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Ted.pm { package FlashVideo::Site::Ted; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser) = @_; my $url; if($browser->content =~ m{Watch this talk as high-res}) { $url = URI->new_abs($1, $browser->uri); $browser->allow_redirects; } else { die "Unable to find download link"; } my $title = extract_title($browser); $title =~ s/\s*\|.*//; my $filename = title_to_filename($title, "mp4"); return $url, $filename; } 1; } ##} ./FlashVideo/Site/Ted.pm BEGIN { $INC{'FlashVideo/Site/Theonion.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Theonion.pm { package FlashVideo::Site::Theonion; # horrible casing :( use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser) = @_; my $video_id; if ($browser->content =~ /content =~ /var videoid = ["'](\d+)["'];/) { $video_id = $1; } die "Couldn't find Onion video ID" unless $video_id; $browser->get("http://www.theonion.com/content/xml/$video_id/video"); die "Couldn't download Onion XML: " . $browser->response->status_line if !$browser->success; my ($url, @filenames) = FlashVideo::Generic->find_video($browser); my $has_xml_simple = eval { require XML::Simple }; if ($has_xml_simple) { my $video_rss = eval { XML::Simple::XMLin($browser->content); }; die "Couldn't parse The Onion XML: $@" if $@; if (my $title_from_rss = $video_rss->{channel}->{item}->[0]->{title}) { $title_from_rss = title_to_filename($title_from_rss); unshift @filenames, $title_from_rss; } } return $url, @filenames; } 1; } ##} ./FlashVideo/Site/Theonion.pm BEGIN { $INC{'FlashVideo/Site/Todaysbigthing.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Todaysbigthing.pm { package FlashVideo::Site::Todaysbigthing; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } my $base = "http://www.todaysbigthing.com/betamax"; sub find_video { my ($self, $browser, $embed_url) = @_; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Today's big thing videos"; } 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 = eval { XML::Simple::XMLin($browser->content) }; if ($@) { die "Couldn't parse Today's big thing XML: $@"; } 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; } ##} ./FlashVideo/Site/Todaysbigthing.pm BEGIN { $INC{'FlashVideo/Site/Truveo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Truveo.pm { package FlashVideo::Site::Truveo; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my($self, $browser, $embed_url) = @_; my($videourl) = $browser->content =~ /var videourl = "(.*?)"/; $videourl = $embed_url if !$videourl && $browser->uri->host eq 'xml.truveo.com'; die "videourl not found" unless $videourl; $browser->get($videourl); if($browser->content =~ /url=(http:.*?)["']/) { my $redirect = url_exists($browser, $1); $browser->get($redirect); my($package, $possible_url) = FlashVideo::URLFinder::find_package($redirect, $browser); die "Recursion detected" if $package eq __PACKAGE__; return $package->find_video($browser, $possible_url); } else { die "Redirect URL not found"; } } 1; } ##} ./FlashVideo/Site/Truveo.pm BEGIN { $INC{'FlashVideo/Site/Tudou.pm'}++; } ##{ ./FlashVideo/Site/Tudou.pm { package FlashVideo::Site::Tudou; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $check_response = sub { my ( $message ) = @_; return if $browser->success; die sprintf $message, $browser->response->code; }; die "Must have XML::Simple installed to download tudou videos" unless eval { require XML::Simple }; my $videoID = 0; if ( $embed_url =~ m`hd.tudou.com/program/\w+` ) { ( $videoID ) = ( $browser->content =~ /iid: "(\w+)"/ ); } else { if ( $embed_url =~ m`tudou.com/programs/view/(.+)$` ) { $embed_url = sprintf "http://www.tudou.com/v/%s", $1; $browser->get( $embed_url ); } if ( $browser->response->code eq 302 and $embed_url =~ m`tudou.com/v/(.+)$` ) { $embed_url = $browser->response->header( 'Location' ); } ( $videoID ) = ( $embed_url =~ m`tudou.com/player/outside/player_outside.swf\?iid=(\d+)` ); } die "Couldn't extract video ID, we are out probably out of date" unless $videoID; debug "Using video ID $videoID"; $browser->get( sprintf "http://v2.tudou.com/v2/kili?safekey=%s&id=%s&noCatch=%d", 'YouNeverKnowThat', $videoID, rand( 10000 ) ); 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" ); return parse_video_info( $browser->content ); } sub parse_video_info { my ( $raw_xml ) = @_; my $xml = eval { XML::Simple::XMLin( $raw_xml, forcearray => [ 'f' ] ) }; die "Unable to parse video info ($@)" if $@; my %streams; foreach my $file ( @{$xml->{b}->{f}} ) { my $url = $file->{content}; 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}; } my $stream = ( exists $streams{mp4} ? 'mp4' : exists $streams{m4v} ? 'm4v' : exists $streams{flv} ? 'flv' : exists $streams{phoneMp4} ? 'phoneMp4' : '' ); my $stream_formats = join ', ', ( keys %streams ); die "Video is only available in unknown file formats ($stream_formats)", unless $stream; 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]; my $sourceID = ( $stream eq 'flv' ? '11000' : '18000' ); $url =~ s/\?key=/?$sourceID&key=/; 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; } ##} ./FlashVideo/Site/Tudou.pm BEGIN { $INC{'FlashVideo/Site/Videojug.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Videojug.pm { package FlashVideo::Site::Videojug; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } my $playlist_url = "http://www.videojug.com/views/film/playlist.aspx?items=&userName=&ar=16_9&id="; sub find_video { my ($self, $browser) = @_; die "Must have XML::Simple installed to download from Videojug" unless eval { require XML::Simple }; my $interview_clip; if ($browser->uri->as_string =~ m'/interview/'i) { $playlist_url = "http://www.videojug.com/views/interview/playlist.aspx?ar=16_9&id="; $interview_clip = $browser->uri->fragment; } my $video_id; if ($browser->content =~ /get($playlist_url . $video_id); my($video_url, $filename); eval { my $xml = XML::Simple::XMLin($browser->content); my $shape = $xml->{Shapes}->{Shape}->[-1]; my $location = (grep { $shape->{Locations} =~ /\Q$_->{Name}\E/ } @{$xml->{Locations}->{Location}})[0]; my ($prefix, $title); if ($interview_clip) { ($prefix, $title) = get_prefix_and_title($xml, $interview_clip); } else { $prefix = $xml->{Items}->{Media}->{Prefix}; $title = $xml->{Items}->{Media}->{Title}; } $video_url = sprintf "%s%s__%sENG.flv", $location->{Url}, $prefix, $shape->{Code}; $filename = title_to_filename($title); }; die "Unable to retrieve/parse Videojug playlist. $@" if $@; die "Couldn't find video URL" unless $video_url; return $video_url, $filename; } sub get_prefix_and_title { my ($xml, $video_name) = @_; foreach my $media (@{ $xml->{Items}->{Media} }) { my $title = lc $media->{Title}; $title =~ s/ /-/g; $title =~ s/[^a-z0-9\-]//g; if ($title eq $video_name) { return $media->{Prefix}, $media->{Title}; } } die "Couldn't find prefix for video '$video_name'"; } 1; } ##} ./FlashVideo/Site/Videojug.pm BEGIN { $INC{'FlashVideo/Site/Videolectures.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Videolectures.pm { package FlashVideo::Site::Videolectures; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser) = @_; my $author = ($browser->content =~ /author:\s*]+>([^<]+)/s)[0]; my $title = ($browser->content =~ /

([^<]+)/)[0]; my $streamer = ($browser->content =~ /streamer:\s*["']([^"']+)/)[0]; my $playpath = ($browser->content =~ /file:\s*["']([^"']+)/)[0]; $playpath =~ s/\.flv$//; my $data = { app => (split m{/}, $streamer)[-1], rtmp => $streamer, playpath => $playpath, flv => title_to_filename("$author - $title") }; return $data; } 1; } ##} ./FlashVideo/Site/Videolectures.pm BEGIN { $INC{'FlashVideo/Site/Vimeo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Vimeo.pm { package FlashVideo::Site::Vimeo; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $base = "http://vimeo.com/moogaloop"; my $has_xml_simple = eval { require XML::Simple }; if(!$has_xml_simple) { die "Must have XML::Simple installed to download Vimeo videos"; } my $id; if($embed_url =~ /clip_id=(\d+)/) { $id = $1; } elsif($embed_url =~ m!/(\d+)!) { $id = $1; } die "No ID found\n" unless $id; $browser->get("$base/load/clip:$id/embed?param_fullscreen=1¶m_clip_id=$id¶m_show_byline=0¶m_server=vimeo.com¶m_color=cc6600¶m_show_portrait=0¶m_show_title=1"); my $xml = eval { XML::Simple::XMLin($browser->content) }; if ($@) { die "Couldn't parse Vimeo XML : $@"; } my $filename = title_to_filename($xml->{video}->{caption}); my $request_signature = $xml->{request_signature}; my $request_signature_expires = $xml->{request_signature_expires}; $browser->allow_redirects; my $url = "$base/play/clip:$id/$request_signature/$request_signature_expires/?q=sd&type=embed"; return $url, $filename; } 1; } ##} ./FlashVideo/Site/Vimeo.pm BEGIN { $INC{'FlashVideo/Site/Wat.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Wat.pm { package FlashVideo::Site::Wat; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use HTML::Entities; use URI::Escape; sub find_video { my ($self, $browser) = @_; $browser->content =~ /videoid\s*:\s*["'](\d+)/i || die "No video ID found"; my $video_id = $1; $browser->get("http://www.wat.tv/interface/contentv2/$video_id"); my $title = json_escape(($browser->content =~ /title":"(.*?)",/)[0]); my $url = json_escape(($browser->content =~ /files.*?url":"(.*?)",/)[0]); my $filename = title_to_filename($title); $browser->allow_redirects; return $url, $filename; } sub json_escape { my($s) = @_; $s =~ s/\\u([0-9a-f]{1,4})/chr hex $1/eg; $s =~ s/\\//g; return $s; } 1; } ##} ./FlashVideo/Site/Wat.pm BEGIN { $INC{'FlashVideo/Site/Xnxx.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Xnxx.pm { package FlashVideo::Site::Xnxx; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $url = ($browser->content =~ /flv_url=(.+?)&/)[0]; die "Unable to extract url" unless $url; $browser->content =~ /(?:|\s*)([^<]+)/; my $filename = title_to_filename($1, $url); return $url, $filename; } 1; } ##} ./FlashVideo/Site/Xnxx.pm BEGIN { $INC{'FlashVideo/Site/Xvideos.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Xvideos.pm { package FlashVideo::Site::Xvideos; use strict; BEGIN { FlashVideo::Site::Xnxx->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Site::Xnxx'; 1; } ##} ./FlashVideo/Site/Xvideos.pm BEGIN { $INC{'FlashVideo/Site/Youku.pm'}++; } ##{ ./FlashVideo/Site/Youku.pm { package FlashVideo::Site::Youku; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub find_video { my ($self, $browser, $embed_url) = @_; my $check_response = sub { my ( $message ) = @_; return if $browser->success; die sprintf $message, $browser->response->code; }; if ( $embed_url !~ m`^http://v.youku.com/v_show/` ) { die "Don't recognise the youku link" unless $embed_url =~ m`player.php/sid/(.+)/v\.swf` or $embed_url =~ m`qplayer\.swf\?VideoIDS=([^&]+)`; $embed_url = sprintf "http://v.youku.com/v_show/id_%s.html", $1; $browser->get( $embed_url ); } $check_response->( "Can't load the youku page, server response was %s" ); my ( $videoID ) = ( $browser->content =~ /var videoId = '(.+?)';/ ); die "Couldn't extract video ID from youku page, we are probably out of date" unless $videoID; debug "Using video ID $videoID"; $browser->get( sprintf "http://v.youku.com/player/getPlayList/VideoIDS/%s/version/5/source/video/password/?ran=%d&n=%d", $videoID, rand( 10000 ), 3 ); $check_response->( "Couldn't grab video informaton from youku, server response was %s" ); return parse_video_info( $browser, $browser->content ); } sub parse_video_info { my ( $browser, $json ) = @_; debug "Video data: $json"; my ( $shuffle_seed ) = ( $json =~ /"seed":(\d+)/ ); die "Can't find the seed value in the video info JSON" unless $shuffle_seed; my ( $streams ) = ( $json =~ /"streamtypes":\[([^\]]+)\]/ ); my $stream = ( index $streams, 'mp4' ) > 0 ? 'mp4' : 'flv'; debug "Choosing to use the $stream stream (available: $streams)"; my ( $fileID ) = ( $json =~ /"streamfileids":{"$stream":"([^"]+)"/ ); ( $fileID ) = ( $json =~ /"fileid":"([^"]+)"/ ) if not $fileID; debug "Encrypted file ID: $fileID"; my @lookup_table = shuffle_table( $shuffle_seed ); $fileID =~ s/(\d+)\*/$lookup_table[$1]/eg; debug "Decrypted file ID: $fileID (seed is $shuffle_seed)"; my $sID = sprintf "%s1%07d_00", time, rand( 10000000 ) ; my ( $keyA ) = ( $json =~ /"key1":"([^"]+)"/ ); my ( $keyB ) = ( $json =~ /"key2":"([^"]+)"/ ); my $key = sprintf "%s%x", $keyB, hex( $keyA ) ^ hex( 'a55aa5a5' ); $browser->get( sprintf "http://f.youku.com/player/getFlvPath/sid/%s/st/%s/fileid/%s?K=%s&myp=null", $sID, $stream, $fileID, $key ); my $url = $browser->response->header( 'Location' ); die "Youku rejected our attempt to get the video, we're probably out of date" unless $browser->response->code eq 302 and $url; debug "Video location is $url"; $url = "$url.$stream" unless $url =~ /$stream$/; my ( $title ) = ( $json =~ /"title":"([^"]+)"/ ); $title =~ s/\\u([a-f0-9]{4})/chr(hex $1)/egi; my $filename = get_video_filename( $stream ); $filename = title_to_filename( $title, $stream ) if $title; my ( $stream_info ) = ( $json =~ /"segs":{"$stream":\[([^\]]+)\]/ ); my ( $stream_duration ) = ( $stream_info =~ /"seconds":"([^"]+)"/ ); my ( $stream_size ) = ( $stream_info =~ /"size":"([^"]+)"/ ); debug sprintf "%s, %s seconds, %s bytes", $title, $stream_duration, $stream_size if ( $title and $stream_duration and $stream_size ); return ( $url, $filename ); } sub shuffle_table { my ( $seed ) = @_; my @lookup = split //, q`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890`; my @shuffled; while ( $#lookup > 0 ) { $seed = ( 211 * $seed + 30031 ) % 2**16; my $x = int( $seed / 2**16 * ( $#lookup + 1 ) ); push @shuffled, splice( @lookup, $x, 1 ); } return @shuffled; } 1; } ##} ./FlashVideo/Site/Youku.pm BEGIN { $INC{'FlashVideo/Site/Youtube.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Site/Youtube.pm { package FlashVideo::Site::Youtube; use strict; use Encode; use HTML::Entities; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI::Escape; sub find_video { my ($self, $browser, $embed_url) = @_; if($embed_url !~ m!youtube\.com/watch!) { $browser->get($embed_url); if ($browser->response->header('Location') =~ m!/swf/.*video_id=([^&]+)! || $embed_url =~ m!/v/([-_a-z0-9]+)!i || $browser->uri =~ m!v%3D([-_a-z0-9]+)!i) { $embed_url = "http://www.youtube.com/watch?v=$1"; $browser->get($embed_url); } } if (!$browser->success) { if ($browser->response->code == 303 && $browser->response->header('Location') =~ m!/verify_age|/accounts/!) { my $confirmation_url = $browser->response->header('Location'); print "Unfortunately, due to Youtube being lame, you have to have\n" . "an account to download this video.\n" . "Username (Google Account Email): "; chomp(my $username = ); print "Ok, need your password (will be displayed): "; chomp(my $password = ); unless ($username and $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 => $username, Passwd => $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) { my $check_cookie_url = $browser->response->header('Location'); $browser->get($check_cookie_url); if ($browser->content =~ /get($redirected); 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"; } $browser->get($embed_url); if ($browser->response->code == 303) { 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 { if ($browser->response->code == 302) { $browser->get($browser->response->header('Location')); } if (!$browser->success) { die "Couldn't download URL: " . $browser->response->status_line; } } } my $video_id; if ($browser->content =~ /(?:var pageVideoId =|(?:CFG_)?VIDEO_ID'?\s*:)\s*'(.+?)'/ || $embed_url =~ /v=([^&]+)/) { $video_id = $1; } else { die "Couldn't extract video ID"; } my $page_info = extract_info($browser); my $title; if ($page_info->{meta_title}) { $title = $page_info->{meta_title}; } elsif ($browser->content =~ /
\s+(.+?)<\/span>/ or $browser->content =~ /
\s*
(.+?)<\/div>/) { $title = $1; } my $video_page_url = $browser->uri()->as_string; my $video_info_url_template = "http://www.youtube.com/get_video_info?&video_id=%s&el=profilepage&ps=default&eurl=%s&hl=en_US"; my $video_info_url = sprintf $video_info_url_template, uri_escape($video_id), uri_escape($video_page_url); $browser->get($video_info_url); if ($browser->success) { my %info = parse_youtube_video_info($browser->content); if ($info{conn} =~ /^rtmp/) { $browser->back(); my ($season, $episode); if ($browser->content =~ m{Season ?(\d+)}) { $season = $1; } if ($browser->content =~ m{Episode ?(\d+)}) { $episode = $1; } if ($season and $episode) { $title .= sprintf " S%02dE%02d", $season, $episode; } my $swf_url; if ($browser->content =~ /SWF_URL['"] ?: ?.{0,50}?(http:\/\/[^ ]+\.swf)/) { $swf_url = $1; } else { die "Couldn't extract SWF URL"; } return { flv => title_to_filename($title), rtmp => $info{conn}, swfhash($browser, $swf_url) }; } } $browser->back(); my $t; # no idea what this parameter is but it seems to be needed if ($browser->content =~ /\W['"]?t['"]?: ?['"](.+?)['"]/) { $t = $1; } else { die "Couldn't extract mysterious t parameter"; } my $fetcher = sub { my($url, $filename) = @_; $url = url_exists($browser, $url, 1); return $url, $filename if $url; return; }; my @ret = $fetcher->("http://www.youtube.com/get_video?fmt=37&video_id=$video_id&t=$t", title_to_filename($title, "mp4")); return @ret if @ret; @ret = $fetcher->("http://www.youtube.com/get_video?fmt=22&video_id=$video_id&t=$t", title_to_filename($title, "mp4")); return @ret if @ret; @ret = $fetcher->("http://www.youtube.com/get_video?fmt=18&video_id=$video_id&t=$t", title_to_filename($title, "mp4")); return @ret if @ret; @ret = $fetcher->("http://www.youtube.com/get_video?video_id=$video_id&t=$t", title_to_filename($title)); die "Unable to find video URL" unless @ret; $browser->allow_redirects; return @ret; } 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; } 1; } ##} ./FlashVideo/Site/Youtube.pm ##{ .sitemodules { package main; } ##} .sitemodules #!/usr/bin/env perl ################################################# # # This file was automatically generated by utils/combine-perl.pl # You should edit the original files, not this # combined version. # # The original files are available at: # http://code.google.com/p/get-flash-videos/source/checkout # ################################################# # # 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. BEGIN { $INC{'FlashVideo/URLFinder.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/Mechanize.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/Downloader.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Downloader.pm { package FlashVideo::Downloader; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub new { my $class = shift; my $self = { has_readkey => eval { require Term::ReadKey } }; bless $self, $class; return $self; } sub play { my ($self, $url, $file, $browser) = @_; $self->{stream} = sub { $self->{stream} = undef; if ($^O =~ /MSWin/i and $::opt{player} eq "VLC") { if (my $vlc_binary = FlashVideo::Utils::get_vlc_exe_from_registry()) { require Win32::Process; require File::Basename; require File::Spec; $file = File::Spec->rel2abs($file); my $binary_no_path = File::Basename::basename $vlc_binary; my $binary_just_path = File::Basename::dirname $vlc_binary; my $process; Win32::Process::Create( $process, $vlc_binary, "$binary_no_path $file", 1, 32, # NORMAL_PRIORITY_CLASS $binary_just_path, ) or info "Couldn't launch VLC ($vlc_binary): " . Win32::GetLastError(); } } else { my $pid = fork; die "Fork failed" unless defined $pid; if(!$pid) { exec $self->replace_filename($::opt{player}, $file); die "Exec failed\n"; } } }; $self->download($url, $file, $browser); } sub download { my ($self, $url, $file, $browser) = @_; $self->{printable_filename} = $file; $file = $self->get_filename($file); my $mode = (-e $file) ? '>>' : '>'; my $offset; if (-e $file) { $offset = -s $file; my $response = $browser->head($url); if ($offset == $response->header('Content-Length')) { error "File $self->{printable_filename} has been fully downloaded."; $self->{stream}->() if defined $self->{stream}; return; } info "File $self->{printable_filename} already exists, seeing if resuming is supported."; if (!$response->header('Accept-Ranges')) { if(!$::opt{yes}) { error "This server doesn't explicitly support resuming.\n" . "Do you want to try resuming anyway (y/n)?"; chomp(my $answer = ); if (!$answer or lc($answer) eq 'n') { undef $offset; $mode = '>'; } } } else { info "Server supports resuming, attempting to resume."; } } open my $video_fh, $mode, $file or die $!; binmode $video_fh; $self->{fh} = $video_fh; info "Downloading $url..."; if ($offset) { $browser->add_header("Range", "bytes=$offset-"); } my $response = $browser->get($url, ':content_cb' => sub { my ($data, $response) = @_; if (!$self->{content_length}) { $self->{content_length} = $response->header('Content-Length') + $offset; if($response->header('Content-encoding') =~ /gzip/i) { eval { require Compress::Zlib; } or do { error "Must have Compress::Zlib installed to download from this site.\n"; exit 1; }; my($inflate, $status) = Compress::Zlib::inflateInit( -WindowBits => -Compress::Zlib::MAX_WBITS()); error "inflateInit failed: $status" if $status; $self->{filter} = sub { my($data) = @_; if(!$self->{downloaded}) { Compress::Zlib::_removeGzipHeader(\$data); } my($output, $status) = $inflate->inflate($data); return $output; } } } if ($offset and !$response->header('Content-Range')) { error "Resuming failed - please delete $self->{printable_filename} and restart."; exit 1; } else { $self->{downloaded} = $offset unless $self->{downloaded}; } my $len = length $data; if($self->{filter}) { $data = $self->{filter}->($data); } my $fh = $self->{fh}; print $fh $data || die "Unable to write to '$self->{printable_filename}': $!\n"; if(defined $self->{stream}) { if($self->{downloaded} > 300_000) { $self->{stream}->(); } } if(!$self->{downloaded} && length $data > 16) { if(!$self->check_magic($data)) { error "Sorry, file does not look like a media file, aborting."; exit 1; } } $self->{downloaded} += $len; $self->progress; }, ':read_size_hint' => 16384); if($browser->response->header("X-Died")) { error $browser->response->header("X-Died"); } close $self->{fh} || die "Unable to write to '$self->{printable_filename}': $!"; if ($browser->success) { return $self->{downloaded} - $offset; } else { unlink $file unless -s $file; error "Couldn't download $url: " . $browser->response->status_line; return 0; } } sub progress { my($self) = @_; return unless -t STDERR; return if $::opt{quiet}; my $progress_text; if ($self->{content_length}) { my $percent = int( ($self->{downloaded} / $self->{content_length}) * 100 ); if ($percent && ($percent != $self->{percent} || time != $self->{last_time})) { my $downloaded_kib = _bytes_to_kib($self->{downloaded}); my $total_kib = _bytes_to_kib($self->{content_length}); $progress_text = ": $percent% ($downloaded_kib / $total_kib KiB)"; $self->{last_time} = time; $self->{percent} = $percent; } } else { my $data_transferred = _bytes_to_kib($self->{downloaded});; if ($data_transferred != $self->{data_transferred}) { $progress_text = ": $data_transferred KiB"; } } if($progress_text) { my $width = $self->terminal_width; my $filename = $self->{printable_filename}; my $filename_len = $width - length($progress_text); if($filename_len < length $filename) { my $rem = 3 + length($filename) - $filename_len; my $pos = length($filename) - $rem - 12; $pos = 0 if $pos < 0; substr($filename, $pos, $rem) = "..."; } print STDERR "\r$filename$progress_text"; } } sub terminal_width { my($self) = @_; if($self->{has_readkey} && (my($width) = Term::ReadKey::GetTerminalSize())) { return $width; } elsif($ENV{COLUMNS}) { return $ENV{COLUMNS}; } else { return 80; } } sub _bytes_to_kib { return sprintf '%0.2f', ($_[0] / 1024) } sub replace_filename { my($self, $string, $filename) = @_; $string .= " %s" unless $string =~ /%s/; my $esc = $self->shell_escape($filename); $string =~ s/['"]?%s['"]?/$esc/g; return $string; } sub shell_escape { my($self, $file) = @_; $file =~ s/'/'\\''/g; return "'$file'"; } sub check_file { my($self, $file) = @_; open my $fh, "<", $file; binmode $fh; my $data; read $fh, $data, 16; return $self->check_magic($data); } sub check_magic { my($self, $data) = @_; if(substr($data, 0, 3) eq 'FLV') { return 1; } elsif(substr($data, 0, 3) eq 'ID3') { return 1; } elsif(substr($data, 0, 4) eq "\x30\x26\xb2\x75") { return 1; } elsif(substr($data, 4, 4) eq 'ftyp') { return 1; } elsif(substr($data, 4, 4) eq 'moov' || substr($data, 4, 4) eq 'mdat') { return 1; } return 0; } sub get_filename { my($self, $file) = @_; if($^O =~ /MSWin/i) { $file = Encode::encode(get_win_codepage(), $file); $file =~ s/\?/_/g; } return $file; } 1; } ##} ./FlashVideo/Downloader.pm ##{ ./FlashVideo/Mechanize.pm { package FlashVideo::Mechanize; use WWW::Mechanize; BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl) use Encode; use strict; use WWW::Mechanize;use base "WWW::Mechanize"; sub new { my $class = shift; my $browser = $class->SUPER::new(autocheck => 0); $browser->agent_alias("Windows Mozilla"); my $proxy = $::opt{proxy}; if($proxy && $proxy !~ /^\w+:/) { my $port = ($proxy =~ /:(\d+)/)[0] || 1080; $proxy = "socks://$1:$port"; } if($proxy) { $browser->proxy([qw[http https]] => $proxy); } return $browser; } sub redirect_ok { my($self) = @_; return $self->{redirects_ok}; } sub allow_redirects { my($self) = @_; $self->{redirects_ok} = 1; } sub get { my($self, @rest) = @_; print STDERR "-> GET $rest[0]\n" if $::opt{debug}; my $r = $self->SUPER::get(@rest); if($::opt{debug}) { my $text = join " ", $self->response->code, $self->response->header("Content-type"), "(" . length($self->content) . ")"; $text .= ": " . DBI::data_string_desc($self->content) if eval { require DBI }; print STDERR "<- $text\n"; } return $r; } sub update_html { my($self, $html) = @_; my $charset = _parse_charset($self->response->header("Content-type")); if(!$charset || !Encode::is_utf8($html)) { $html = Encode::encode("iso-8859-1", $html) if Encode::is_utf8($html); if(!FlashVideo::Downloader->check_magic($html)) { my $p = HTML::TokeParser->new(\$html); while(my $token = $p->get_tag("meta")) { my($tag, $attr) = @$token; if($tag eq 'meta' && $attr->{"http-equiv"} =~ /Content-type/i) { $charset ||= _parse_charset($attr->{content}); } } if($charset) { eval { $html = decode($charset, $html) }; FlashVideo::Utils::error("Failed decoding as $charset: $@") if $@; } } } return $self->SUPER::update_html($html); } sub _parse_charset { my($field) = @_; return(($field =~ /;\s*charset=([-_.:a-z0-9]+)/i)[0]); } sub get_socks_proxy { my $self = shift; my $proxy = $self->proxy("http"); if($proxy =~ m!^socks://(.*?):(\d+)!) { return "$1:$2"; } return ""; } 1; } ##} ./FlashVideo/Mechanize.pm BEGIN { $INC{'FlashVideo/Generic.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/Generic.pm { package FlashVideo::Generic; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use Memoize; use LWP::Simple; use URI::Escape; my $video_re = qr!http[-:/a-z0-9%_.?=&]+@{[EXTENSIONS]} (?:\?[-:/a-z0-9%_.?=&]+)?!xi; sub find_video { my ($self, $browser) = @_; 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) { memoize("LWP::Simple::head"); @flv_urls = sort { (head($a))[1] <=> (head($b))[1] } @flv_urls; $possible_filename = (split /\//, $flv_urls[-1])[-1]; $actual_url = url_exists($browser->clone, $flv_urls[-1]); } if(!$actual_url) { RE: for my $regex( qr{(?si)]+)}, qr{(?si)]+)}, qr{(?si)]* href=["']?([^"'>]+?@{[EXTENSIONS]})}, qr{(?si)]*>.*?]*value=["']?([^"'>]+)}, qr{(?si)]*>(.*?)}, qr{(?si)]*>(.*?)}) { for my $param($browser->content =~ /$regex/gi) { (my $url, $possible_filename) = find_file_param($browser->clone, $param); 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); ($actual_url) = eval { $self->find_video($sub_browser) }; } } } my @filenames; $possible_filename =~ s/\?.*//; push @filenames, $possible_filename if $possible_filename && $possible_filename !~ /^[0-9_.]+@{[EXTENSIONS]}$/; my $ext = substr(($actual_url =~ /(@{[EXTENSIONS]})$/)[0], 1); push @filenames, title_to_filename($title, $ext) if $title && $title !~ /\Q$possible_filename\E/i; push @filenames, get_video_filename() if !@filenames; return $actual_url, @filenames if $actual_url; die "No URLs found"; } sub find_file_param { my($browser, $param) = @_; for my $file($param =~ /(?:video|movie|file)_?(?:href|src|url)?['"]?\s*[=:,]\s*['"]?([^&'" ]+)/gi, $param =~ /(?:config|playlist|options)['"]?\s*[,:=]\s*['"]?(http[^'"&]+)/gi, $param =~ /['"=](.*?@{[EXTENSIONS]})/gi, $param =~ /([^ ]+@{[EXTENSIONS]})/gi, $param =~ /SWFObject\(["']([^"']+)/) { my $actual_url = guess_file($browser, $file); if($actual_url) { my $possible_filename = (split /\//, $actual_url)[-1]; return $actual_url, $possible_filename; } } if($param =~ m{(rtmp://[^ &"']+)}) { info "This looks like RTMP ($1), no generic support yet.."; } return; } sub guess_file { my($browser, $file, $once) = @_; $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) { my $content_type = $browser->response->header("Content-type"); if($content_type =~ m!^(text|application/xml)!) { $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!) { debug "Found a video at $uri"; return $uri; } return if $browser->content =~ /]*>/i; if($browser->content =~ m!($video_re)!) { return $1; } elsif(!defined $once && $browser->content =~ m!(http[-:/a-zA-Z0-9%_.?=&]+)!i) { return guess_file($browser, $1, 1); } else { info "Tried $uri, but no video URL found"; } } elsif($content_type =~ m!application/! && $uri ne $orig_uri) { return((find_file_param($browser, $uri))[0]); } else { return $uri->as_string; } } elsif(not defined $once) { 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); } } } } } return; } 1; } ##} ./FlashVideo/Generic.pm ##{ ./FlashVideo/URLFinder.pm { package FlashVideo::URLFinder; use strict; BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Generic->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } use URI; my @extra_can_handle = qw(Brightcove Mtvnservices Gawker); sub find_package { my($url, $browser) = @_; my $package = find_package_url($url, $browser); if(!defined $package) { 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 = "FlashVideo::Site::$_"; eval "require $possible_package"; my $r = $possible_package->can_handle($browser, $url); if($r) { $package = $possible_package; last; } } } if(!defined $package) { $package = "FlashVideo::Generic"; } return _found($package, $url); } sub find_package_url { my($url, $browser) = @_; my $package; foreach my $host_part (split /\./, URI->new($url)->host) { $host_part = ucfirst lc $host_part; $host_part =~ s/[^a-z0-9]//i; my $possible_package = "FlashVideo::Site::$host_part"; eval "require $possible_package"; if(UNIVERSAL::can($possible_package, "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; } 1; } ##} ./FlashVideo/URLFinder.pm BEGIN { $INC{'FlashVideo/RTMPDownloader.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/RTMPDownloader.pm { package FlashVideo::RTMPDownloader; use strict; BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl) use base 'FlashVideo::Downloader'; use Fcntl; use IPC::Open3; use Symbol qw(gensym); BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } sub download { my ($self, $rtmp_data) = @_; $self->{printable_filename} = $rtmp_data->{flv}; my $file = $rtmp_data->{flv} = $self->get_filename($rtmp_data->{flv}); 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} && $::opt{play}) { pipe($r_fh, $w_fh); my $pid = fork; die "Fork failed" unless defined $pid; if(!$pid) { fcntl $r_fh, F_SETFD, ~FD_CLOEXEC; exec $self->replace_filename($::opt{player}, "/dev/fd/" . fileno $r_fh); die "Exec failed\n"; } fcntl $w_fh, F_SETFD, ~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($::opt{debug}) { $rtmp_data->{verbose} = undef; } my($return, @errors) = $self->run($prog, $rtmp_data); if($return != 0 && "@errors" =~ /failed to connect/i) { $rtmp_data->{port} = 443; ($return, @errors) = $self->run($prog, $rtmp_data); } if(-s $file < 100 || !$self->check_file($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"; } return "rtmpdump"; } sub run { my($self, $prog, $rtmp_data) = @_; debug "Running $prog", join(" ", map { ("--$_" => $rtmp_data->{$_} ? $self->shell_escape($rtmp_data->{$_}) : ()) } keys %$rtmp_data); my($in, $out, $err); $err = gensym; my $pid = open3($in, $out, $err, $prog, map { ("--$_" => ($rtmp_data->{$_} || ())) } keys %$rtmp_data); my $complete = 0; my $buf = ""; my @error; while(sysread($err, $buf, 128, length $buf) > 0) { my @parts = split /\r/, $buf; $buf = ""; for(@parts) { if(/^((?:DEBUG:|WARNING:|Closing connection|ERROR: No playpath found).*)\n/) { debug "$prog: $1"; } elsif(/^(ERROR: .*)\n/) { 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) { $self->{content_length} = $self->{downloaded} / ($percent / 100); } $self->progress; } elsif(/\n$/) { for my $l(split /\n/) { 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(/open3/) { error "\nMake sure you have 'rtmpdump' or 'flvstreamer' installed and available on your PATH."; return 0; } } else { $buf = $_; } } if(defined $self->{stream} && $self->{downloaded} > 300_000) { $self->{stream}->(); } } waitpid $pid, 0; return $? >> 8, @error; } 1; } ##} ./FlashVideo/RTMPDownloader.pm BEGIN { $INC{'FlashVideo/Search.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. BEGIN { $INC{'FlashVideo/GoogleVideoSearch.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ ./FlashVideo/GoogleVideoSearch.pm { package FlashVideo::GoogleVideoSearch; use strict; BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl) sub search { my $search = shift; my $browser = FlashVideo::Mechanize->new; $browser->get('http://video.google.com/'); $browser->submit_form( with_fields => { q => $search, } ); return unless $browser->success; my @links = map { chomp(my $name = $_->text); { name => $name, url => $_->url_abs->as_string } } grep { $_->attrs()->{onclick} =~ /return resultClick/ } $browser->find_all_links(text_regex => qr/.+/); return @links; } 1; } ##} ./FlashVideo/GoogleVideoSearch.pm ##{ ./FlashVideo/Search.pm { package FlashVideo::Search; use strict; use Carp; BEGIN { FlashVideo::GoogleVideoSearch->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } my @sites_with_search = (); sub search { my ($search, $max_per_site, $max_results) = @_; my @search_sites = map { /^FlashVideo::Site::/ ? $_ : "FlashVideo::Site::$_"; } @sites_with_search; 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::Site::$possible_site"; eval "require $possible_package"; if (UNIVERSAL::can($possible_package, "search")) { debug "Search for '$search' will only search $possible_site."; $search =~ s/^\w+ //; my @results = $possible_package->search($search); trim_resultset(\@results, $max_results); return @results; } } my @plugins = main::get_installed_plugins(); foreach my $plugin (@plugins) { $plugin =~ s/\.pm$//; my $plugin_package = "FlashVideo::Site::$plugin"; eval "require $plugin_package"; if (UNIVERSAL::can($plugin_package, "search")) { debug "Plugin '$plugin' has a search method."; push @search_sites, $plugin_package; } else { debug "Plugin '$plugin' doesn't have a search method."; } } my @results; foreach my $search_site (@search_sites) { debug "Searching '$search_site' for '$search'."; if (my @site_results = $search_site->search($search)) { debug "Found " . @site_results . " results for $search."; trim_resultset(\@site_results, $max_per_site); push @results, @site_results; } else { debug "No results found for '$search'."; } } my @google_results = FlashVideo::GoogleVideoSearch::search($search); trim_resultset(\@google_results, $max_per_site); push @results, @google_results; trim_resultset(\@results, $max_results); return @results; } 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; } ##} ./FlashVideo/Search.pm ##{ get_flash_videos { package main; use strict; use File::stat; use File::Basename; use Getopt::Long; BEGIN { FlashVideo::URLFinder->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::RTMPDownloader->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Search->import(); } # (added by utils/combine-perl.pl) BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *extract_title = \&FlashVideo::Utils::extract_title; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *swfhash_data = \&FlashVideo::Utils::swfhash_data; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; } BEGIN { FlashVideo::GoogleVideoSearch->import(); } # (added by utils/combine-perl.pl) unshift @INC, \&plugin_loader; use constant VERSION => "1.18"; our %opt; BEGIN { my $player = "mplayer -really-quiet"; $player = "VLC" if $^O =~ /MSWin/i; $player = "open" if $^O =~ /darwin/ && !is_program_on_path("mplayer"); if(is_program_on_path("gnome-open") && !is_program_on_path("mplayer")) { $player = "gnome-open"; } elsif(is_program_on_path("kde-open") && !is_program_on_path("mplayer")) { $player = "kde-open"; } %opt = ( yes => 0, filename => '', version => 0, update => 0, play => 0, player => $player, proxy => '', debug => 0, quiet => 0, ); } use constant VER_INFO => < VER_INFO . < < < \$opt{yes}, "filename|f=s" => \$opt{filename}, "version|v" => \$opt{version}, "update|u" => \$opt{update}, "help|h" => \$opt{help}, "play|p" => \$opt{play}, "player=s" => \$opt{player}, "proxy=s" => \$opt{proxy}, "debug|d" => \$opt{debug}, "quiet|q" => \$opt{quiet}, "add-plugin=s" => \$opt{add_plugin}, ); if($opt{version}) { die VER_INFO; } elsif($opt{update}) { exit update(); } elsif($opt{help}) { die USAGE; } elsif($opt{add_plugin}) { exit add_plugin($opt{add_plugin}); } if ($opt{debug}) { if(my @plugins = get_installed_plugins()) { debug @plugins . " plugins installed:"; debug "- $_" for @plugins; } else { debug "No plugins installed"; } } if (FlashVideo::Mechanize->new->get_socks_proxy()) { my $HAS_LWP_PROTOCOL_SOCKS = eval { require LWP::Protocol::socks }; if (!$HAS_LWP_PROTOCOL_SOCKS) { die "LWP::Protocol::socks is required for SOCKS support, please install it" } } if($^O =~ /MSWin/i) { binmode STDERR, ":encoding(" . get_win_codepage() . ")"; binmode STDOUT, ":encoding(" . get_win_codepage() . ")"; } else { binmode STDERR, ":utf8"; binmode STDOUT, ":utf8"; } my (@urls) = @ARGV; @urls > 0 or die USAGE; my $search; if ( ((@urls == 1) and $urls[0] !~ m'\.') or ( (@urls > 1) and ! grep /^http:\/\/|^[\w\-]+\.[\w\-]+/, @urls)) { $search = join ' ', @urls; } my @download_urls; if ($search) { if (my @results = FlashVideo::Search::search($search, 10, 20)) { if ($opt{yes} or @results == 1) { my $message = (@results == 1) ? "Downloading only match for '$search': '$results[0]->{name}'" : "Downloading first match for '$search': '$results[0]->{name}'" ; info $message; push @download_urls, $results[0]->{url}; } else { print "Search for '$search' found these results:\n"; my $count = 1; for my $result(@results) { printf "[%2d] %s\n", $count, $result->{name}; $count++; } print "Enter the number(s) of the videos to download " . "(separate multiple with comma or space): "; chomp(my $choice = ); $choice ||= 1; for(split /[ ,]+/, $choice) { $_--; if (!$results[$_]) { print STDERR "'$_' is an invalid choice.\n"; exit 1; } push @download_urls, $results[$_]->{url}; } } } else { print STDERR "No results found for '$search'.\n"; exit 1; } } else { @download_urls = @urls; } my $download_count = 0; foreach my $url (@download_urls) { if (download($url, @download_urls - $download_count)) { $download_count++; } } if($download_count == 0) { info "Couldn't download any videos."; exit 1; } exit 0; sub download { my($url, $remaining) = @_; $url = "http://$url" if $url !~ m!^\w+:!; info "Downloading $url"; my $browser = FlashVideo::Mechanize->new; $browser->get($url); if (!$browser->success and !$browser->response->is_redirect) { error "Couldn't download '$url': " . $browser->response->status_line; } my($package, $possible_url) = FlashVideo::URLFinder::find_package($url, $browser); my($actual_url, @suggested_fnames) = eval { $package->find_video($browser, $possible_url); }; if(!$actual_url) { if($@ =~ /^Must have | requires /) { my $error = "$@"; $error =~ s/at $0.*//; die "$error" . REQ_INFO; } else { die "Error: $@" . FRIENDLY_FAILURE; } } my $suggested_filename = $suggested_fnames[-1]; if (!$opt{play}) { if (!$opt{yes} && @suggested_fnames > 1) { print "There are different suggested filenames, please choose:\n"; my $count; foreach my $filename (@suggested_fnames) { $count++; print "$count - $filename\n"; } print "\nWhich filename would you like to use?: "; chomp(my $chosen_fname = ); $suggested_filename = $suggested_fnames[$chosen_fname - 1] || $suggested_fnames[-1]; } } my $save_as = $opt{filename} || $suggested_filename; my $action = $opt{play} ? "play" : "download"; for my $data((ref($actual_url) eq 'ARRAY' ? @$actual_url : $actual_url)) { my $downloader; if(ref $data eq 'HASH') { $downloader = FlashVideo::RTMPDownloader->new; } else { $downloader = FlashVideo::Downloader->new; } my $size = $downloader->$action($data, $save_as, $browser) || exit 1; info "\n" . ($remaining == 1 ? "Done. " : "") . "Saved $size bytes to $downloader->{printable_filename}"; } return 1; } sub read_conf { for my $file("/etc/get_flash_videosrc", "$ENV{HOME}/.get_flash_videosrc") { open my $fh, "<", $file or next; while(<$fh>) { s/\r?\n//; next if /^\s*(#|$)/; my($n, $v) = split /\s*=\s*/; $v = 1 unless defined $v; $opt{$n} = $v; } } } sub add_plugin { my($plugin_url) = @_; my $uri = URI->new($plugin_url); unless(-d get_plugin_dir()) { require File::Path; File::Path::mkpath(get_plugin_dir()) or die "Unable to create plugin dir: $!"; } my $filename = get_plugin_dir() . "/" . basename($uri->path); if($filename !~ /\.pm$/) { die "Plugins must have a file extension of '.pm'\n"; } if(!$uri->scheme) { require File::Copy; File::Copy::copy($plugin_url => $filename) || die "Unable to copy plugin to '$filename': $!\n"; info "Plugin installed."; return 0; } else { my $browser = FlashVideo::Mechanize->new; return !install_plugin($browser, $plugin_url, $filename); } } sub update { if($::SCRIPT_NAME) { my $browser = FlashVideo::Mechanize->new; $browser->get("http://get-flash-videos.googlecode.com/svn/wiki/Version.wiki"); if(!$browser->response->is_success) { die "Unable to retrieve version data: " . $browser->response->status_line; } my $version = ($browser->content =~ /version: (\S+)/)[0]; my $base = ($browser->content =~ /from: (\S+)/)[0]; my $info = ($browser->content =~ /info: (\S+)/)[0]; my $url = $base . $::SCRIPT_NAME . "-" . $version; die "Unable to parse version data" unless $version and $base; my @v = split /\./, $version; my @V = split /\./, VERSION; my $newer = 0; my $i = 0; for(@v) { $newer = 1 if !defined $V[$i] || $_ > $V[$i]; last if $V[$i] > $v[$i]; $i++; } if($newer) { info "Newer version ($version) available, downloading.."; die "Cannot update -- unable to write to $0\n" unless -w $0; my $new_file = $0 . ".new"; $browser->mirror($url, $new_file); if($browser->response->is_success && -f $new_file) { rename $0, "$0.old" or die "Unable to rename $0 to $0.old: $!"; rename $new_file, $0 or die "Unable to rename $new_file to $0: $!"; chmod 0755, $0; info "New version installed as $0"; info "(previous version backed up to $0.old)."; info $info; exit 0; } else { die "Download failed: " . $browser->response->status_line; } } else { print STDERR "You already have the latest version.\n"; } } else { info "Development version, not updated"; } update_plugins(); } sub update_plugins { my $browser = FlashVideo::Mechanize->new; foreach my $plugin(get_installed_plugins()) { debug "Seeing if there is an update for $plugin.."; my $file = get_plugin_dir() . "/$plugin"; require $file; my $package = "FlashVideo::Site::" . ($plugin =~ /(.*)\.pm$/)[0]; if($package->can("update")) { $package->update(); } else { no strict 'refs'; my $downloaded = 0; my $newer_found = 0; foreach my $update_url (@{ "$package\::update_urls" }) { $browser->head($update_url); if (!$browser->response->is_success) { debug "Couldn't retrieve $update_url for $plugin: " . $browser->response->status_line; next; } my $file_mtime = stat($file)->mtime; my $remote_plugin_mtime = $browser->response->last_modified; if ($remote_plugin_mtime > $file_mtime) { info "Newer version of plugin $plugin found at $update_url, trying to download and install"; $newer_found = 1; if ($downloaded = install_plugin($browser, $update_url, $file)) { last; } } else { debug "Plugin $plugin is already the lastest version."; debug "(Remote: " . $browser->response->header("Last-Modified") . "; Local: " . gmtime($file_mtime) . " GMT)"; } } if ($newer_found and !$downloaded) { die "Couldn't install $plugin plugin"; } } } } sub install_plugin { my ($browser, $url, $file) = @_; my $plugin_exists = -f $file; my $new_file = $plugin_exists ? "$file.new" : $file; $browser->mirror($url, $new_file); if ($browser->response->is_success && -f $new_file) { my $short_name = basename($file); if ($plugin_exists) { rename $file, "$file.old" or die "Unable to rename $file to $file.old: $!"; rename $new_file, $file or die "Unable to rename $new_file to $file: $!"; info "New version of $short_name installed as $file"; info "(previous version backed up to $file.old)."; } else { info "New plugin $short_name installed as $file"; } return 1; } else { warn "Download failed: " . $browser->response->status_line; } return 0; } sub plugin_loader { my (undef, $module) = @_; if ($module =~ m'^FlashVideo/Site/(.*)') { my $plugin_name = $1; my $plugin_dir = get_plugin_dir(); debug "Trying to open plugin $plugin_dir/$plugin_name"; if (open my $plugin_fh, '<', "$plugin_dir/$plugin_name") { return $plugin_fh; # Perl then reads the plugin from the FH } } return; } sub get_installed_plugins { my $plugin_dir = get_plugin_dir(); my @plugins; if (opendir my $plugin_dir_dh, $plugin_dir) { @plugins = grep /\.pm$/i, readdir $plugin_dir_dh; closedir $plugin_dir_dh; } return @plugins; } sub get_plugin_dir { return get_user_config_dir() . "/plugins"; } } ##} get_flash_videos