#!/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://github.com/monsieurvideo/get-flash-videos # ################################################# # # 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/4od.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. ##{ blib/lib/FlashVideo/Utils.pm { package FlashVideo::Utils; use strict; no warnings 'uninitialized'; 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|avi|m4v)/i; use constant MAX_REDIRECTS => 5; our @EXPORT = qw(debug info error extract_title extract_info title_to_filename get_video_filename url_exists swfhash swfhash_data EXTENSIONS get_user_config_dir get_win_codepage is_program_on_path get_terminal_width json_unescape convert_sami_subtitles_to_srt from_xml); sub debug(@) { my $string = "@_\n"; $string =~ s/\Q$ENV{HOME}\E/~/g; print STDERR $string if $App::get_flash_videos::opt{debug}; } sub info(@) { print STDERR "@_\n" unless $App::get_flash_videos::opt{quiet}; } sub error(@) { print STDERR "@_\n"; } sub extract_title { my($browser) = @_; return extract_info($browser)->{title}; } sub extract_info { my($browser) = @_; my($title, $meta_title); my $p = HTML::TokeParser->new(\$browser->content); while(my $token = $p->get_tag("title", "meta")) { my($tag, $attr) = @$token; if($tag eq 'meta' && $attr->{name} =~ /title/i) { $meta_title = $attr->{content}; } elsif($tag eq 'title') { $title = $p->get_trimmed_text; } } return { title => $title, meta_title => $meta_title, }; } sub swfhash { my($browser, $url) = @_; $browser->get($url); return swfhash_data($browser->content, $url); } sub swfhash_data { my ($data, $url) = @_; die "Must have Compress::Zlib and Digest::SHA for this RTMP download\n" unless eval { require Compress::Zlib; require Digest::SHA; }; $data = "F" . substr($data, 1, 7) . Compress::Zlib::uncompress(substr $data, 8); return swfsize => length $data, swfhash => Digest::SHA::hmac_sha256_hex($data, FP_KEY), swfUrl => $url; } sub url_exists { my($browser, $url) = @_; $browser->head($url); my $response = $browser->response; debug "Exists on $url: " . $response->code; return $url if $response->code == 200; my $redirects = 0; while ( ($response->code =~ /^30\d/) and ($response->header('Location')) and ($redirects < MAX_REDIRECTS) ) { $url = URI->new_abs($response->header('Location'), $url); $response = $browser->head($url); debug "Redirected to $url (" . $response->code . ")"; if ($response->code == 200) { return $url; } $redirects++; } return ''; } sub title_to_filename { my($title, $type) = @_; if($App::get_flash_videos::opt{filename} ne '') { return $App::get_flash_videos::opt{filename}; } if($title =~ s/(@{[EXTENSIONS]})$//) { $type = substr $1, 1; } elsif ($type && $type !~ /^\w+$/) { $type = substr((URI->new($type)->path =~ /(@{[EXTENSIONS]})$/)[0], 1); } $type ||= "flv"; $title = decode_utf8($title); 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 $title = encode_utf8($title); 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; } sub get_terminal_width { if(eval { require Term::ReadKey } && (my($width) = Term::ReadKey::GetTerminalSize())) { return $width - 1 if $^O =~ /MSWin|cygwin/i; # seems to be off by 1 on Windows return $width; } elsif($ENV{COLUMNS}) { return $ENV{COLUMNS}; } else { return 80; } } sub json_unescape { my($s) = @_; $s =~ s/\\u([0-9a-f]{1,4})/chr hex $1/ge; $s =~ s{(\\[\\/rnt"])}{"\"$1\""}gee; return $s; } sub convert_sami_subtitles_to_srt { my ($sami_subtitles, $filename, $decrypt_callback) = @_; die "SAMI subtitles must be provided" unless $sami_subtitles; die "Output SRT filename must be provided" unless $filename; $sami_subtitles =~ s/[\r\n]//g; # flatten my @lines = split /| |g; s|&|&|g; s{&(?:nbsp|#160);}{ }g; ($begin, $sub) = ($1, $2) if m{[^>]*Start="(.+?)"[^>]*>(.*?)<\/Sync>}i; if (/^\s*Encrypted="true"\s*/i) { if ($decrypt_callback and ref($decrypt_callback) eq 'CODE') { $sub = $decrypt_callback->($sub); } } $sub =~ s@&@&@g; $sub =~ s@(?:]*>| | )@ @g; $sub =~ s{]*?>}{}g; # remove

and similar $sub =~ s{<(/)?([BI])>}{"<$1" . lc($2) . ">"}eg; decode_entities($sub); # in void context, this works in place if ($sub and ($begin or $begin == 0)) { my $seconds = int( $begin / 1000.0 ); my $ms = $begin - ( $seconds * 1000.0 ); $begin = sprintf("%02d:%02d:%02d,%03d", (gmtime($seconds))[2,1,0], $ms ); $sub =~ s/^\s*(.*?)\s*$/$1/; $sub =~ s/\s{2,}/ /g; $sub =~ s|
|\n|ig; $sub =~ s/^\s*|\s*$//mg; if ($count and !$subtitles[$count - 1]->{end}) { $subtitles[$count - 1]->{end} = $begin; } if (!$sub or $sub =~ /^\s+$/) { if ($count) { $last_proper_sub_end_time = $subtitles[$count - 1]->{end}; } next; # this is not a meaningful subtitle } push @subtitles, { start => $begin, text => $sub, }; $count++; } } $subtitles[$count - 1]->{end} = $last_proper_sub_end_time; open my $subtitle_fh, '>', $filename or die "Can't open subtitles file $filename: $!"; binmode $subtitle_fh, ':utf8'; $count = 1; foreach my $subtitle (@subtitles) { print $subtitle_fh "$count\n$subtitle->{start} --> $subtitle->{end}\n" . "$subtitle->{text}\n\n"; $count++; } close $subtitle_fh; return 1; } sub from_xml { my($xml, @args) = @_; if(!eval { require XML::Simple && XML::Simple::XMLin("") }) { die "Must have XML::Simple to download " . caller =~ /::([^:])+$/ . " videos\n"; } $xml = eval { XML::Simple::XMLin(ref $xml eq 'SCALAR' ? $xml : ref $xml ? $xml->content : $xml, @args); }; if($@) { die "$@ (from ", join("::", caller), ")\n"; } return $xml; } 1; } ##} blib/lib/FlashVideo/Utils.pm ##{ blib/lib/FlashVideo/Site/4od.pm { package FlashVideo::Site::4od; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *from_xml = \&FlashVideo::Utils::from_xml; } use URI::Escape; sub search { my ($self, $search, $type) = @_; unless(eval { from_xml("") }) { if($type eq 'site') { die $@; } else { debug $@; return; } } my $gdata_template_url = "http://gdata.youtube.com/feeds/api/videos?q=%s&orderby=published&start-index=1&max-results=50&v=2"; my $search_url = sprintf $gdata_template_url, uri_escape($search); my $browser = FlashVideo::Mechanize->new(); $browser->get($search_url); if (!$browser->success) { die "Couldn't get YouTube search Atom XML: " . $browser->response->status_line(); } my $xml = from_xml($browser, KeyAttr => [], ForceArray => ['entry']); my @matches = map { _process_4od_result($_) } grep { $_->{author}->{name} =~ /^4oD\w+$/i } @{ $xml->{entry} }; return @matches; } sub _process_4od_result { my $feed_entry = shift; my $url = $feed_entry->{'media:group'}->{'media:player'}->{url}; $url =~ s/&feature=youtube_gdata//; my $published_date = $feed_entry->{published}; $published_date =~ s/T.*$//; # only care about date, not time my $title = $feed_entry->{'media:group'}->{'media:title'}->{content}; my $description = $feed_entry->{'media:group'}->{'media:description'}->{content}; my $result_name = "$title ($published_date)"; return { name => $result_name, url => $url, description => $description }; } 1; } ##} blib/lib/FlashVideo/Site/4od.pm BEGIN { $INC{'FlashVideo/Site/5min.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/5min.pm { package FlashVideo::Site::5min; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } 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; } ##} blib/lib/FlashVideo/Site/5min.pm BEGIN { $INC{'FlashVideo/Site/Abc.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Abc.pm { package FlashVideo::Site::Abc; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; } sub find_video { my ($self, $browser, $embed_url) = @_; if ($browser->uri->as_string =~ m'/watch/clip/[\w\-]+/(\w+)/(\w+)/(\w+)') { my $show_id = $1; my $playlist_id = $2; my $video_id = $3; return handle_abc_clip($browser, $show_id, $playlist_id, $video_id); } my $playpath; if ($browser->content =~ /http:\/\/cdn\.video\.abc\.com\/abcvideo\/video_fep\/thumbnails\/220x124\/([^"]*)220x124\.jpg/) { $playpath = "mp4:/abcvideo/video_fep/mov/" . lc($1) . "768x432_700.mov"; } $browser->content =~ /

([^<]*)<\/h2>/; my $title = $1; my $rtmpurl = "rtmp://abcondemandfs.fplive.net:1935/abcondemand"; return { rtmp => $rtmpurl, playpath => $playpath, flv => title_to_filename($title) }; } sub handle_abc_clip { my ($browser, $show_id, $playlist_id, $video_id) = @_; my $abc_clip_rss_url_template = "http://ll.static.abc.com/vp2/ws/s/contents/1000/videomrss?" . "brand=001&device=001&width=644&height=362&clipId=%s" . "&start=0&limit=1&fk=CATEGORIES&fv=%s"; my $abc_clip_rss_url = sprintf $abc_clip_rss_url_template, $video_id, $playlist_id; $browser->get($abc_clip_rss_url); if (!$browser->success) { die "Couldn't download ABC clip RSS: " . $browser->response->status_line; } my $xml = from_xml($browser); my $video_url = $xml->{channel}->{item}->{'media:content'}->{url}; my $type = $video_url =~ /\.mp4$/ ? 'mp4' : 'flv'; if (!$video_url) { die "Couldn't determine ABC clip URL"; } my $episode_name; if ($video_url =~ /FLF_\d+[A-Za-z]{0,5}_([^_]+)/) { $episode_name = $1; } my $category = $xml->{channel}->{item}->{category}; my $title = $xml->{channel}->{item}->{'media:title'}->{content}; if (ref($category) eq 'HASH' and ! keys %$category) { $category = ''; } my $description = $xml->{channel}->{item}->{'media:description'}->{content}; for ($category, $description, $title) { s/<\/?\w+>//g; } my $video_title = make_title($category, $episode_name, $title, $description); return $video_url, title_to_filename($video_title, $type); } sub make_title { return join " - ", grep /./, @_; } sub can_handle { my($self, $browser, $url) = @_; return $url && URI->new($url)->host =~ /\babc\.(?:go\.)?com$/; } 1; } ##} blib/lib/FlashVideo/Site/Abc.pm BEGIN { $INC{'FlashVideo/Site/Abclocal.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Abclocal.pm { package FlashVideo::Site::Abclocal; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; } use Data::Dumper; use File::Basename; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my($station,$id) = $browser->content =~ m{http://cdn.abclocal.go.com/[^"']*station=([^&;"']+)[^"']*mediaId=([^&;"']+)}s; die "No media id and station found" unless $id; $browser->get("http://cdn.abclocal.go.com/$station/playlistSyndicated?id=$id"); my @tmp = $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; } ##} blib/lib/FlashVideo/Site/Expertvillage.pm BEGIN { $INC{'FlashVideo/Site/Filebox.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://github.com/monsieurvideo/get-flash-videos # ################################################# ##{ blib/lib/FlashVideo/Site/Filebox.pm { package FlashVideo::Site::Filebox; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; } sub find_video { my ($self, $browser, $embed_url) = @_; my $pause = 5; #if we don't pause, we don't get the proper video page info 'Pausing for '.$pause.' seconds (or the server won\'t respond)...'; sleep($pause); my $btn_id = 'btn_download'; #the ID of the button to submit the form for my $form ($browser->forms) { if ($form->find_input('#'.$btn_id)){ info 'Submitting form to get real video page.'; $browser->request($form->click('#'.$btn_id)); #submit to get the real page } } my ($filename) = ($browser->content =~ /product_file_name=(.*?)[&'"]/); my ($url) = ($browser->content =~ /product_download_url=(.*?)[&'"]/); return $url, $filename; } 1; } ##} blib/lib/FlashVideo/Site/Filebox.pm BEGIN { $INC{'FlashVideo/Site/Flickr.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Flickr.pm { package FlashVideo::Site::Flickr; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; } use URI::Escape; my $get_mtl = "http://www.flickr.com/apps/video/video_mtl_xml.gne?v=x"; sub find_video { my ($self, $browser, $embed_url) = @_; my($id) = $browser->content =~ /photo_id=(\d+)/; my($secret) = $browser->content =~ /photo_secret=(\w+)/; die "No video ID found\n" unless $id; $browser->get($get_mtl . "&photo_id=$id&secret=$secret&olang=en-us&noBuffer=null&bitrate=700&target=_self"); my $xml = from_xml($browser); my $guid = $self->make_guid; my $video_id = $xml->{Data}->{Item}->{id}->{content}; my $playlist_url = $xml->{Playlist}->{TimelineTemplates}->{Timeline} ->{Metadata}->{Item}->{playlistUrl}->{content}; die "No video ID or playlist found" unless $video_id and $playlist_url; $browser->get($playlist_url . "?node_id=$video_id&secret=$secret&tech=flash&mode=playlist" . "&lq=$guid&bitrate=700&rd=video.yahoo.com&noad=1"); $xml = eval { XML::Simple::XMLin($browser->content) }; die "Failed parsing XML: $@" if $@; $xml = $xml->{"SEQUENCE-ITEM"}; die "XML not as expected" unless $xml; my $filename = title_to_filename($xml->{META}->{TITLE}); my $url = $xml->{STREAM}->{APP} . $xml->{STREAM}->{FULLPATH}; return $url, $filename; } sub make_guid { my($self) = @_; my @chars = ('A' .. 'Z', 'a' .. 'z', 0 .. 9, '.', '_'); return join "", map { $chars[rand @chars] } 1 .. 22; } 1; } ##} blib/lib/FlashVideo/Site/Flickr.pm BEGIN { $INC{'FlashVideo/Site/Fliqz.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Fliqz.pm { package FlashVideo::Site::Fliqz; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } 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; } ##} blib/lib/FlashVideo/Site/Fliqz.pm BEGIN { $INC{'FlashVideo/Site/Fora.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Fora.pm { package FlashVideo::Site::Fora; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; } sub find_video { my ($self, $browser, $embed_url) = @_; my($clip_id) = $browser->content =~ /clipid=(\d+)/; die "Unable to extract clipid" unless $clip_id; $browser->get("http://fora.tv/fora/fora_player_full?cid=$clip_id&h=1&b=0"); my $xml = from_xml($browser); my $filename = title_to_filename($xml->{clipinfo}->{clip_title}); my $playpath = $xml->{encodeinfo}->{encode_url}; $playpath =~ s/\.flv$//; return { flv => $filename, app => "a953/o10", rtmp => "rtmp://foratv.fcod.llnwd.net", playpath => $playpath, }; } 1; } ##} blib/lib/FlashVideo/Site/Fora.pm BEGIN { $INC{'FlashVideo/Site/Freevideo.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/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'; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } 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; } ##} blib/lib/FlashVideo/Site/Freevideo.pm BEGIN { $INC{'FlashVideo/Site/Gamespot.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Gamespot.pm { package FlashVideo::Site::Gamespot; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; } sub find_video { my ($self, $browser, $embed_url) = @_; my($params) = $browser->content =~ /xml.php\?(id=[0-9]+.*?)"/; ($params) = $embed_url =~ /xml.php%3F(id%3D[^"&]+)/ unless $params; die "No params found\n" unless $params; $browser->get("http://www.gamespot.com/pages/video_player/xml.php?" . $params); my $xml = from_xml($browser); my $title = $xml->{playList}->{clip}->{title}; my $url = $xml->{playList}->{clip}->{URI}; $browser->allow_redirects; return $url, title_to_filename($title); } 1; } ##} blib/lib/FlashVideo/Site/Gamespot.pm BEGIN { $INC{'FlashVideo/Site/Gawker.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Gawker.pm { package FlashVideo::Site::Gawker; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } 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; } ##} blib/lib/FlashVideo/Site/Gawker.pm BEGIN { $INC{'FlashVideo/Site/Globaltv.pm'}++; } ################################# ################################################# # # 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://github.com/monsieurvideo/get-flash-videos # ################################################# # GlobalTV Canada # # first alpha plugin version # # Input URL should be # http://www.globaltv.com/$show/video/full+episodes/$clip/video.html?v=$contentID # where # $show show name # $clip section # $contentID numeric ID # Stavr00 # # TODO: fetch all clips for a show # ##{ blib/lib/FlashVideo/Site/Globaltv.pm { package FlashVideo::Site::Globaltv; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; } use strict 'refs'; sub find_video { my ($self, $browser, $embed_url, $prefs) = @_; my $pid; if ( $browser->content =~ /pid:\s+"([^"]+?)"/ ) { $pid = $1; } debug "PID = " . $pid; die "PID not found." unless $pid; $browser->get("http://release.theplatform.com/content.select?pid=$pid&mbr=true&Embedded=True&Portal=GlobalTV&Site=global_prg.com&TrackBrowser=True&Tracking=True&TrackLocation=True&format=SMIL"); my $xml = from_xml($browser->content); my $maxres = $prefs->quality->quality_to_resolution($prefs->{quality}); my $sw; my $vid; my $title; my $url; my $rate = 0; my $res; debug "Enumerating all streams ..."; foreach $sw (@{ $xml->{body}->{switch} }) { if ($sw->{ref}->{src} =~ /^rtmp\:\/\// ) { $title = $sw->{ref}->{title}; debug "TITLE = " . $title; # short title, not very useful } if ( ref($sw->{video}) eq "ARRAY" ) { foreach $vid (@{ $sw->{video} }) { my $t = $vid->{src}; if ( $t =~ /^rtmp\:\/\// ) { my $w = $vid->{width}; my $h = $vid->{height}; my $br = $vid->{'system-bitrate'}; debug ' '. $t ." ". $w . 'x' . $h ."/". $br; if ( ( $br > $rate ) && ( $h <= @$maxres[1] ) ) { $rate = $br; $url = $t; $res = $w .'x'. $h .' '. int($br/1024) . 'kb/s'; } } } } } info 'Stream selected: ' . $url . ' ' . $res; $url =~ /([^\/]+\.mp4$)/; $title = $1; return { rtmp => $url, flv => title_to_filename($title) }; } 1; } ##} blib/lib/FlashVideo/Site/Globaltv.pm BEGIN { $INC{'FlashVideo/Site/Google.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Google.pm { package FlashVideo::Site::Google; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } use URI::Escape; sub find_video { my ($self, $browser) = @_; if ($browser->content =~ /googleplayer\.swf\?doc[iI]d=([^&;'"]+)/) { $browser->get("http://video.google.com/videoplay?docid=$1"); } 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; } ##} blib/lib/FlashVideo/Site/Google.pm BEGIN { $INC{'FlashVideo/Site/Googlevideosearch.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. BEGIN { $INC{'FlashVideo/Site.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site.pm { package FlashVideo::Site; use strict; sub debug { $App::get_flash_videos::opt{debug}; } sub action { $App::get_flash_videos::opt{play} ? "play" : "download"; } sub player { $App::get_flash_videos::opt{player}; } sub yes { $App::get_flash_videos::opt{yes}; } sub quiet { $App::get_flash_videos::opt{quiet}; } 1; } ##} blib/lib/FlashVideo/Site.pm ##{ blib/lib/FlashVideo/Downloader.pm { package FlashVideo::Downloader; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *get_terminal_width = \&FlashVideo::Utils::get_terminal_width; } BEGIN { FlashVideo::Site->import(); } # (added by utils/combine-perl.pl) use base "FlashVideo::Site"; sub new { my $class = shift; my $self = { has_readkey => scalar 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 $self->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($self->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 ($file ne '-' && -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(!$self->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."; } } my $video_fh; if($file eq '-') { $video_fh = \*STDOUT; } else { open $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); } return unless $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 $self->quiet; my $progress_text; if ($self->{content_length}) { my $percent = int( ($self->{downloaded} / $self->{content_length}) * 100 ); if ($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 = get_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) = "..."; } syswrite STDERR, "\r$filename$progress_text"; } } 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, 2) eq "\xff\xfb") { 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) =~ /moov|mdat|wide|free|pnot|skip/) { return 1; } elsif(substr($data, 0, 4) eq 'OggS') { return 1; } elsif(substr($data, 0x1F, 4) eq 'webm') { return 1; } elsif(substr($data, 0, 4) eq 'RIFF') { 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; } ##} blib/lib/FlashVideo/Downloader.pm ##{ blib/lib/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 = $App::get_flash_videos::opt{proxy}; if ($proxy) { if ($proxy =~ /^(\w+):?(\d+)?$/) { my ($host, $port) = ($1, $2); $port ||= 1080; # socks by default $proxy = "socks://$host:$port"; print STDERR "Using proxy server $proxy\n" if $App::get_flash_videos::opt{debug}; $browser->proxy([qw[http https]] => $proxy); } } if($browser->get_socks_proxy) { if(!eval { require LWP::Protocol::socks }) { die "LWP::Protocol::socks is required for SOCKS support, please install it\n"; } } 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 $App::get_flash_videos::opt{debug}; my $r = $self->SUPER::get(@rest); if($App::get_flash_videos::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($LWP::UserAgent::VERSION < 5.827 && (!$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 = Encode::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(defined $proxy && $proxy =~ m!^socks://(.*?):(\d+)!) { return "$1:$2"; } return ""; } 1; } ##} blib/lib/FlashVideo/Mechanize.pm ##{ blib/lib/FlashVideo/Site/Googlevideosearch.pm { package FlashVideo::Site::Googlevideosearch; use strict; no warnings 'uninitialized'; BEGIN { FlashVideo::Mechanize->import(); } # (added by utils/combine-perl.pl) use URI::Escape; sub search { my($self, $search, $type) = @_; my $browser = FlashVideo::Mechanize->new; $browser->get('http://video.google.com/videoadvancedsearch'); $browser->submit_form( with_fields => { q => $search, } ); return unless $browser->success; my @links = map { chomp(my $name = $_->text); my $url = $_->url_abs->as_string; $url =~ /q=([^&]*)/; $url = uri_unescape($1); { name => $name, url => $url } } $browser->find_all_links(text_regex => qr/.+/, url_regex => qr/\/url/); return @links; } 1; } ##} blib/lib/FlashVideo/Site/Googlevideosearch.pm BEGIN { $INC{'FlashVideo/Site/Gorillavid.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://github.com/monsieurvideo/get-flash-videos # ################################################# #This package handles sites such as GorillaVid.in, DaClips.in and # MovPod.in ##{ blib/lib/FlashVideo/Site/Gorillavid.pm { package FlashVideo::Site::Gorillavid; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; } sub find_video { my ($self, $browser, $embed_url) = @_; my $filename; for my $form ($browser->forms) { if ($form->find_input('#btn_download')){ $filename = $form->value('fname'); #extract the filename from the form info 'Submitting form to get real video page.'; $browser->request($form->click()); #submit to get the real page } } my ($url) = ($browser->content =~ /file: *"(https?:\/\/.*?)"/); my ($ext) = ($url =~ /(\.[a-z0-9]{2,4})$/); return $url, $filename.$ext; } sub can_handle { my($self, $browser, $url) = @_; return 1 if $url && URI->new($url)->host =~ /(gorillavid|daclips|movpod)\.in$/; } 1; } ##} blib/lib/FlashVideo/Site/Gorillavid.pm BEGIN { $INC{'FlashVideo/Site/Grindtv.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Grindtv.pm { package FlashVideo::Site::Grindtv; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } 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; } ##} blib/lib/FlashVideo/Site/Grindtv.pm BEGIN { $INC{'FlashVideo/Site/Ima.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Ima.pm { package FlashVideo::Site::Ima; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; } sub find_video { my ($self, $browser) = @_; my($id) = $browser->uri =~ /id=(\d+)/; die "ID not found" unless $id; my $rpc = "http://www.ima.umn.edu/videos/video_rpc.php?id=$id"; $browser->get($rpc); my($title) = $browser->content =~ m{(.*)}; my($instance) = $browser->content =~ m{(.*)}; my($file) = $browser->content =~ m{(.*)}; return { rtmp => "rtmp://reel.ima.umn.edu/ima/$instance/$file", flv => title_to_filename($title) }; } sub can_handle { my($self, $browser) = @_; return $browser->uri->host =~ /ima\.umn\.edu/i; } 1; } ##} blib/lib/FlashVideo/Site/Ima.pm BEGIN { $INC{'FlashVideo/Site/Itv.pm'}++; } # Part of get-flash-videos. See get_flash_videos for copyright. ##{ blib/lib/FlashVideo/Site/Itv.pm { package FlashVideo::Site::Itv; use strict; BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl) BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *swfhash = \&FlashVideo::Utils::swfhash; } use HTML::Entities; sub find_video { my ($self, $browser, $page_url, $prefs) = @_; my($id) = $browser->uri =~ /Filter=(\d+)/; die "No id (filter) found in URL\n" unless $id; $browser->post("http://mercury.itv.com/PlaylistService.svc", Content_Type => "text/xml; charset=utf-8", Referer => "http://www.itv.com/mercury/Mercury_VideoPlayer.swf?v=1.5.309/[[DYNAMIC]]/2", SOAPAction => '"http://tempuri.org/PlaylistService/GetPlaylist"', Content => < FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF $id itv.com scc=true; svisit=1; sc4=Other None ITV ITVPLAYER.VIDEO DotCom ItvCom EOF debug $browser->content; die "Unable to find