#!/usr/local/bin/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 /<Sync\s/i, $sami_subtitles;
  shift @lines; # Skip headers

  my @subtitles;
  my $count = 0;

  my $last_proper_sub_end_time = '';

  for (@lines) {
    my ($begin, $sub);
    s|<\/?span.*?>| |g;
    
    s|&amp;|&|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@&amp;@&@g;
    $sub =~ s@(?:</?span[^>]*>|&nbsp;|&#160;)@ @g;

    $sub =~ s{</?P[^>]*?>}{}g;  # remove <P Class="ENCC"> 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|<br ?\/? ?>|\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("<foo/>") }) {
    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("<foo/>") }) {
    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 id="video_title">([^<]*)<\/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{<video *videopath="([^"]*)"[^>]*width="([^"]*)"[^>]*height="([^"]*)"[^>]*>}s ;
  my(@videos);
  for (my $i = 0; $i < @tmp; $i+=3)
  {
    push @videos, { "playpath" => $tmp[$i], "resolution" => [$tmp[$i+1], $tmp[$i+2]] };
  }

  my $video = $prefs->quality->choose(@videos);

  my $url = $video->{"playpath"};

  return $url, File::Basename::basename($url);
}

1;
}
##} blib/lib/FlashVideo/Site/Abclocal.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.
##{ blib/lib/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; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
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 =~ /<param name=["']?playerID["']? value=["'](\d+) ?["']/i)[0];
  $video_id ||= ($browser->content =~ /<param name=["']?\@?video(?:Player|id)["']? value=["'](\d+)["']/i)[0];

  $player_id ||= ($browser->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;
  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(<<EOF));
AAAAAAABAEhjb20uYnJpZ2h0Y292ZS50ZW1wbGF0aW5nLlRlbXBsYXRpbmdGYWNhZGUuZ2V0Q29u
dGVudEZvclRlbXBsYXRlSW5zdGFuY2UAAi8yAAACNQoAAAACAEH4tP+1EAAAEAA1Y29tLmJyaWdo
dGNvdmUudGVtcGxhdGluZy5Db250ZW50UmVxdWVzdENvbmZpZ3VyYXRpb24ACnZpZGVvUmVmSWQG
AAd2aWRlb0lkBgAIbGluZXVwSWQGAAtsaW5ldXBSZWZJZAYAF29wdGltaXplRmVhdHVyZWRDb250
ZW50AQEAF2ZlYXR1cmVkTGluZXVwRmV0Y2hJbmZvEAAkY29tLmJyaWdodGNvdmUucGVyc2lzdGVu
Y2UuRmV0Y2hJbmZvAApjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRjaExldmVsRW51bQBAEAAAAAAA
AAALY29udGVudFR5cGUCAAtWaWRlb0xpbmV1cAAACQAKZmV0Y2hJbmZvcwoAAAACEAAkY29tLmJy
aWdodGNvdmUucGVyc2lzdGVuY2UuRmV0Y2hJbmZvAApjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRj
aExldmVsRW51bQA/8AAAAAAAAAALY29udGVudFR5cGUCAAtWaWRlb0xpbmV1cAAACRAAJGNvbS5i
cmlnaHRjb3ZlLnBlcnNpc3RlbmNlLkZldGNoSW5mbwAKY2hpbGRMaW1pdABAWQAAAAAAAAAPZ3Jh
bmRjaGlsZExpbWl0AEBZAAAAAAAAAA5mZXRjaExldmVsRW51bQBACAAAAAAAAAALY29udGVudFR5
cGUCAA9WaWRlb0xpbmV1cExpc3QAAAkAAAk=
EOF

  if (defined $player_id) {
    $packet->messages->[0]->{value}->[0] = "$player_id";
  }

  if (ref $metadata) {
    for(keys %$metadata) {
      $packet->messages->[0]->{value}->[1]->{$_} = "$metadata->{$_}";
    }
  }

  my $data = $packet->serialize;

  $browser->post(
    "http://c.brightcove.com/services/amfgateway",
    Content_Type => "application/x-amf",
    Content => $data
  );

  die "Failed to post to Brightcove AMF gateway"
    unless $browser->response->is_success;

  $packet = Data::AMF::Packet->deserialize($browser->content);

  if($self->debug) {
    require Data::Dumper;
    debug Data::Dumper::Dumper($packet);
  }

  if(ref $packet->messages->[0]->{value} ne 'ARRAY') {
    die "Unexpected data from AMF gateway";
  }

  my @found;
  for (@{$packet->messages->[0]->{value}}) {
    if ($_->{data}->{videoDTO}) {
      push @found, $_->{data}->{videoDTO};
    }
    if ($_->{data}->{videoDTOs}) {
      push @found, @{$_->{data}->{videoDTOs}};
    }
  }

  my @rtmpdump_commands;

  for my $d (@found) {
    next if $metadata->{videoId} && $d->{id} != $metadata->{videoId};

    my $host = ($d->{FLVFullLengthURL} =~ m!rtmp://(.*?)/!)[0];
    my $file = ($d->{FLVFullLengthURL} =~ m!&([a-z0-9:]+/.*?)(?:&|$)!)[0];
    my $app = ($d->{FLVFullLengthURL} =~ m!//.*?/(.*?)/&!)[0];
    my $filename = ($d->{FLVFullLengthURL} =~ m!&.*?/([^/&]+)(?:&|$)!)[0];

    $app .= "?videoId=$d->{id}&lineUpId=$d->{lineupId}&pubId=$d->{publisherId}&playerId=$player_id&playerTag=&affiliateId=";

    my $args = {
      app => $app,
      pageUrl => $page_url,
      swfUrl => "http://admin.brightcove.com/viewer/federated/f_012.swf?bn=590&pubId=$d->{publisherId}",
      tcUrl => "rtmp://$host:1935/$app",
      auth => ($d->{FLVFullLengthURL} =~ /^[^&]+&(.*)$/)[0],
      rtmp => "rtmp://$host/$app",
      playpath => $file,
      flv => "$filename.flv",
    };

    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;
}
##} blib/lib/FlashVideo/Site/Brightcove.pm
##{ blib/lib/FlashVideo/Site/About.pm
{
package FlashVideo::Site::About;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
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;
}
##} blib/lib/FlashVideo/Site/About.pm
BEGIN { $INC{'FlashVideo/Site/Adultswim.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Adultswim.pm
{
package FlashVideo::Site::Adultswim;

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 $xml;
	my $id;

	my $segIds;
	if($browser->{content} =~ m/(<meta[^>]* ?name=["']segIds["'] ?[^>]*>)/){
		my $text = $1;
		if($text =~ m/content=["']([^"']+)["']/){
			$segIds = $1;
		}
	}

	my $id1;
	if($segIds =~ m/^([^#]*)#/){
		$id1 = $1;
	}

	my $title;
	if($browser->{content} =~ m/<meta property=["']og:title["'] content=["']([^"']+)["']\/>/){
		$title = $1;
	}

	my $configURL = "/tools/swf/player_configs/watch_player.xml";

		if($browser->content =~ /pageObj\.configURL = ["']([^"']+)["'];/) {
			$configURL = $1;
		}

	$browser->get($configURL);

	my $serviceConfigURL;

	if($browser->response->code =~ /^30\d$/){

		$xml = from_xml($browser);

		if($xml->{serviceConfigURL} ne ""){
			$serviceConfigURL = $1;
		}
	} else {
		$serviceConfigURL = "http://asfix.adultswim.com/staged/AS.configuration.xml";
	}

	$browser->get($serviceConfigURL);

	$xml = from_xml($browser);

	my $getVideoPlayerURL;
	if($xml->{config}->{services}->{getVideoPlaylist}->{url} ne ""){
		$getVideoPlayerURL = $1;
	} else {
		$getVideoPlayerURL = "http://asfix.adultswim.com/asfix-svc/episodeservices/getVideoPlaylist?networkName=AS";
	}

	my $videoURL = "$getVideoPlayerURL&id=$id1";
	$browser->get($videoURL);

	$xml = from_xml($browser);



	my $pick = $xml->{entry}[4];

	my $file_url = $pick->{ref}->{href};


	return $file_url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Adultswim.pm
BEGIN { $INC{'FlashVideo/Site/Amazon.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
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;

  my $parsed_smil = from_xml($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;
}
##} blib/lib/FlashVideo/Site/Amazon.pm
BEGIN { $INC{'FlashVideo/Site/Aniboom.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Aniboom.pm
{
package FlashVideo::Site::Aniboom;

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, $url, $title);

  if ($browser->uri->as_string =~ /\/animation-video\/(\d*)\/([^\/]*)/) {
    $id = $1;
    $title = $2;
    $title =~ s/-/ /g;
  } else {
    die "Could not detect video ID!";
  }
  
  $browser->get("http://www.aniboom.com/animations/player/handlers/animationDetails.aspx?mode=&movieid=$id");

  if ($browser->content =~ /(?:mp4|flv)=([^&]*)/) {
    $url = $1;
    $url =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  } else {
    die "Could not get flv/mp4 location!";
  }
  
  return $url, title_to_filename($title);
}

1;

}
##} blib/lib/FlashVideo/Site/Aniboom.pm
BEGIN { $INC{'FlashVideo/Site/Apple.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Apple.pm
{
package FlashVideo::Site::Apple;
use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  if(!FlashVideo::Downloader->check_file($browser->content)) {
    my @urls = $browser->content =~ /['"]([^'"]+\.mov)(?:\?[^'"]+)?['"]/g;
    die "No .mov URLs found on page" unless @urls;
    debug "Found URLs: @urls";

    my $redirect_url = $prefs->quality->choose(map {
        /(\d+p?)\.mov/ && {
          url => $_,
          resolution => $prefs->quality->format_to_resolution($1)
        }
      } @urls
    )->{url};

    $browser->get($redirect_url);
  }

  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;
}
##} blib/lib/FlashVideo/Site/Apple.pm
BEGIN { $INC{'FlashVideo/Site/Arte.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Arte.pm
{
package FlashVideo::Site::Arte;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my ($lang, $xmlurl1, $xmlurl2, $filename, $videourl, $hash, $playerurl, $quality);

  debug "Arte::find_video called, embed_url = \"$embed_url\"\n";

  my $pageurl = $browser->uri() . "";
  if($pageurl =~ /videos\.arte\.tv\/(..)\//) {
    $lang = $1;
  } else {
    die "Unable to find language in original URL \"$pageurl\"\n";
  }

  if($browser->content =~ /videorefFileUrl = "(.*)";/) {
    $xmlurl1 = $1;
    debug "found videorefFileUrl \"$xmlurl1\"\n";
    ($filename = $xmlurl1) =~ s/-.*$//;
    $filename =~ s/^.*\///g;
    $filename = title_to_filename($filename);
  } else {
    die "Unable to find 'videorefFileUrl' in page\n";
  }

  if($browser->content =~ /<param name="movie" value="(http:\/\/videos\.arte\.tv\/[^\?]+)\?/) {
    $playerurl = $1;
    debug "found playerurl \"$playerurl\"\n";
  }

  $browser->get($xmlurl1);

  if($browser->content =~ /<video lang="$lang" ref="(.*)" \/>/) {
    $xmlurl2 = $1;
    debug "found <video ref=\"$xmlurl2\">\n";
  } else {
    die "Unable to find <video ref...> in XML $xmlurl1\n";
  }

  $browser->get($xmlurl2);
  $quality = {high => 'hd', low => 'sd'}->{$prefs->{quality}};

  if($browser->content =~ /<url quality="$quality">([^<]+)<\/url>/) {
    $videourl = { rtmp => $1,
		flv => $filename};
    if(defined $playerurl) {
      $videourl->{swfVfy} = $playerurl;
    }
  } else {
    die "Unable to find <url ...> in XML $xmlurl2\n";
  }

  return $videourl, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Arte.pm
BEGIN { $INC{'FlashVideo/Site/Bbc.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
use URI;

sub find_video {
  my ($self, $browser, $page_url, $prefs) = @_;

  my $count = 0;
  while((my $location = $browser->response->header("Location")) && $count++ < 5) {
    $browser->get($location);
  }

  my $playlist_xml;
  if ($browser->content =~ /<param name="playlist" value="(http:.+?\.s?xml)"/) {
    $playlist_xml = $1;
  }
  elsif($browser->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 { from_xml($browser, KeyAttr => {item => 'kind'}) };

  if ($@) {
    my $content = $browser->content;
    if ($content !~ m{</media>}) {
      $content .= "\n</media></item></playlist>\n";
    }
    $playlist = from_xml($$content, KeyAttr => {item => 'kind'})
  }

  my $sound = ($playlist->{item}->{guidance} !~ /has no sound/);

  my $info = ref $playlist->{item}->{media} eq 'ARRAY'
    ? $playlist->{item}->{media}->[0]->{connection}
    : $playlist->{item}->{media}->{connection};

  $info = $playlist->{item}->{programme}->{media}->{connection} unless $info;

  $info->{application} ||= "ondemand";

  if (!$info->{server}) {
    my $id = $playlist->{item}->{mediator}->{identifier};
    if(!$id) { $id = $playlist->{item}->{programme}->{mediator}->{identifier}; }

    my $stream_info_url = sprintf
      "http://open.live.bbc.co.uk/mediaselector/4/mtis/stream/%s", $id;

    $browser->back();
    $browser->get($stream_info_url);

    if (!$browser->success) {
      die "Couldn't get BBC stream info URL: " .
        $browser->response->status_line;
    }

    my $stream_info = from_xml($browser->content);

    if( ref $stream_info->{media} eq 'ARRAY' ){
      my $q = $prefs->{quality};
      my @media = sort { $a->{bitrate} <=> $b->{bitrate} } @{$stream_info->{media}};
      my @q_media = grep { $_->{bitrate} == $q || "$_->{height}x$_->{width}x$_->{bitrate}" == $q || "$_->{height}x$_->{width}" == $q } @media;
      if( @q_media ){ @media = @q_media; }
      my $cnt = @media;
      my $num = {high => int($cnt)-1, medium => int($cnt/2), low => 0}->{$q};
      $info = $media[$num]->{connection};
    } else {
      $info = $stream_info->{media}->{connection};
    }
  }

  if( $info->{href} ){
    my $url = $info->{href};
    my @path = URI->new($url)->path_segments();
    return $url, @path[-1];
  }

  my $data = {
    app      => $info->{application},
    tcUrl    => "rtmp://$info->{server}/$info->{application}",
    swfUrl   => "http://news.bbc.co.uk/player/emp/2.11.7978_8433/9player.swf",
    pageUrl  => $page_url,
    rtmp     => "rtmp://" .  $info->{server} . "/$info->{application}",
    playpath => $info->{identifier},
    flv      => title_to_filename('BBC - ' . $playlist->{title} .
                                ($sound ? '' : ' (no sound)'))
  };

  if ($info->{authString}) {
    my $token = $info->{authString};

    $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}" .
                   "&$token";
                    
    $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}"
            . "&$token";

    $data->{playpath} .= "?$token";
  }

  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 = from_xml($browser);

    my $token = $stream_auth->{token};

    if (!$token) {
      die "Couldn't get token for 'secure' video download";
    }

    $data->{app} = "$info->{application}?_fcs_vhost=$info->{server}"
            . "&auth=$token"
            . "&aifp=v001&slist=" . $info->{identifier};
    $data->{tcUrl} = "rtmp://$info->{server}/$info->{application}?_fcs_vhost=$info->{server}"
            . "&auth=$token"
            . "&aifp=v001&slist=" . $info->{identifier};
    $data->{playpath} .= "?auth=$token&aifp=v0001";

    if($info->{application} eq 'live') {
      $data->{subscribe} = $data->{playpath};
      $data->{live} = 1;
    }
  }

  return $data;
}

1;
}
##} blib/lib/FlashVideo/Site/Bbc.pm
BEGIN { $INC{'FlashVideo/Site/Bing.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Bing.pm
{
package FlashVideo::Site::Bing;
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, $prefs) = @_;

  my $count = 0;
  while((my $location = $browser->response->header("Location")) && $count++ < 5) {
    $browser->get($location);
  }

  my $title;
  if ($browser->content =~ /sourceFriendly:\s*'([^']+)'[\s\S]+?\s*title:\s*'([^']+)'/) {
    $title = "$1 - $2";
  }

  my $url;
  if ($browser->content =~ /formatCode:\s*1003,\s*url:\s*'([^']+)'/) {
    $url = $1;

    $url =~ s/\\x([0-9a-f]{2})/chr hex $1/egi;
  }
  die "Unable to extract video url" unless $url;

  $browser->allow_redirects;

  return $url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Bing.pm
BEGIN { $INC{'FlashVideo/Site/Blip.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Blip.pm
{
package FlashVideo::Site::Blip;

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 $base = "http://blip.tv";

  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];
    }
  }

  if (!$id) {
    if ($browser->content =~ /post_masthed_(\d+)/) {
      $id = $1;
    }
  }

  if (!$id) { ($id) = ($browser->content =~ m{data-posts-id="(\d+)"}s); }
  if (!$id) { ($id) = ($browser->content =~ m{data-disqus-id="(\d+)"}s); }
  if (!$id) { ($id) = ($browser->content =~ m{content="http://[^"]-(\d+)"}s); }

  die "No ID found\n" unless $id;

  $browser->get("$base/rss/flash/$id");

  my $xml = from_xml($browser);

  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;
}
##} blib/lib/FlashVideo/Site/Blip.pm
BEGIN { $INC{'FlashVideo/Site/Break.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Break.pm
{
package FlashVideo::Site::Break;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;

sub find_video {
  my($self, $browser, $embed_url) = @_;

  my $video_id;

  if ($browser->content =~ /flashVars\.icon = ["'](\w+)["']/) {
    $video_id = $1;
  }
  else {
    die "Couldn't get Break video ID";
  }

  if($browser->content =~ /<meta name=['"]embed_video_url['"] content=["']([^'"]*)["']/) {
    $browser->get($1);
  }

  if(URI->new($embed_url)->host eq "embed.break.com") {
    $browser->get($embed_url);
  }

  if($browser->uri->host eq "embed.break.com") {
    if(!$browser->success && $browser->response->header('Location') !~ /sVidLoc/) {
      $browser->get($browser->response->header('Location'));
    }

    if($browser->response->header("Location") =~ /sVidLoc=([^&]+)/) {
      my $url = uri_unescape($1).'?'.$video_id;
      my $filename = title_to_filename((split /\//, $url)[-1]);

      return $url, $filename;
    }
  }

  my $path = ($browser->content =~ /sGlobalContentFilePath='([^']+)'/)[0];
  my $filename = ($browser->content =~ /sGlobalFileName='([^']+)'/)[0];

  die "Unable to extract path and filename" unless $path and $filename;

  my $video_path = ($browser->content =~ /videoPath\s*(?:',|=)\s*['"]([^'"]+)/)[0];

  $browser->allow_redirects;

  return $video_path . $path . "/" . $filename . ".flv" . "?" . $video_id,
    title_to_filename($filename);
}

1;
}
##} blib/lib/FlashVideo/Site/Break.pm
BEGIN { $INC{'FlashVideo/Site/Canalvie.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
#
#################################################
#	Canalvie.pm												2010-11-25
#
#	Reverse-engineered using URLSnooper v2.28.01 & WinPcap 4.1.2
#
#	Stavr0
#
#
##{ blib/lib/FlashVideo/Site/Canalvie.pm
{
{
package FlashVideo::Site::Canalvie;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  my $check_response = sub {
    my ( $message ) = @_;
    return if $browser->success;
    die sprintf $message, $browser->response->code;
  };


  my $videoID = 0;

  ( $videoID ) = ( $browser->content =~ /var\s+videoId\s*=\s*(\d+)\s*;/ );
  debug "VIDEOID = " . $videoID;
  
  die "No Canalvie Video ID found" unless  $videoID;
  
  my $title;
  ( $title ) = ( $browser->content =~ /NOM EPISODE\+LIEN ici --><a [^>]+>([^<]+)/ );
  debug "TITLE = " . $title . " " . title_to_filename($title, 'flv');
 
  my $xmlurl = 'http://www.canalvie.com/webtele/_dyn/getVideoDataXml.jsp?videoId=' . $videoID;
  $browser->get($xmlurl);
  my $xml = from_xml($browser);
  
  my $url;
  if ( $prefs->{quality} == "high" ) {
	$url = $xml->{video}->{highFlvUrl};
  } else {		
  	$url = $xml->{video}->{lowFlvUrl};
  }
  debug "URL = " . $url;
  
  my $ext;
  ( $ext ) = ( $url =~ /\.(.+)$/ );

  die "No (high|low)FlvUrl found in XML ". $xmlurl unless $url;
  
  return $url, title_to_filename($title, $ext);
  
 }


1;
}}
##} blib/lib/FlashVideo/Site/Canalvie.pm
BEGIN { $INC{'FlashVideo/Site/Canoe.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Canoe.pm
{
package FlashVideo::Site::Canoe;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Brightcove';

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id  = ($browser->content =~ /player.SetVideo.(\d+)/i)[0];
  my $player_id = ($browser->content =~ /player.SetPlayer.(\d+)/i)[0];

  debug "Extracted playerId: $player_id, videoId: $video_id"
    if $player_id or $video_id;

  if(!$video_id) {
    my $video_offset = ($browser->content =~ /player.SetVideo.\w+\[(\d+)/i)[0];
    $video_id = ($browser->content =~ /videos\[$video_offset\].+'(\d+)'\s*\]/)[0];
  }

  die "Unable to extract Brightcove IDs from page"
    unless $player_id and $video_id;

  return $self->amfgateway($browser, $player_id, { videoId => $video_id, } );
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return $browser->content =~ /player = CanoeVideoStandalone\.create\(\);/i;
}

1;
}
##} blib/lib/FlashVideo/Site/Canoe.pm
BEGIN { $INC{'FlashVideo/Site/Cartoonnetwork.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Cartoonnetwork.pm
{
package FlashVideo::Site::Cartoonnetwork;

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 POSIX();

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id;
  if ($browser->uri->as_string =~ /episodeID=([a-z0-9]*)/) {
    $video_id = $1;
  }

  $browser->get("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeSearch/getEpisodesByIDs?ids=$video_id");
  my $xml = from_xml($browser);
  my $episodes = $xml->{episode};
  my $episode = ref $episodes eq 'ARRAY' ?
    (grep { $_->{id} eq $video_id } @$episodes)[0] :
    $episodes;

  my $title = $episode->{title};

  my @gmtime = gmtime;
  $gmtime[1] = 15 * int($gmtime[1] / 15);
  my $date = POSIX::strftime("%m%d%Y%H%M", @gmtime);

  my $url;
  foreach my $key (keys (%{$episode->{segments}->{segment}})){
    my $content_id = $key;
    $browser->post("http://www.cartoonnetwork.com/cnvideosvc2/svc/episodeservices/getVideoPlaylist",
      Content  => "id=$content_id&r=$date"
    );

    if ($browser->content =~ /<ref href="([^"]*)" \/>/){
      $url = $1;
    }
  }

  return $url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Cartoonnetwork.pm
BEGIN { $INC{'FlashVideo/Site/Cbs.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Cbs.pm
{
package FlashVideo::Site::Cbs;

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 $pid;
  if ($browser->uri->as_string =~ /pid=([^&]*)/) {
    $pid = $1;
  }

  $browser->get("http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&MBR=true&pid=$pid");

  my $xml = from_xml($browser->content);

  my $items = $xml->{body}->{switch};
  my $item = ref $items eq 'ARRAY' ?
    (grep { $_->{video}->{src} =~ /^rtmp:\/\// } @$items)[0] :
    $items;

  my $rtmpurl = $item->{video}->{src};
  $rtmpurl =~ s/<break>.*//;
  my $title = $item->{ref}->{title};

  return {
    rtmp => $rtmpurl,
    flv => title_to_filename($title)
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Cbs.pm
BEGIN { $INC{'FlashVideo/Site/Cbsnews.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
BEGIN { $INC{'FlashVideo/Site/Cnet.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Cnet.pm
{
package FlashVideo::Site::Cnet;

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; }

my $cnet_api_base = "http://api.cnet.com";
my $cnet_api_rest = $cnet_api_base . "/restApi/v1.0";
my $cnet_api_video_search = $cnet_api_rest . "/videoSearch";


sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id;

  if($browser->content =~ /<param name="FlashVars" value="playerType=embedded&type=id&value=([0-9]+)" \/>/) {
    $video_id = $1;
  } elsif($browser->content =~ /assetId: '([0-9]+)',/) {
    $video_id = $1;
  } else {
    die "Could not find video ID; you may have to click the 'share' link on the flash player to get the permalink to the video.";
  }

  return $self->get_video($browser, $video_id);
}

sub get_video {
  my ($self, $browser, $video_id) = @_;

  $browser->get($cnet_api_video_search . "?videoIds=" . $video_id . "&iod=videoMedia&players=RTMP");

  my $xml = from_xml($browser->content, NoAttr => 1);

  my $video = $xml->{"Videos"}->{"Video"};

  my $medias = $video->{"VideoMedias"}->{"VideoMedia"};

  my $max = 0;
  foreach (@{$video->{VideoMedias}->{VideoMedia}}) {
    if(int($_->{Width}) * int($_->{Height}) > $max){
      $max = int($_->{Width}) * int($_->{Height});
    }
  }
  my $media = (grep { (int($_->{Width}) * int($_->{Height})) eq $max } @$medias)[0];
  my $delivery_url = $media->{DeliveryUrl};

  my $title = $video->{FranchiseName} . ' - ' . $video->{Title};

  if($media->{Player} eq 'RTMP'){
    return {
      rtmp => $delivery_url,
      flv => title_to_filename($title)
    };
  } elsif($media->{Player} eq 'Download'){
    return $delivery_url, title_to_filename($title)
  }
}

1;

}
##} blib/lib/FlashVideo/Site/Cnet.pm
##{ blib/lib/FlashVideo/Site/Cbsnews.pm
{
package FlashVideo::Site::Cbsnews;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
BEGIN { FlashVideo::Site::Cnet->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Cnet';

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id;
  if($browser->content =~ /CBSVideo\.setVideoId\(["']([0-9]+)["']\)/) {
    $video_id = $1;
  } else {
    die "Could not find video id. If this is a valid CBS News video, please file a bug report at http://code.google.com/p/get-flash-videos/issues";
  }
  return $self->get_video($browser, $video_id);
}

1;
}
##} blib/lib/FlashVideo/Site/Cbsnews.pm
BEGIN { $INC{'FlashVideo/Site/Channel4.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
#
#################################################
# Thanks to Nibor for his XBMC 4od plugin - this is largely a Perl port of
# it.
##{ blib/lib/FlashVideo/Site/Channel4.pm
{
package FlashVideo::Site::Channel4;

use strict;

use Crypt::Blowfish_PP;
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; *url_exists = \&FlashVideo::Utils::url_exists; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; *from_xml = \&FlashVideo::Utils::from_xml; }
use MIME::Base64;

use constant TOKEN_DECRYPT_KEY => 'STINGMIMI';

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  my $page_url = $browser->uri->as_string;

  my $series_and_episode;
  if ($browser->content =~ /<meta\ property="og:image"
                            \ content="\S+series-(\d+)\/episode-(\d+)/x) {
    $series_and_episode = sprintf "S%02dE%02d", $1, $2;
  }

  my $swf_player;
  if ($browser->content =~ /fourodPlayerFile\s+=\s+\'(4od\S+\.swf)\'/i) {
    $swf_player = $1;
  }
  else {
     $swf_player = '4odplayer-11.21.2.swf';
  }

  my $asset_id;

  if ($page_url =~ m'(?:4od/player/|4od[^\/]*#)(\d+)') {
    $asset_id = $1;
  }
  else {
    die "Can't get asset ID";
  }

  my $raw_xml = $browser->get("http://ais.channel4.com/asset/$asset_id");

  if (!$browser->success) {
    die "Couldn't get asset XML: " . $browser->status_line;
  }

  my $xml = from_xml($raw_xml);

  my $stream_url = $xml->{assetInfo}->{uriData}->{streamUri};
  my $token      = $xml->{assetInfo}->{uriData}->{token};
  my $cdn        = $xml->{assetInfo}->{uriData}->{cdn};

  my $decoded_token = decode_4od_token($token);

  my $auth;

  if ($cdn eq 'll') {
    my $ip = $xml->{assetInfo}->{uriData}->{ip};
    my $e  = $xml->{assetInfo}->{uriData}->{e};

    if (defined $ip) {
      $auth = sprintf "e=%s&ip=%s&h=%s", $e, $ip, $decoded_token;
    }
    else {
      $auth = sprintf "e=%s&h=%s", $e, $decoded_token;
    }
  }
  else {
    my $fingerprint = $xml->{assetInfo}->{uriData}->{fingerprint};
    my $slist       = $xml->{assetInfo}->{uriData}->{slist};

    $auth = sprintf "auth=%s&aifp=%s&slist=%s",
      $decoded_token, $fingerprint, $slist;
  }

  my $title;
  my @title_components = grep defined,
                         map { $xml->{assetInfo}->{$_} }
                         qw(brandTitle episodeTitle);

  if ($series_and_episode) {
    push @title_components, $series_and_episode;
  }

  if (@title_components) {
    $title = join " - ", @title_components;
  }
  
  my $filename = title_to_filename($title, "mp4");

  if ($prefs->subtitles) {
    if (my $subtitles_url = $xml->{assetInfo}->{subtitlesFileUri}) {
      $subtitles_url = "http://ais.channel4.com$subtitles_url";
      
      $browser->get($subtitles_url);

      if (!$browser->success) {
        info "Couldn't download 4od subtitles: " . $browser->status_line;
      }

      my $subtitles_file = title_to_filename($title, "srt");
      convert_sami_subtitles_to_srt($browser->content, $subtitles_file); 

      info "Saved subtitles to $subtitles_file";
    }
    else {
      debug("Subtitles requested for '$title' but none available.");
    }
  }

  my $rtmp_url;
  
  if ($stream_url =~ /(.*?)mp4:/) {
    $rtmp_url = $1;
  }

  $rtmp_url =~ s{\.com/}{.com:1935/};
  $rtmp_url .= "?ovpfv=1.1&$auth";
  
  my $app;
  if ($stream_url =~ /.com\/(.*?)mp4:/) {
    $app = $1;
    $app .= "?ovpfv=1.1&$auth";
  }

  my $playpath;
  if ($stream_url =~ /.*?(mp4:.*)/) {
    $playpath = $1;
    $playpath .= "?$auth";
  }

  my $swf_player_url = url_exists($browser, "http://www.channel4.com/static/programmes/asset/flash/swf/$swf_player");

  if (!$swf_player_url) {
     die "swf url not found";
  }
  
  return {
    flv      => $filename,
    rtmp     => $rtmp_url,
    flashVer => '"WIN 11,0,1,152"',
    swfVfy   => "$swf_player_url",
    conn     => 'Z:',
    playpath => $playpath,
    pageUrl  => $page_url,
    app      => $app,
  };
}

sub decode_4od_token {
  my $encrypted_token = shift;

  $encrypted_token = decode_base64($encrypted_token);

  my $blowfish = Crypt::Blowfish_PP->new(TOKEN_DECRYPT_KEY);

  my $decrypted_token = '';

  my $position = 0;

  while ( $position < length $encrypted_token) {
    $decrypted_token .= $blowfish->decrypt(substr $encrypted_token, $position, 8);
    $position += 8;
  }

  my $npad = unpack("c", substr($decrypted_token, -1));
  if ($npad > 0 && $npad < 9) {
    $decrypted_token = substr($decrypted_token, 0, length($decrypted_token)-$npad);
  }
  return $decrypted_token;
}

1;
}
##} blib/lib/FlashVideo/Site/Channel4.pm
BEGIN { $INC{'FlashVideo/Site/Channel5.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Channel5.pm
{
package FlashVideo::Site::Channel5;

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; }
use MIME::Base64;

my $encode_rates = {
     "low" => 480,
     "medium" => 800,
     "medium2" => 1200, 
     "high" => 1500 };

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  my $metadata = { };
  my ($video_id, $player_id);

  $player_id = ($browser->content =~ /playerId["'\] ]*[:=]["' ]*(\d+)/i)[0];
  $metadata->{videoplayer} = ($browser->content =~ /videoPlayer=ref:(C\d+)/i)[0];
  $metadata->{publisherId} = ($browser->content =~ /publisherID=(\d+)/i)[0];

  $player_id ||= ($browser->content =~ /<param name=["']?playerID["']? value=["'](\d+) ?["']/i)[0];
  $metadata->{videoplayer} ||= ($browser->content =~ /param name=["']?\@videoPlayer["']? value=["']?(\d+)["']?/i)[0];
  $metadata->{publisherId} ||= ($browser->content =~ /param name=["']?publisherID["']? value=["']?(\d+)["']?/i)[0];

  $player_id ||= ($browser->content =~ /flashVars.*playerID=(\d+)/i)[0];

  if(!$player_id && $browser->content =~ /brightcove.player.create\(['"]?(\d+)['"]?,\s*['"]?(\d+)/) {
    $player_id = $2;
  }

  $metadata->{sessionId} = ($browser->cookie_jar->as_string =~ /session=([0-9a-f]*);/)[0];

  for my $url($browser->uri->as_string, $embed_url) {

    if($url =~ /(?:playerID|bcpid)=?(\d+)/i) {
      $player_id ||= $1;
    }
  }

  debug "Extracted playerId: $player_id, sessionId: $metadata->{sessionId} videoplayer: $metadata->{videoplayer} publisherId: $metadata->{publisherId} "
    if $player_id or $video_id;

  die "Unable to extract Brightcove IDs from page" unless $player_id;

  return $self->amfgateway($browser, $player_id, $metadata, $prefs);
}

sub amfgateway {
  my($self, $browser, $player_id, $metadata, $prefs) = @_;

  my $has_amf_packet = eval { require Data::AMF::Packet };
  if (!$has_amf_packet) {
    die "Must have Data::AMF::Packet installed to download Brightcove videos";
  }

  my $page_url = $browser->uri;
  my $base_url = "" . $page_url;


  my $amf0_formatter = Data::AMF::Formatter->new(version =>0);
  my $amf3_formatter = Data::AMF::Formatter->new(version =>3);
  my @amf_pkt;


  $amf_pkt[0] = decode_base64(<<EOF1);
AAMAAAABAEZjb20uYnJpZ2h0Y292ZS5leHBlcmllbmNlLkV4cGVyaWVuY2VSdW50aW1lRmFjYWRl
LmdldERhdGFGb3JFeHBlcmllbmNlAAIvMQAA
EOF1

  $amf_pkt[2] = decode_base64(<<EOF2);
CgAAAAI=
EOF2

  $amf_pkt[3] = $amf0_formatter->format($metadata->{sessionId});

  $amf_pkt[4] = decode_base64(<<EOF3);
EQpjY2NvbS5icmlnaHRjb3ZlLmV4cGVyaWVuY2UuVmlld2VyRXhwZXJpZW5jZVJlcXVlc3QhY29u
dGVudE92ZXJyaWRlcwdVUkwZZXhwZXJpZW5jZUlkEVRUTFRva2VuE3BsYXllcktleRlkZWxpdmVy
eVR5cGUJAwEKgQNTY29tLmJyaWdodGNvdmUuZXhwZXJpZW5jZS5Db250ZW50T3ZlcnJpZGUXY29u
dGVudFR5cGUTY29udGVudElkGWNvbnRlbnRSZWZJZBtmZWF0dXJlZFJlZklkG2NvbnRlbnRSZWZJ
ZHMVZmVhdHVyZWRJZBVjb250ZW50SWRzDXRhcmdldAQABX/////gAAAA
EOF3

  $amf_pkt[5] = $amf3_formatter->format($metadata->{videoplayer});

  $amf_pkt[6] = decode_base64(<<EOF4);
AQEFf////+AAAAABBhd2aWRlb1BsYXllcg==
EOF4

  $amf_pkt[7] = $amf3_formatter->format($base_url);

  $amf_pkt[8] = decode_base64(<<EOF5);
BUI4gZvSwQAABgEGAQV/////4AAAAA==
EOF5
  my $experianceid = $amf3_formatter->format($player_id);
  $amf_pkt[8] = $experianceid . substr($amf_pkt[8], 7);


  $amf_pkt[1] = pack('n', length(join('',@amf_pkt[2..8])));

  my $data = join('',@amf_pkt[0..8]);





  $browser->post(
    "http://c.brightcove.com/services/messagebroker/amf?playerid=$player_id",
    Content_Type => "application/x-amf",
    Content => $data
  );

  die "Failed to post to Brightcove AMF gateway"
    unless $browser->response->is_success;

  my $packet = Data::AMF::Packet->deserialize($browser->content);

  if($self->debug) {
    require Data::Dumper;
    debug Data::Dumper::Dumper($packet);
  }

  if ( ref  $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions} ne 'ARRAY') {
    die "Unexpected data from AMF gateway";
  }

  my @found;
  for (@{$packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{renditions}}) {
    if ($_->{defaultURL}) {
      push @found, $_;
    }
  }

  my $mediaId = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaId};
  my $seasonnumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{seasonnumber};
  my $episodenumber = $packet->messages->[0]->{value}->{programmedContent}->{videoPlayer}->{mediaDTO}->{customFields}->{episodenumber};
  my $show = ($page_url =~ m!/shows/([^/]+)/!i)[0];
  my $episode = ($page_url =~ m!/episodes/([^/]+)!i)[0];
  my $filehead = $show . "_Series" . $seasonnumber;
  if ( $show ne $episode ) {
    $filehead = $filehead . "_Episode" . $episodenumber . "_" . $episode;
  }
  my $encode_rate = $encode_rates->{$prefs->{quality}};
  if (! defined $encode_rate ) {
    $encode_rate = $prefs->{quality};
  }

  my @rtmpdump_commands;

  for my $d (@found) {

    my $rate = ($d->{defaultURL} =~ /H264-(\d+)-16x9/i)[0];
    next if $encode_rate != $rate;
    my $host = ($d->{defaultURL} =~ m!rtmpe://(.*?)/!)[0];
    my $file = ($d->{defaultURL} =~ /^[^&]+&(.*)$/)[0];
    my $app = ($d->{defaultURL} =~ m!//.*?/(.*?)/&!)[0];
    my $filename = $filehead . "_" . $rate;

    $app .= "?videoId=$mediaId&lineUpId=&pubId=$metadata->{publisherId}&playerId=$player_id&affiliateId=";

    my $args = {
      app => $app,
      pageUrl => $page_url,
      swfVfy => "http://admin.brightcove.com/viewer/us1.24.04.08.2011-01-14072625/connection/ExternalConnection_2.swf",
      tcUrl => "rtmpe://$host:1935/$app",
      rtmp => "$d->{defaultURL}",
      playpath => $file,
      flv => "$filename.flv",
    };

    if ($d->{publisherName} and $d->{displayName}) {
      $args->{flv} = title_to_filename("$d->{publisherName} - $d->{displayName}");
    }


    push @rtmpdump_commands, $args;
  }

  if (@rtmpdump_commands > 1) {
    return \@rtmpdump_commands;
  }
  else {
    return $rtmpdump_commands[-1];
  }
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return 1 if $url && URI->new($url)->host =~ /\.channel5\.com$/;

  return $browser->content =~ /(playerI[dD]|brightcove.player.create)/
    && $browser->content =~ /brightcove/i;
}

1;
}
##} blib/lib/FlashVideo/Site/Channel5.pm
BEGIN { $INC{'FlashVideo/Site/Collegehumor.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Collegehumor.pm
{
package FlashVideo::Site::Collegehumor;

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; *from_xml = \&FlashVideo::Utils::from_xml; }

sub find_video {
  my ($self, $browser, $embed_url) = @_;
  my $base = "http://www.collegehumor.com/moogaloop";

  my $id;
  if($browser->content =~ /video:(\d+)/) {
    $id = $1;
  } elsif($embed_url =~ m![/:](\d+)!) {
    $id = $1;
  }
  die "No ID found\n" unless $id;

  $browser->get("$base/video:$id");

  my $xml = from_xml($browser);

  my $title = $xml->{video}->{caption};
  $title = extract_title($browser) if ref $title;

  return $xml->{video}->{file}, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Collegehumor.pm
BEGIN { $INC{'FlashVideo/Site/Ctv.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
#
#################################################
#
#	Handler module for CTV Canadian broadcaster
#	- Requires RTMPDUMP
#	- Expects an URL in the form of: http://watch.ctv.ca/ $show / $season / $episode /
#	- Each show is split in clips intersected with commercial breaks, so there will be several calls to RTMPDUMP
#	- Streams are restricted to Canadian ISPs
#
#	Stavr0
#
##{ blib/lib/FlashVideo/Site/Ctv.pm
{
package FlashVideo::Site::Ctv;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }

sub find_video {
  my($self, $browser, $page_url) = @_;

  my $entityid = ($browser->content =~ /<meta name="EntityId" content="(\d+)"/i)[0];
  debug "EntityID = " . $entityid;

  die "Couldn't find EntityId in <meta> tags" unless $entityid;

  $browser->get("http://watch.ctv.ca/AJAX/ClipLookup.aspx?callfunction=Playlist.GetInstance.AddEpisodeClipsAfter&episodeid=$entityid&maxResults=99");
  die "Couldn't download playlist: " . $browser->response->status_line
    if !$browser->success;

  my $plist = $browser->content;
  my @found;
  while ($plist =~ /(videoArray\.push[^}]+} \) \);)/gi) {
    push @found, ($1 =~ /Format\:'FLV', ClipId\:'(\d+)'/i);
  }

  my @rtmpdump_commands;

  for my $clipid (@found) {
    debug "clipID = $clipid";
    my $rand =  int rand 999999;
    $browser->get("http://esi.ctv.ca/datafeed/flv/urlgenjs.aspx?vid=$clipid&timeZone=-4&random=$rand");

    if ($browser->content =~ /(rtmpe\:\/\/[^\']+)/) {
      my $rtmp = $1;
      my $tcurl = ($rtmp =~ /\?(auth=.+)/ )[0];
      my $filename =  ($rtmp =~ /([^\?\/]+)\?/ )[0];
      $filename =~ s/\.mp4/\.flv/;

      debug "$rtmp, $tcurl, $filename";

      push @rtmpdump_commands, {
        app => "ondemand?$tcurl",
        pageUrl => $page_url,
        swfUrl => "http://watch.ctv.ca/Flash/player.swf?themeURL=http://watch.ctv.ca/themes/CTV/player/theme.aspx",
        tcUrl => "rtmpe://cp45924.edgefcs.net/ondemand?$tcurl",
        auth => ($rtmp =~ /auth=([^&]+)/)[0],
        rtmp => $rtmp,
        playpath => "mp4:" . ($rtmp =~ /ondemand\/(.+)/)[0],
        flv => $filename,
      };
    } elsif($browser->content =~ /geoblock/) {
      die "CTV returned geoblock (content not available in your country)\n";
    }
  }

  return \@rtmpdump_commands;
}

sub can_handle {
  my($self, $browser, $url) = @_;
  return $url =~ m{watch\.ctv\.ca};
}

1;
}
##} blib/lib/FlashVideo/Site/Ctv.pm
BEGIN { $INC{'FlashVideo/Site/Dailymotion.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Dailymotion.pm
{
package FlashVideo::Site::Dailymotion;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  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 =~ /<h1[^>]*>(.*?)<\//;
  my $filename = title_to_filename($1);

  my $video;
  if ($browser->content =~ /"video", "([^"]+)/) {
    $video = uri_unescape($1);
  }
  if (!$video && $browser->content =~ /"sequence", *"([^"]+)/) {
    my $data = json_unescape(uri_unescape($1));
    my ($low) = $data =~ /"sdURL" *: *"([^"]+)"/i;
    my ($high) = $data =~ /"hqURL" *: *"([^"]+)"/i;
    if($data =~ /"videoTitle" *: *"([^"]+)"/i){
      my $title = uri_unescape($1);
      $title =~ s/\+/ /g;
      $filename = title_to_filename($title);
    }
    if( $prefs->{quality} == 'high' && $high ){ $video = $high; }
    elsif( $low ){ $video = $low; }
  }
  if(!$video) {
    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));
    }
  }

  if(!$video) {
    my($package, $possible_url) = FlashVideo::URLFinder->find_package($browser->uri, $browser);

    if($package ne __PACKAGE__) {
      return $package->find_video($browser, $possible_url, $prefs);
    }
  }

  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;
}
##} blib/lib/FlashVideo/Site/Dailymotion.pm
BEGIN { $INC{'FlashVideo/Site/Daum.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Daum.pm
{
package FlashVideo::Site::Daum;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use HTML::Entities qw(decode_entities);

sub find_video {
  my ($self, $browser) = @_;

  my $video_id = get_video_id($browser);
  debug "Video ID: $video_id";

  my $video_title = get_video_title($browser, $video_id);
  debug "Video title: $video_title";

  my $video_url = get_video_url($browser, $video_id);
  debug "Video URL: $video_url";

  return $video_url, title_to_filename($video_title);
}


sub is_valid_video_id {
  my ($video_id) = @_;

  return if !defined $video_id;

  return if length $video_id != 12;

  return if $video_id !~ /\$$/xms;

  return 1;
}

sub get_video_id {
  my ($browser) = @_;

  my $singer_url
    = quotemeta 'http://media.daum.net/entertain/showcase/singer/';
  my $singer_url_pattern = qr{^ $singer_url .* [#] (\d+) $}xmsi;
  if ( $browser->uri()->as_string() =~ $singer_url_pattern ) {
    my $id = $1;
    return get_video_id_for_singer($browser, $id);
  }

  if ( $browser->uri()->as_string() =~ /[#] clipid = (\d+)/xmsi ) {
    my $url = 'http://tvpot.daum.net/clip/ClipView.do?clipid=' . $1;
    $browser->get($url);
    if ( !$browser->success() ) {
      die "Cannot fetch the document identified by the given URL: $url\n";
    }
  }

  my $document = $browser->content();

  my $flv_player_url = quotemeta 'http://flvs.daum.net/flvPlayer.swf';
  my $video_id_pattern_1 = qr{['"] $flv_player_url [?] vid = ([^'"&]+)}xmsi;

  my $function_name      = quotemeta 'Story.UI.PlayerManager.createViewer';
  my $video_id_pattern_2 = qr{$function_name [(] '(.+?)' [)]}xms;

  if (    $document !~ $video_id_pattern_1
       && $document !~ $video_id_pattern_2 )
  {
    die "Cannot find video ID from the document.\n";
  }
  my $video_id = $1;

  $video_id =~ s/\s+//xmsg;

  die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id);

  return $video_id;
}

sub get_video_id_for_singer {
  my ($browser, $id) = @_;

  my $document = $browser->content();

  my $video_id_pattern = qr{id:'$id', \s* vid:'(.+?)'}xms;
  if ( $document !~ $video_id_pattern ) {
    die "Cannot find video ID from the document.\n";
  }
  my $video_id = $1;

  $video_id =~ s/\s+//xmsg;

  die "Invalid video ID: $video_id\n" if !is_valid_video_id($video_id);

  return $video_id;
}

sub get_video_title {
  my ($browser, $video_id) = @_;

  my $query_url = "http://tvpot.daum.net/clip/ClipInfoXml.do?vid=$video_id";

  $browser->get($query_url);
  if ( !$browser->success() ) {
    die "Cannot fetch the document identified by the given URL: $query_url\n";
  }

  my $document = $browser->content();

  my $video_title_pattern
    = qr{<TITLE> <!\[CDATA \[ (.+?) \] \]> </TITLE>}xmsi;
  if ( $document !~ $video_title_pattern ) {
    die "Cannot find video title from the document.\n";
  }
  my $video_title = $1;

  $video_title = decode_entities($video_title);

  return $video_title;
}

sub get_video_url {
  my ($browser, $video_id) = @_;

  my $query_url
    = 'http://stream.tvpot.daum.net/fms/pos_query2.php'
    . '?service_id=1001&protocol=http&out_type=xml'
    . "&s_idx=$video_id";

  $browser->get($query_url);
  if ( !$browser->success() ) {
    die "Cannot fetch the document identified by the given URL: $query_url\n";
  }

  my $document = $browser->content();

  my $video_url_pattern = qr{movieURL = "(.+?)"}xmsi;
  if ( $document !~ $video_url_pattern ) {
    die "Cannot find video URL from the document.\n";
  }
  my $video_url = $1;

  return $video_url;
}

1;
}
##} blib/lib/FlashVideo/Site/Daum.pm
BEGIN { $INC{'FlashVideo/Site/Divxstage.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Divxstage.pm
{
package FlashVideo::Site::Divxstage;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; }
use URI;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my ($file) = ($browser->content =~ /flashvars.file\s*=\s*"([a-f0-9]+)"/);
  my ($filekey) = ($browser->content =~ /flashvars.filekey\s*=\s*"([.\-a-f0-9]+)"/);
  
  my ($filename) = title_to_filename(extract_title($browser));
  $filename =~ s/_-_DivxStage//i;
  
  my %query_params = (
    'codes'=>'1',
    'file'=>$file,
    'key'=>$filekey,
    'pass'=>'undefined',
    'user'=>'undefined',);
  
  info "Sending query to DivxStage Player API.";
  
  my $uri = URI->new( "http://www.divxstage.eu/api/player.api.php" );
  $uri->query_form(%query_params);
  
  my $contents = $browser->get($uri)->content;
  my ($url) = ($contents =~ /url=(.*?)&/);

  die "Couldn't find video URL from the player API." unless $url;
  
  info "Got the real video URL: ".$url;
  $filename ||= ($contents =~ /title=(.*?)&/)[0]; #probably the most reliable source of title
  $filename ||= get_video_filename();

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Divxstage.pm
BEGIN { $INC{'FlashVideo/Site/Ehow.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Ehow.pm
{
package FlashVideo::Site::Ehow;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;

sub find_video {
  my ($self, $browser) = @_;

  my $uri;
  if ($browser->content =~ /source=(.*?)[ &]/) {
    $uri = $1;
  }
  else {
    die "Couldn't extract video location from page";
  }

  my $title;
  if ($browser->content =~ /<h1[^>]* class="[^"]*articleTitle[^"]*"[^>]*>(.*?)<\/h1>/x) {
    $title = $1;
  }

  if($uri =~ /^http:/) {
    return $uri, title_to_filename($title);
  }
	elsif($uri =~ /http:%3A/) {
		$uri = uri_unescape($1);
		if ($browser->content =~ /<a[^>]*>(.*?)<\/a>/) {
			$title = $1;
		}
		return $uri, title_to_filename($title);
	}
	else {
		die "Couldn't extract Flash video URL from embed page";
	}
}


1;
}
##} blib/lib/FlashVideo/Site/Ehow.pm
BEGIN { $INC{'FlashVideo/Site/Escapistmagazine.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
BEGIN { $INC{'FlashVideo/JSON.pm'}++; }
##{ blib/lib/FlashVideo/JSON.pm
{
package FlashVideo::JSON;

use strict;
use Exporter;use base 'Exporter';
our @EXPORT = qw(from_json);

my $number = qr{(?:-?\b(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b)};
my $oneChar = qr{(?:[^\0-\x08\x0a-\x1f\"\\]|\\(?:["/\\bfnrt]|u[0-9A-Fa-f]{4}))};
my $string = qr{(?:"$oneChar*")};
my $jsonToken = qr{(?:false|true|null|[\{\}\[\]]|$number|$string)};
my $escapeSequence = qr{\\(?:([^u])|u(.{4}))};

my %escapes = (
  '\\' => '\\',
  '"' => '"',
  '/' => '/',
  'b' => "\b",
  'f' => "\f",
  'n' => "\xA",
  'r' => "\xD",
  't' => "\t"
);

sub from_json {
  my($in) = @_;

  my @tokens = $in =~ /$jsonToken/go;
  my $result = $tokens[0] eq '{' ? {} : [];
  shift @tokens if $tokens[0] =~ /^[\[\{]/;

  my $key; # key to use for next value
  my @stack = $result;
  for my $t(@tokens) {
    my $ft = substr $t, 0, 1;
    my $cont = $stack[0];

    if($ft eq '"') {
      my $s = substr $t, 1, length($t) - 2;
      $s =~ s/$escapeSequence/$1 ? $escapes{$1} : chr hex $2/geo;
      if(!defined $key) {
        if(ref $cont eq 'ARRAY') {
          $cont->[@$cont] = $s;
        } else {
          $key = $s;
          next; # need to save $key
        }
      } else {
        $cont->{$key} = $s;
      }
    } elsif($ft eq '[' || $ft eq '{') {
      unshift @stack,
        (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) = $ft eq '[' ? [] : {};
    } elsif($ft eq ']' || $ft eq '}') {
      shift @stack;
    } else {
      (ref $cont eq 'ARRAY' ? $cont->[@$cont] : $cont->{$key}) =
          $ft eq 'f' ? 0 # false
        : $ft eq 'n' ? undef # null
        : $ft eq 't' ? 1 # true
        : $t; # sign or digit
    }
    undef $key;
  }

  return $result;
}

1;
}
##} blib/lib/FlashVideo/JSON.pm
##{ blib/lib/FlashVideo/Site/Escapistmagazine.pm
{
package FlashVideo::Site::Escapistmagazine;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my ($self, $browser, $embed_url) = @_;
  my $title;
	my $url;
	if ($browser->content =~ /<div[^>]*class=['"]name['"]>(.*?)<\/div>/) {
		$title = $1;
		$title =~ s/<[^>]*>//g;
	} else {
		$title = extract_title($browser);
	}

	my $config_url;
	if ($browser->content =~ /<param name=['"]flashvars['"] value=['"]config=([^'"]*)['"]/) {
		$config_url = $1;
	} else {
		die "No Video Info URL Found\n";
	}

	$browser->add_header(Accept => '*/*');
	$browser->get("$config_url");
	my $replaced = $browser->content;
	$replaced =~ s/'/"/g;
	my $json = from_json($replaced);

	my $item;
	for $item (@{$json->{playlist}}) {
		if ($item->{eventCategory} eq "Video") {
			$url = $item->{url};
		}
	}
	return $url, title_to_filename($title);
}
}
##} blib/lib/FlashVideo/Site/Escapistmagazine.pm
BEGIN { $INC{'FlashVideo/Site/Expertvillage.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Expertvillage.pm
{
package FlashVideo::Site::Expertvillage;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
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{<h1[^>]*>(.*)</h1>}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 =~ /<param name=["']flashvars["'] value=["']file=([a-f0-9]{32})/) {
    $id = $1;
  }

  if (!$id and $browser->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)</)[0];

  if (!$flv_url) {
    $browser->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)</)[0];
  }

  my $filename = ($browser->content =~ /<t [^>]+>([^<]+)/)[0];
  $filename = title_to_filename($filename);

  $browser->allow_redirects;

  return $flv_url, $filename;
}

sub _get_soap_xml {
  my $id = shift;

  return <<EOF
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
  <i0:ad xmlns:i0="urn:fliqz.s.mac.20071201">
  <i0:rq>
    <i0:a>$id</i0:a>
    <i0:pu></i0:pu>
    <i0:pid>1F866AF1-1DB0-4864-BCA1-6236377B518F</i0:pid>
  </i0:rq>
</i0:ad> 
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
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]+.*?)&quot/;
  ($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 = <STDIN>);
        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{<video_title>(.*)</video_title>};
  my($instance) = $browser->content =~ m{<video_instance>(.*)</video_instance>};
  my($file) = $browser->content =~ m{<video_file>(.*)</video_file>};

  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      => <<EOF);
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP-ENV:Body>
    <tem:GetPlaylist xmlns:tem="http://tempuri.org/" xmlns:itv="http://schemas.datacontract.org/2004/07/Itv.BB.Mercury.Common.Types" xmlns:com="http://schemas.itv.com/2009/05/Common">
      <tem:request>
        <itv:RequestGuid>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</itv:RequestGuid>
        <itv:Vodcrid>
          <com:Id>$id</com:Id>
          <com:Partition>itv.com</com:Partition>
        </itv:Vodcrid>
      </tem:request>
      <tem:userInfo>
        <itv:GeoLocationToken>
          <itv:Token/>
        </itv:GeoLocationToken>
        <itv:RevenueScienceValue>scc=true; svisit=1; sc4=Other</itv:RevenueScienceValue>
      </tem:userInfo>
      <tem:siteInfo>
        <itv:AdvertisingRestriction>None</itv:AdvertisingRestriction>
        <itv:AdvertisingSite>ITV</itv:AdvertisingSite>
        <itv:Area>ITVPLAYER.VIDEO</itv:Area>
        <itv:Platform>DotCom</itv:Platform>
        <itv:Site>ItvCom</itv:Site>
      </tem:siteInfo>
    </tem:GetPlaylist>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOF

  debug $browser->content;
  die "Unable to find <Video> in XML" unless $browser->content =~ m{<Video timecode[^>]+>(.*?)</Video>}s;
  my $video = $1;


  my %formats;

  while ($video =~ m/(mp4:[^\]]+_[A-Z]+([0-9]{3,4})_(16|4)[-x](9|3)[^\]]*.mp4)/gi)
  {
    $formats{$2} = { video => $video, playpath => $1, ratio => "$3x$4" };
  }

  while ($video =~ m/(mp4:[^\]]+-([0-9]{3,4})kbps.mp4)/gi)
  {
    $formats{$2} = { video => $video, playpath => $1, ratio => "16x9" };
  }
  while ($video =~ m/(mp4:[^\]]+-([0-9]{3,4})kbps.\d+.mp4)/gi)
  {
    $formats{$2} = { video => $video, playpath => $1, ratio => "16x9" };
  }

  my @rates = sort { $a <=> $b } keys(%formats);
  my $cnt = $#rates;

  die "Unable to find video in XML" unless $cnt >= 0;

  my $q = $prefs->{quality};
  if ( $q =~ /^\s*\d+\s*$/) {
     my $rate = $rates[0];
     foreach (@rates) {
        if ( $q >= $_ )
        { $rate = $_;}
     }
     $q = $rate;
  }
  else {
    my $num = {high =>int($cnt), medium => int(($cnt+1)/2), low => 0}->{$q};
    if (! defined $num ) { 
      $num = int($cnt);
    }
    $q = $rates[$num];
  }
  
  my $format = $formats{$q};
  if ( ! defined($format)) {
    $format = $formats{$rates[int($cnt)]};
  }

  $video = $format->{"video"};
  my $rtmp = decode_entities($video =~ /base="(rtmp[^"]+)/);
  my($playpath) = $format->{"playpath"};
  my($flv) = $playpath =~ m{/([^/]+)$};

  return {
    rtmp => $rtmp,
    playpath => $playpath,
    flv => $flv,
    swfhash($browser, "http://www.itv.com/mercury/Mercury_VideoPlayer.swf")
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Itv.pm
BEGIN { $INC{'FlashVideo/Site/Joemonster.pm'}++; }
# Author: paczesiowa@gmail.com
#################################################
#
# 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 plugin works for videos from www.joemonster.org using 'Monster Player'
#
# Most (~70%) of them are single embedded youtube videos:
# http://www.joemonster.org/filmy/28773/Sposob_na_Euro_2012
# This plugin doesn't directly support them,
# so get_flash_videos fallbacks to youtube method, which works just fine.
# Pages with multiple youtube videos are also supported by youtube method,
# but only the first embedded video is downloaded:
# http://www.joemonster.org/filmy/4551/Terapia_masazem
#
# This plugin claims to support a page when it contains at least one video
# embedded with Monster Player.
# Pages with mixed providers, like this (Monster Player+youtube):
# http://www.joemonster.org/filmy/5496/Kolo_Smierci
# only downloads Monster Player movies, the rest is discarded,
# because I don't know how to provide links AND fallback to a different method.
#
# There are two versions of Monster Player:
# * old/fat
# http://www.joemonster.org/filmy/28784/Genialny_wystep_mlodego_iluzjonisty_w_Mam_talent (single video)
# http://www.joemonster.org/filmy/28693/Dave_Chappelle_w_San_Francisco_ (multi videos)
#
# * new/slim
# http://www.joemonster.org/filmy/28372/Wszyscy_kochamy_Polske_czesc_ (single video)
#
# Currently multiple videos are unsupported, only the first one is downloaded,
# I have no idea how to return multiple links
#
# About 5% of videos are embedded from external providers (different than youtube),
# they should work if get_flash_videos has appropriate method.

##{ blib/lib/FlashVideo/Site/Joemonster.pm
{
package FlashVideo::Site::Joemonster;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;
use URI::QueryParam;


my $new_monster_player_regex = "<\\s*embed\\s*src\\s*=\\s*\"\\s*(http:\\/\\/www\\.joemonster\\.org\\/flvplayer\\.swf\\?file=.*?)\\s*\"";

sub is_new_monster_player {
    my($self, $browser) = @_;
    return $browser->content =~ m/$new_monster_player_regex/;
}

sub get_new_monster_player_url {
    my($self, $browser) = @_;
    $browser->content =~ m/$new_monster_player_regex/;
    return URI->new($1)->query_param('file') or die "no file key in player link";
}

my $old_monster_player_regex = "<\\s*embed\\s*src\\s*=\\s*\"\\s*(http:\\/\\/www\\.joemonster\\.org\\/emb\\/.*?)\\s*\"";

sub is_old_monster_player {
    my($self, $browser) = @_;
    return $browser->content =~ m/$old_monster_player_regex/;
}


sub get_old_monster_player_url {
    my($self, $browser) = @_;
    $browser->content =~ m/$old_monster_player_regex/;
    my $embedded_url = $1;
    $browser->get($embedded_url);
    my $url = $browser->uri;
    return URI->new($url)->query_param('file') or die "no file key in player link";
}

sub can_handle {
    my($self, $browser, $url) = @_;
    return $self->is_new_monster_player($browser) || $self->is_old_monster_player($browser);
}

sub find_video {
    my($self, $browser, $url) = @_;
    my $real_url;

    if ($self->is_new_monster_player($browser)) {
	$real_url = $self->get_new_monster_player_url($browser);
    }
    else {
	$real_url = $self->get_old_monster_player_url($browser);
    }

    my $title;
    if ($browser->title =~ m/(.*) - Joe Monster/ ) {
	$title = $1;
    } else {
	$title = $browser->title;
    }

    return $real_url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Joemonster.pm
BEGIN { $INC{'FlashVideo/Site/Kanal5play.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Kanal5play.pm
{
package FlashVideo::Site::Kanal5play;

use strict;
use warnings;
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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }


my $bitrates = {
     "low" => 250000,
     "medium" => 450000, 
     "high" => 900000 };

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  if(!($browser->uri->as_string =~ m/video\/([0-9]*)/)){
      die "No video id found in url";
  }
  my ($video_id) = $1;
  my $info_url = "http://www.kanal5play.se/api/getVideo?format=FLASH&videoId=$video_id";
  $browser->get($info_url);
  
  if (!$browser->success){
      die "Couldn't download $info_url: " . $browser->response->status_line;
  }

  my $jsonstr = $browser->content;
  my $json = from_json($jsonstr);

  my $name = $json->{program}->{name};
  my $episode = $json->{episodeNumber};
  my $season = $json->{seasonNumber};
  my $filename = sprintf "%s - S%02dE%02d", $name, $season, $episode;
  my ($rtmp) = "rtmp://fl1.c00608.cdn.qbrick.com:1935/00608";
  my ($playpath) = $json->{streams}[0]->{source};

  my  $i;
  foreach $i (keys $json->{streams}) {
      my ($rate) = int($json->{streams}[$i]->{bitrate});
      if($bitrates->{$prefs->{quality}} == $rate){
	  $playpath = $json->{streams}[$i]->{source};
      }
  }
  return {
      flv => title_to_filename($filename, "flv"),
      rtmp => $rtmp,
      playpath => $playpath,
      swfVfy => "http://www.kanal5play.se/flash/StandardPlayer.swf"
  };

}
1;
}
##} blib/lib/FlashVideo/Site/Kanal5play.pm
BEGIN { $INC{'FlashVideo/Site/Kidswb.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Kidswb.pm
{
package FlashVideo::Site::Kidswb;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  my $config_url = "http://staticswf.kidswb.com/franchise/digitalsmiths/wbkidsvideoplayer.xml";
  my $mediaKey;
  if ($browser->uri->as_string =~ /\/video#.*\/([^\/]*)$/) {
    $mediaKey = $1;
  } else {
    die "Couldn't find flashvars param in " . $browser->uri->as_string;
  }

  $browser->allow_redirects;
  $browser->get($config_url);
  if (!$browser->success) {
    die "Couldn't download config.xml $config_url: " . $browser->response->status_line;
  }

  my $xml = from_xml($browser);
  my $domain = $xml->{mfs}->{url};
  my $version = "v2";
  my $account = $xml->{mfs}->{account};
  my $partner = $xml->{mfs}->{partnerid};

  my $asset_url = "$domain/$version/$account/assets/$mediaKey/partner/$partner?format=json";
  $browser->get($asset_url);
  if (!$browser->success) {
    die "Couldn't download asset file $asset_url: " . $browser->response->status_line;
  }

  my $asset_data = from_json($browser->content);
  my $videos = $asset_data->{videos};

  my $title = title_to_filename($asset_data->{assetFields}->{seriesName} . " - " . $asset_data->{assetFields}->{title});

  my $video = $videos->{limelight700};

  my $rtmp = $video->{uri};

  return {
    flv => $title,
    rtmp => $rtmp,
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Kidswb.pm
BEGIN { $INC{'FlashVideo/Site/Last.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Last.pm
{
package FlashVideo::Site::Last;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my($artist, $id) = $embed_url =~ m{/([^/]+)/\+videos/(\d+)};
  my($title) = $browser->content =~ /<h1>([^<]+)/;

  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 =~ /<location>([^<]+)/, title_to_filename($title);
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return $url =~ /last\.fm/ && $url =~ m{\+video/\d{2,}};
}

1;
}
##} blib/lib/FlashVideo/Site/Last.pm
BEGIN { $INC{'FlashVideo/Site/Liveleak.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Liveleak.pm
{
package FlashVideo::Site::Liveleak;

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, $embed_url) = @_;

  my $file_embed_tag;
  if ($browser->content =~ /file_embed_tag(?:%3D|=)(\w+)\W/) {
    $file_embed_tag = $1; 
  }
  else {
    die "Unable to get file_embed_tag";
  }

  $browser->get("http://www.liveleak.com/playlist_new.php?file_embed_tag=$file_embed_tag");

  if (!$browser->success) {
    die "Couldn't download LiveLeak playlist: " . $browser->response->status_line();
  }

  my $video_url;
  if ($browser->content =~ m'<location>(http://.*?)</location>') {
    $video_url = $1;
  }
  else {
    die "Unable to extract LiveLeak video URL";
  }

  if (my $redirected_url = $browser->head($video_url)->header('Location')) {
    $video_url = $redirected_url;
  }

  $browser->back();

  my $title;
  if ($browser->content =~ m'<h4 id="s_hd">(.*?)</h4>') {
    $title = $1;
  }
  else {
    $title = extract_title($browser);
  }

  return $video_url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Liveleak.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.
##{ blib/lib/FlashVideo/Site/Megavideo.pm
{
package FlashVideo::Site::Megavideo;

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; }
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;
}
##} blib/lib/FlashVideo/Site/Megavideo.pm
##{ blib/lib/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;
}
##} blib/lib/FlashVideo/Site/Megaporn.pm
BEGIN { $INC{'FlashVideo/Site/Metacafe.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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; *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->response->header("Location") =~ /Openx/) {
    my $filter = "http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user&filters=0&prevURL=" . $browser->uri->path;
    debug "Disabling family filter by getting $filter";

    $browser->allow_redirects;
    $browser->get($filter);
  }

  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;
}
##} blib/lib/FlashVideo/Site/Metacafe.pm
BEGIN { $INC{'FlashVideo/Site/Mitworld.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Mitworld.pm
{
package FlashVideo::Site::Mitworld;

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) = $browser->content =~ m{id="video-meta">\s*<h2>(.*?)</h2>}s;
  if(!$title) {
    $title = extract_title($browser);
    $title =~ s/\|.*//;
  }

  my($host) = $browser->content =~ m{host:\s*"(.*?)"};
  my($flv) = $browser->content =~ m{flv:\s*"(.*?)"};

  return {
    rtmp => "rtmp://$host/ondemand/ampsflash/$flv?_fcs_vhost=$host",
    flv  => title_to_filename($title)
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Mitworld.pm
BEGIN { $INC{'FlashVideo/Site/Mofosex.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Mofosex.pm
{
package FlashVideo::Site::Mofosex;

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 $filename = title_to_filename($browser->content =~ /<title>(.*?)<\//);
  
  $browser->allow_redirects;

  my $playlist = ($browser->content =~ /videoPath=(.+?)%26page/)[0];
  $browser->get($playlist);
   
  my $url = ($browser->content =~ /<url>(.+?)<\/url>/)[0];
    
  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Mofosex.pm
BEGIN { $INC{'FlashVideo/Site/Msn.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Msn.pm
{
package FlashVideo::Site::Msn;

use strict;
BEGIN { FlashVideo::Site::Bing->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Bing';

1;
}
##} blib/lib/FlashVideo/Site/Msn.pm
BEGIN { $INC{'FlashVideo/Site/Msnbc.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Msnbc.pm
{
package FlashVideo::Site::Msnbc;

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) = @_;

  $browser->allow_redirects;

  my $id;
  my $location;
  if ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/.+#([0-9]+)/) {
    $location = $1;
    $id = $3;
  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/vp\/([0-9]+)/) {
    $location = $1;
    $id = $3;
  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/.+#([0-9]+)/) {
    $location = $1;
    $id = $3;
  } elsif ($embed_url =~ /(.+\/id\/)([0-9]+)\/#([0-9]+)/) {
    $location = $1;
    $id = $3;
  }
  die "Unable to find location and videoid" unless $location and $id;

  $browser->get($location . $id . '/displaymode/1219/'); # http://today.msnbc.msn.com/id/$id/displaymode/1219/

  my $xml = from_xml($browser->content);

  my $title;
  my $url;
  if ($xml->{video}->{docid} eq $id) {
    $title = $xml->{video}->{title};
    foreach my $media (@{$xml->{video}->{media}}) {
      if ($media->{type} =~ /flashVideo$/i) {
        $url = $media->{content};
        last; #prefer http get over rtmp
      } elsif ($media->{type} =~ /flashVideoStream$/i) {
        $browser->get($media->{content});
        if ($browser->content =~ /<FlashLink>(.+)<\/FlashLink>/i) {
          $url = $1; #rtmp
        }
      }
    }
  }
  die "Unable to extract video url" unless $url;

  if ($url =~ /^rtmp/i) {
    return {
      rtmp => $url,
      flv => title_to_filename($title)
    };
  }

  return $url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Msnbc.pm
BEGIN { $INC{'FlashVideo/Site/Mtvnservices.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; *from_xml = \&FlashVideo::Utils::from_xml; }
use URI::Escape;

my $MTVN_URL = qr{http://\w+.mtvnservices.com/(?:\w+/)?mgid:[a-z0-9:.\-_]+};
my $MTVN_ALT_URL = qr{mgid:[a-z0-9:.\-_]+};

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $page_url = $browser->uri->as_string;

  if($embed_url !~ $MTVN_URL) {
    if($browser->content =~ m!($MTVN_URL)!) {
      $embed_url = $1;
    } elsif($browser->content =~ m!($MTVN_ALT_URL)!) {
      $embed_url = "http://media.mtvnservices.com/$1";
    } else {
      die "Unable to find embedding URL";
    }
  }

  $browser->get($embed_url);
  die "Unable to get embed URL" unless $browser->response->code =~ /^30\d$/;

  my %param;
  my $location = $browser->response->header("Location");
  for(split /&/, (split /\?/, $location)[-1]) {
    my($n, $v) = split /=/;
    $param{$n} = uri_unescape($v);
  }

  die "No config_url/id found\n" unless $param{CONFIG_URL};

  $browser->get($param{CONFIG_URL});
  my $xml = from_xml_urlfix($browser);

  if($xml->{player}->{feed} && !ref $xml->{player}->{feed}) {
    my $feed = uri_unescape($xml->{player}->{feed});
    $feed =~ s/\{([^}]+)\}/$param{$1}/g;

    $browser->get($feed);

    return $self->handle_feed($browser->content, $browser, $page_url, $param{uri});
  } elsif(ref $xml->{player}->{feed}->{rss}) {
    return $self->handle_feed($xml->{player}->{feed}->{rss}, $browser, $page_url, $param{uri});
  } else {
    die "Unable to find feed\n";
  }
}

sub handle_full_episode {
  my($self, $items, $filename, $browser, $page_url, $uri) = @_;

  my @rtmpdump_commands;

  debug "Handling full episode";

  foreach (@$items) {
    my $item = $_;

    my $affect_counters = (grep { $_->{scheme} eq "urn:mtvn:affect_counters" } @{$item->{"media:group"}->{"media:category"}})[0];
    my $iscommercial = 0;
    if (defined $affect_counters && $affect_counters->{content} eq 'false') {
      $iscommercial = 1;
    }

    if (!$iscommercial) {
      my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url};
      die "Unable to find mediagen URL\n" unless $mediagen_url;

      $browser->get($mediagen_url);
      my $xml = from_xml_urlfix($browser);

      my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY'
        ?  @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition};
      $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY';

      my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src};

      my $mediagen_id;
      if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){
        $mediagen_id = $1;
      } else {
        $mediagen_id = $mediagen_url;
      }

      $browser->allow_redirects;

      push @rtmpdump_commands, {
        flv => title_to_filename($item->{"media:group"}->{"media:title"}),
        rtmp => $url,
        pageUrl => $item->{"link"},
        swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id)
      };
    }
  }

  return \@rtmpdump_commands;
}

sub handle_clip {
  my($self, $items, $filename, $browser, $page_url, $uri) = @_;

  debug "Handling clip";

  my $item = ref $items eq 'ARRAY' ?
    (grep { $_->{guid}->{content} eq $uri } @$items)[0] :
    $items;

  my $mediagen_url = $item->{"media:group"}->{"media:content"}->{url};
  die "Unable to find mediagen URL\n" unless $mediagen_url;

  $browser->get($mediagen_url);
  my $xml = from_xml_urlfix($browser);

  my $rendition = (grep { $_->{rendition} } ref $xml->{video}->{item} eq 'ARRAY'
    ?  @{$xml->{video}->{item}} : $xml->{video}->{item})[0]->{rendition};
  $rendition = [ $rendition ] unless ref $rendition eq 'ARRAY';

  my $url = (sort { $b->{bitrate} <=> $a->{bitrate} } @$rendition)[0]->{src};

  my $mediagen_id;
  if($mediagen_url =~ /mediaGenEntertainment\.jhtml\?uri=([^&]+).*$/){
    $mediagen_id = $1;
  } else {
    $mediagen_id = $mediagen_url;
  }

  $browser->allow_redirects;

  if($url =~ /^rtmpe?:/) {
    return {
      flv => $filename,
      rtmp => $url,
      pageUrl => $page_url,
      swfhash($browser, "http://media.mtvnservices.com/" . $mediagen_id)
    };
  } else {
    return $url, $filename;
  }
}

sub handle_feed {
  my($self, $feed, $browser, $page_url, $uri) = @_;

  my $xml = ref $feed ? $feed : from_xml_urlfix($feed);

  my $filename = title_to_filename($xml->{channel}->{title});

  my $items = $xml->{channel}->{item};
  my $categories = ref $items eq 'ARRAY' ? @$items[0]->{"media:group"}->{"media:category"} : $items->{"media:group"}->{"media:category"};

  if (ref $categories eq 'ARRAY' && (
      (grep { $_->{scheme} eq "urn:mtvn:display:seo" } @$categories)[0]->{content} eq "" ||
      (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "Full Episode" ||
      (grep { $_->{scheme} eq "urn:mtvn:content_type" } @$categories)[0]->{content} eq "full_episode_segment")) {
    return $self->handle_full_episode($items, $filename, $browser, $page_url, $uri);
  } else {
    return $self->handle_clip($items, $filename, $browser, $page_url, $uri);
  }
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return $browser->content =~ /mtvnservices\.com/i;
}


sub from_xml_urlfix {
  my($xmltext) = @_;
  $xmltext =~ s/&(?!amp;)/&amp;/g;  # too lax?
  return from_xml($xmltext);
}

1;
}
##} blib/lib/FlashVideo/Site/Mtvnservices.pm
BEGIN { $INC{'FlashVideo/Site/Muzu.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Muzu.pm
{
package FlashVideo::Site::Muzu;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use HTML::Entities;

sub find_video {
  my ($self, $browser) = @_;

  if ($browser->response->code == 302) {
    $browser->allow_redirects;
    $browser->get($browser->response->header('Location'))
  }

  $browser->content =~ /id="trackHeading">(.*?)</;
  my $title = $1;

  if (!$title) {
    $browser->content =~ /id="videosPageMainTitleH1">(.*?)</s;
    $title = $1;
  }
  
  my $filename = title_to_filename(decode_entities($title));

  my $flashvars = ($browser->content =~ m'flashvars:(?:\s+getPlayerData\(\)\s+\+\s+)?"([^"]+)')[0];
  die "Unable to extract flashvars" unless $flashvars;

  my %map = (
    networkId    => "id",
    assetId      => "assetId",
    vidId        => "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;

  if($url =~ /^rtmp:/) {
    my($playpath) = $url =~ m{/([^/]+)$};

    return {
      flv => $filename,
      rtmp => $url,
      playpath => $playpath,
      $url =~ /live/ ? (live => 1) : ()
    };

  } else {
    return $url, $filename;
  }
}

1;
}
##} blib/lib/FlashVideo/Site/Muzu.pm
BEGIN { $INC{'FlashVideo/Site/Mylifetime.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Mylifetime.pm
{
package FlashVideo::Site::Mylifetime;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
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;
}
##} blib/lib/FlashVideo/Site/Mylifetime.pm
BEGIN { $INC{'FlashVideo/Site/Myvideo.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Myvideo.pm
{
package FlashVideo::Site::Myvideo;

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 $video_url;

  if ($browser->content =~ m{<link rel='image_src' href='(http://[^'"]+)'}) {
    $video_url = $1;
  }

  $video_url =~ s|thumbs/||;
  $video_url =~ s|_\d\.jpg$|.flv|;

  my $title = (split /\//, $browser->uri->as_string)[-1];

  return $video_url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Myvideo.pm
BEGIN { $INC{'FlashVideo/Site/Nasa.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Nasa.pm
{
package FlashVideo::Site::Nasa;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my ($self, $browser, $embed_url) = @_;
  
  my $uri = $browser->uri();
  my $path = $uri->path();
  $path =~ s/index\.html//;               # strip the index.htm at the end of the path.
  $path = $path . "vmixVideoLanding2.js"; # specify the javascript src
  
  debug "Nasa videogallery query is " . $uri->query();
  my ($media_id) = $uri->query() =~ m/media_id=(\d+)/;
  
  die "Nasa support requires 'media_id=nnnnnnnn' in the query" unless $media_id;
  
  $uri->path($path);                      # Change path to javascript src
  $uri->query(undef());                   # Remove the query

  info "Downloading video source instructions at " . $uri;
  $browser->get($uri);
  
  die "Could not locate video source" unless $browser->success();
  
  my $videojs = $browser->content();      # content is javascript
  
  my ($api_url_host) = $browser->content() =~ m{var +api_url *= *'([^']*)' *;};
  die "Could not extract video server" unless $api_url_host;
  
  my ($atoken) = $browser->content() =~ m{var +atoken *= *'([^']*)' *;};

  my $query = 'http://' . $api_url_host . '/apis/media.php?action=getMedia&export=JSONP&media_id=' . $media_id . '&atoken=' . $atoken . '&callback=loadCurrentVideo1';
  
  info "Downloading video details from http://" . $api_url_host;
  $browser->get($query);
  die "Could not get video details" unless $browser->success();
  
  my $result = from_json($browser->content());
  
  my $url = $result->{url};
  die "Could not extract video url" unless $url;
  $url =~ s/\/core\//\/core-dl\//;
  
  my $filename = $result->{title};
  $filename = title_to_filename($filename, "mp4");

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Nasa.pm
BEGIN { $INC{'FlashVideo/Site/Nbc.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Nbc.pm
{
package FlashVideo::Site::Nbc;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
use MIME::Base64;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $has_amf_packet = eval { require Data::AMF::Packet };
  if (!$has_amf_packet) {
    die "Must have Data::AMF::Packet installed to download Nbc videos";
  }


  my $video_id;
  if ($browser->uri->as_string =~ /\/([0-9]+)\//) {
    $video_id = $1;
  }

  my $packet = Data::AMF::Packet->deserialize(decode_base64("AAAAAAABABZnZXRDbGlwSW5mby5nZXRDbGlwQWxsAAIvMQAAAB8KAAAABAIABzEyMjc2MTECAAJVUwIAAzYzMgIAAi0xCg=="));

  $packet->messages->[0]->{value}->[0] = $video_id;

  if($self->debug) {
    require Data::Dumper;
    debug Data::Dumper::Dumper($packet);
  }

  my $data = $packet->serialize;

  $browser->post(
    "http://video.nbcuni.com/amfphp/gateway.php",
    Content_Type => "application/x-amf",
    Content => $data
  );

  die "Failed to post to Nbc AMF gateway"
    unless $browser->response->is_success;

  debug $browser->content;


  my($clipurl) = $browser->content =~ /clipurl.{0,5}(nbc[^\0]+)/;

  my($title) = $browser->content =~ /headline.{1,3}([^\0]+)/;

  debug $clipurl;
  debug $title;

  $browser->get("http://video.nbcuni.com/$clipurl");
  my $xml = from_xml($browser);
  my $video_path = $xml->{body}->{switch}->{ref}->{src};

  $browser->get("http://videoservices.nbcuni.com/player/config?configId=17010&clear=true"); # I don't know what configId means but it seems to be generic
  my $xml = from_xml($browser);
  my $app = $xml->{akamaiAppName};
  my $host = $xml->{akamaiHostName};

  $browser->get("http://$host/fcs/ident");
  my $xml = from_xml($browser);
  my $ip = $xml->{ip};
  my $port = "1935";

  my $rtmpurl = "rtmp://$ip:$port/$app/$video_path";

  return {
    rtmp => $rtmpurl,
    swfUrl => "http://www.nbc.com/[[IMPORT]]/video.nbcuni.com/outlet/extensions/inext_video_player/video_player_extension.swf?4.5.3",
    tcUrl => "rtmp://$ip:$port/$app?_fcs_vhost=$host", 
    flv => title_to_filename($title)
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Nbc.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://github.com/monsieurvideo/get-flash-videos
#
#################################################
# Except the CCR bits, thanks to Fogerty for those.
##{ blib/lib/FlashVideo/Site/Nfb.pm
{
package FlashVideo::Site::Nfb;

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, $prefs) = @_;

  my($refer, $cURL) = $browser->content =~ /<link rel="video_src" href="([^?]+)\?configURL=([^&]+)&/;

  $browser->post(
    $cURL,
    "X-NFB-Referer" => $refer,
    Content_Type => "application/x-www-form-urlencoded",
    Content => "getConfig=true",
  );

  if (!$browser->success) {
    die "Getting config info failed: " . $browser->response->status_line();
  }

  my $xml = from_xml($browser->content);

  my $media;
  foreach (@{$xml->{player}->{stream}->{media}}) {
    if ($_->{"type"} eq "video") {
      $media = $_;
      last;
    }
  }

  my $title = $media->{title};


  my @assets = sort { _get_quality_from_url($b->{default}->{url}) <=> _get_quality_from_url($a->{default}->{url}) }
                    (@{$media->{assets}->{asset}});

  if (!@assets) {
    die "Couldn't find any streams in the config file";
  }

  my $quality = $prefs->{quality};
  my $asset;
  if ($quality eq "high") {
    $asset = $assets[0];
  } elsif ($quality eq "low") {
    $asset = $assets[-1];
  } elsif ($quality eq "medium") {
    if (scalar(@assets) > 1) {
      $asset = $assets[1];
    } else {
      $asset = $assets[0];
    }
  } else {
    die "Unknown quality setting";
  }

  my $rtmp_url = $asset->{default}->{streamerURI};
  my($host, $app) = $rtmp_url =~ m'rtmp://([^/]+)/(\w+)';
  my $playpath = $asset->{default}->{url};

  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;
}
##} blib/lib/FlashVideo/Site/Nfb.pm
BEGIN { $INC{'FlashVideo/Site/Nick.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Nick.pm
{
package FlashVideo::Site::Nick;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; *from_xml = \&FlashVideo::Utils::from_xml; }
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url) = @_;


  my $page_url = $browser->uri->as_string;

  my $title;
  if($browser->content =~ /<span content=["']([\w \.:]+)["'] property=["']media:title["']\/>/) {
    $title = $1;
  } else {
    $title = "nothing";
  }

  my $cmsId;
  if($browser->content =~ /KIDS\.add\("cmsId", "(\d+)"\);/) {
    $cmsId = $1;
  } else {
    die "Couldn't get the cmsId.";
  }

  my $site;
  if($browser->content =~ /KIDS\.add\(["']site["'], ["']([\w\.]+)["']\);/) {
    $site = lc($1);
  } else {
    die "Couldn't get the site.";
  }

  my $type;
  if($browser->content =~ /KIDS\.add\(["']type["'], ["']([a-z]+)["']\);/) {
    $type = $1;
  } else {
    $type = "video";
  }

  my $uri = "mgid:cms:$type:$site:$cmsId";

  $browser->get("http://www.nick.com/dynamo/video/data/mediaGen.jhtml?mgid=$uri");
  my $xml = from_xml($browser->content);
  my $rtmp_url = $xml->{video}->{item}[0]->{rendition}[0]->{src};

  return {
    rtmp => $rtmp_url,
    flv => title_to_filename($title),
    pageUrl => $page_url,
    swfhash($browser, "http://media.nick.com/" . $uri)
  };
}

sub can_handle {
  my($self, $browser) = @_;
  return $browser->content =~ /<script src=["']http:\/\/media.nick.com\/player\/scripts\/mtvn_player_control\.1\.0\.1\.js["']/;
}

1;
}
##} blib/lib/FlashVideo/Site/Nick.pm
BEGIN { $INC{'FlashVideo/Site/Nicovideo.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Nicovideo.pm
{
package FlashVideo::Site::Nicovideo;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
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;
}
##} blib/lib/FlashVideo/Site/Nicovideo.pm
BEGIN { $INC{'FlashVideo/Site/Ooyala.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Ooyala.pm
{
package FlashVideo::Site::Ooyala;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
use File::Basename;
use HTML::Entities;
use URI::Escape;
use Data::Dumper;

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  debug $embed_url;

  my ($player_js) = uri_unescape(
    decode_entities(
      $browser->content =~ m{<script src=["'](http://player\.ooyala\.com/player\.js[^'"]*)['"]>}
    )
  );

  die 'Could not find player.js URL' unless $player_js;

  $browser->get($player_js);

  my ($mobile_player_js) =
    $browser->content =~ m{mobile_player_url *= *['"]([^'"]*)["']};
  $mobile_player_js .= 'unknown&domain=unknown';

  die 'Could not find mobile_player.js URL' unless $mobile_player_js;

  $browser->get($mobile_player_js);

  my ($streams) = $browser->content =~ m{streams *= *[^;]*eval\("(.*?)"\);};

  die 'Could not find streams in mobile_player.js' unless $streams;

  my $data = from_json(json_unescape($streams));

  my $title = $data->[0]{title};
  my $url;
  if ($prefs->{quality} =~ /high|ipad/) {
    $url = $data->[0]{ipad_url};
  } else {
     $url =$data->[0]{url};
  }

  $browser->allow_redirects;

  return $url, title_to_filename($title, 'mp4');
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return 1 if $url && URI->new($url)->host =~ /\.ooyala\.com$/;

  return $browser->content =~ m{<script src=["']http://player\.ooyala\.com/player\.js[^'"]*['"]>};
}

1;
}
##} blib/lib/FlashVideo/Site/Ooyala.pm
BEGIN { $INC{'FlashVideo/Site/Pbs.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Pbs.pm
{
package FlashVideo::Site::Pbs;

use strict;
use warnings;

BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
use MIME::Base64 qw(decode_base64);


sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  die "Must have Crypt::Rijndael installed to download from PBS"
    unless eval { require Crypt::Rijndael };

  my ($media_id) = $browser->uri->as_string =~ m[
    ^http://video\.pbs\.org/video/(\d+)
  ]x;
  unless (defined $media_id) {
    ($media_id) = $browser->content =~ m[
      http://video\.pbs\.org/widget/partnerplayer/(\d+)
    ]x;
  }
  unless (defined $media_id) {
    ($media_id) = $browser->content =~ m[
      /embed-player[^"]+\bepisodemediaid=(\d+)
    ]x;
  }
  unless (defined $media_id) {
    ($media_id) = $browser->content =~ m[var videoUrl = "([^"]+)"];
  }
  unless (defined $media_id) {
    my ($pap_id, $youtube_id) = $browser->content =~ m[
      \bDetectFlashDecision\ \('([^']+)',\ '([^']+)'\);
    ]x;
    if ($youtube_id) {
      debug "Youtube ID found, delegating to Youtube plugin\n";
      my $url = "http://www.youtube.com/v/$youtube_id";
      require FlashVideo::Site::Youtube;
      return FlashVideo::Site::Youtube->find_video($browser, $url, $prefs);
    }
  }
  die "Couldn't find media_id\n" unless defined $media_id;
  debug "media_id: $media_id\n";

  $browser->get("http://video.pbs.org/videoPlayerInfo/$media_id");

  my $xml = $browser->content;
  $xml =~ s/&/&amp;/g;
  my $href = from_xml($xml);
  my $file = $href->{videoInfo}->{title};
  my $release_url = $href->{releaseURL};

  unless ($release_url =~ m[^https?://]) {
    debug "encrypted release url: $release_url\n";
    my ($type, $iv, $ciphertext) = split '\$', $release_url, 3;
    $release_url = undef;

    my $key = 'RPz~i4p*FQmx>t76';

    my $cipher = Crypt::Rijndael->new($key, Crypt::Rijndael->MODE_CBC);
    $iv = pack 'H*', $iv if 32 == length $iv;
    $cipher->set_iv($iv);

    $release_url = $cipher->decrypt(decode_base64($ciphertext));
    $release_url =~ s/\s+$//;
  }
  debug "unencrypted release url: $release_url\n";

  $browser->get($release_url);

  my $rtmp_url = $browser->res->header('location')
    || from_xml($browser->content)->{choice}{url}
    || die "Couldn't find stream url\n";
  $rtmp_url =~ s/<break>//;

  if(!$file) {
    ($file) = $rtmp_url =~ m{([^/\?]+)$};
  }

  return {
    rtmp    => $rtmp_url,
    pageUrl => $embed_url,
    swfUrl  => 'http://www-tc.pbs.org/video/media/swf/PBSPlayer.swf?18809',
    flv     => title_to_filename($file),
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Pbs.pm
BEGIN { $INC{'FlashVideo/Site/Pennyarcade.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Pennyarcade.pm
{
package FlashVideo::Site::Pennyarcade;

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;
	my $title;
	if ($browser->content =~/<h2>(.*?)<\/h2>/) {
		$title = $1;
		$title =~ s/<[^>]*>//g;
	}
	if ($browser->content =~/http:\/\/blip.tv\/play\/(.*).html/) {
		$id = $1;
	} else {
		die "No ID found\n";
	}

	$browser->add_header("User-Agent" => "Android");
	$browser->allow_redirects;
	return "http://blip.tv/play/$id.mp4", title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Pennyarcade.pm
BEGIN { $INC{'FlashVideo/Site/Putlocker.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Putlocker.pm
{
package FlashVideo::Site::Putlocker;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use HTML::Tree;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my ($filename) = title_to_filename(extract_title($browser));
  $filename =~ s/[\s\|_]*PutLocker[\s_]*//;
  
  my $tree = HTML::Tree->new();
  $tree->parse($browser->content);
  my $hash = $tree->look_down( 'name' , 'hash' )->attr('value');
  info 'Found hash: ' . $hash;
  
  info "Confirming request to PutLocker.";
  
  $browser->add_header( 'Content-Type' => 'application/x-www-form-urlencoded' );
  $browser->add_header( 'Accept-Encoding' => 'text/html' );
  $browser->add_header( Referer => $embed_url );
  
  my $response = $browser->post($embed_url,
    [ 'confirm'=>"Continue as Free User",
      'hash'=>$hash
      ]);

  die 'Response code was ' . $response->code . '. Should be 302.' unless ($response->code == '302');
  
  info "Re-fetching page, which will now have the video embedded.";
  $browser->delete_header( 'Content-Type');
  my $page_html = $browser->get($embed_url)->content;
  
  my ($streamID) = ($page_html =~ /get_file\.php\?stream=([A-Za-z0-9]+)/);
  info "Found the stream ID: " . $streamID;
  
  my $uri = URI->new( "http://www.putlocker.com/get_file.php" );
  $uri->query_form((stream=>$streamID));

  my $contents = $browser->get($uri)->content;
  my ($url) = ($contents =~ /url="(.*?)"/);

  info "Got the video URL: " . $url;

  return $url, $filename;
}

1;

}
##} blib/lib/FlashVideo/Site/Putlocker.pm
BEGIN { $INC{'FlashVideo/Site/Redbull.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Redbull.pm
{
package FlashVideo::Site::Redbull;

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; }
use URI;
use HTML::Entities;

sub find_video {
  my ($self, $browser, $page_url) = @_;

  my $video_info_url;
  my $host = $browser->uri->host; 

  if ( ($browser->content =~ /data_url:\s+'([^']+)'/) or
       ($browser->content =~ m{displayVideoPlayer\('([^']+)'\)})) {
    $video_info_url = $1;

    $video_info_url = "http://$host$video_info_url";
  }

  if (!$video_info_url) {
    die "Couldn't find video info URL";
  }

  $browser->get($video_info_url);

  if ($browser->response->is_redirect) {
    $browser->get($browser->response->header('Location'));
  }

  if (!$browser->success) {
    die "Couldn't download Red Bull video info XML: " .
      $browser->response->status_line;
  }
  
  my $xml = $browser->content;
  $xml =~ s/&amp;//g;
  $xml = decode_entities($xml);

  my $video_info = from_xml($xml);

  my $file_type = "flv";
  
  if ($video_info->{high_video_url} =~ /\.mp4$/) {
    $file_type = "mp4";
  }

  return {
    flv  => title_to_filename($video_info->{title}, $file_type),
    rtmp => $video_info->{high_video_url}, 
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Redbull.pm
BEGIN { $INC{'FlashVideo/Site/Redtube.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Redtube.pm
{
package FlashVideo::Site::Redtube;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;

sub find_video {
  my($self, $browser, $embed_url) = @_;

  my($title) = $browser->content =~ /<h1 class="videoTitle">([^<]+)</;

  my($url) = $browser->content =~ /hashlink=([^&"]+)/;
  $url = uri_unescape($url);

  $browser->allow_redirects;
  return $url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Redtube.pm
BEGIN { $INC{'FlashVideo/Site/Ringtv.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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;
}
##} blib/lib/FlashVideo/Site/Ringtv.pm
BEGIN { $INC{'FlashVideo/Site/Sapo.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Sapo.pm
{
package FlashVideo::Site::Sapo;

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 ($video_url, $type);
  
  if ($browser->content =~ m{flvplayer-sapo\.swf\?file=(http://[^&"]+)}) {
    $video_url = $1;

    if ($video_url =~ m{/mov}) {
      $type = "mp4";
    }
  }
  else {
    die "Couldn't extract Sapo video URL";
  }

  (my $title = extract_title($browser)) =~ s/ - SAPO V\x{ed}deos//;

  my $filename = title_to_filename($title, $type);

  $browser->allow_redirects(1);

  return $video_url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Sapo.pm
BEGIN { $INC{'FlashVideo/Site/Sbs.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Sbs.pm
{
package FlashVideo::Site::Sbs;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
use File::Basename;
use HTML::Entities;
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  my $smil;
  my $baseurl;

  my($id) = $browser->content =~ /firstVidId = '([^']*)';/;
  ($smil) = decode_entities($browser->content =~ /player\.releaseUrl = "([^"]*)";/);

  if( $id ){

    ($baseurl) = $browser->content =~ m{so\.addVariable\("nielsenLaunchURL", *"([^"]*)"\);}s ;
    my($menu) = $browser->content =~ m{loadVideo\('([^']*)', '', [^\)]\);}s ;
    if( !$menu ){ $menu = $baseurl . '/video/menu/inline/id/' . $id; }
    else { $menu = 'http://www.sbs.com.au' . $menu; }
    $menu =~ s/' *\+ *firstVidId *\+ *'/$id/g;

    die "No menu URL found" unless $menu;

    $browser->get($menu);

    ($smil) = $browser->content =~ m{<video *name="[^"]*" *id="[^"]*" *src="([^"]*)">}s ;
  }

  die "no smil" unless $smil;

  $browser->get($smil);

  ($baseurl) = decode_entities($browser->content =~ m'<meta base="([^"]*)"/>'s);

  my @tmp = $browser->content =~ m'<video src="([^"]*)" system-bitrate="([^"]*)"/>'gs;
  my %tmp = reverse @tmp;
  my $filename;
  my $q = $prefs->{quality};
  if( grep {$_ eq $q || $_ == $q || $_ == ($q * 100000)} keys(%tmp) ){
    $filename = decode_entities($tmp{$q});
    if(!$filename){
      my @bitrates = grep {$_ == $q || $_ == ($q * 100000)} keys(%tmp);
      $filename = decode_entities($tmp{$bitrates[0]});
    }
  } else {
    my @filenames = ();
    foreach (sort { $a <=> $b } keys(%tmp) )
      { push @filenames, $tmp{$_}; }
    my $cnt = @filenames;
    my $num = {high => int($cnt/3)*2, medium => int($cnt/3)*1, low => int($cnt/3)*0}->{$q};
    $filename = decode_entities($filenames[$num]);
  }

  die "no filenames" unless $filename;

  if( $baseurl =~ /^rtmp:/ ){
    my($flvname) = $filename =~ m'[^/]*/(.*)'s;
    return {
      rtmp => $baseurl,
      playpath => $filename,
      flv => $flvname,
      swfUrl => 'http://www.sbs.com.au/vod/theplatform/core/4_4_3/swf/flvPlayer.swf',
    };
  } elsif ($baseurl) {
    my $url = $baseurl . $filename;
    return $url, $filename;
  } else {
    return $filename, File::Basename::basename($filename);
  }
}

1;
}
##} blib/lib/FlashVideo/Site/Sbs.pm
BEGIN { $INC{'FlashVideo/Site/Scivee.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Scivee.pm
{
package FlashVideo::Site::Scivee; # horrible casing :(


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; }
use HTML::Entities;
sub find_video {

  my ($self, $browser) = @_;
  
  my $title;
  if ($browser->content =~ /title\>([^\|]+)/) {
    $title = $1;
  }
  else {
    $title = extract_info($browser)->{title};
  }
  my $filename = title_to_filename($title);
  my $vid;
  if ($browser->content =~ /\/ratings\/(\d+)/) {
    $vid = $1;
  }
  elsif ($browser->content =~ /flashvars="id=(\d+)/) {
    $vid = $1;
  }
  else {
    die "Could not find video!";
  }
  my $url = "http://www.scivee.tv/asset/video/$vid";

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Scivee.pm
BEGIN { $INC{'FlashVideo/Site/Seesaw.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Seesaw.pm
{
package FlashVideo::Site::Seesaw;

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; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; }
use HTML::Entities qw(decode_entities);
use URI::Escape qw(uri_escape);

my @res = (
  { name => "lowResUrl",  resolution => [ 512, 288 ] },
  { name => "stdResUrl",  resolution => [ 672, 378 ] },
  { name => "highResUrl", resolution => [ 1024, 576 ] }
);

sub find_video {
  my ($self, $browser, $page_url, $prefs) = @_;

  my $player_info = ($browser->content =~ m{(/videoplayerinfo/\d+[^"]+)"})[0];

  (my $content = $browser->content) =~ s{\\/}{/}g;

  my %seen; # avoid duplication in filenames
  
  my %metadata = map { $_ => '' } qw(brandTitle seriesTitle programmeTitle);
 
  my ($series, $episode);

  ($series, $episode) = ($browser->content =~ /Series (\d+) - Ep(?:isode)?\.? (\d+)/);

  if (!$series and !$episode) {
    ($series, $episode) = ($browser->content =~ /series_number: ["']?(\d+)["']?,\s+ep_number: ['"]?(\d+)['"]/);
  }

  if ($series and $episode) {
    $metadata{series_and_episode} = sprintf "S%02dE%02d", $series, $episode;
  }

  foreach my $metadata_item (keys %metadata) {
    if (my $value = ($content =~ m{<$metadata_item>(.*?)</$metadata_item>}isg)[0]) {
      $value = decode_entities($value);

      next if $seen{$value};

      $seen{$value}++;

      $metadata{$metadata_item} = $value;
    }
  }

  my @metadata_items;

  if ( (grep length, values %metadata) == 2 and
       $metadata{series_and_episode}) {
    @metadata_items = ((grep { $_ ne 'series_and_episode' } keys %metadata), 'series_and_episode');
  }
  elsif (!$metadata{brandTitle}) {
    @metadata_items = qw(seriesTitle series_and_episode programmeTitle);
  }
  else {
    @metadata_items = qw(brandTitle series_and_episode seriesTitle programmeTitle);
  }

  my $title = join "-", map { trim($_) }
                        grep length,
                        @metadata{@metadata_items};

  $browser->get($player_info);

  debug "Got player info URL $player_info";

  if (!$browser->success) {
    die "Couldn't get player info: " . $browser->response->status_line;
  }

  my @urls;
  for my $res(@res) {
    if($browser->content =~ /$res->{name}":\["([^"]+)/) {
      push @urls, { %$res, url => $1 };
    }
  }

  die "No video URLs found" unless @urls;

  my $rtmp = $prefs->quality->choose(@urls);

  my($app, $playpath, $query) = $rtmp->{url} =~ m{^\w+://[^/]+/(\w+/\w+)(/[^?]+)(\?.*)};
  my $prefix = "mp4";
  $prefix = "flv" if $playpath =~ /\.flv$/;

  if ($prefs->subtitles) {
    if ($browser->content =~ m{"subtitleLocation":\["([^"]+)"\]}) {
      my $subtitles_url = $1;
      
      if ($subtitles_url =~ m{^/}) {
        $subtitles_url = "http://www.seesaw.com$subtitles_url";
      }

      debug "Got Seesaw subtitles URL: $subtitles_url";

      $browser->get($subtitles_url);

      if ($browser->success) {
        my $srt_filename = title_to_filename($title, "srt"); 

        convert_sami_subtitles_to_srt($browser->content, $srt_filename);

        info "Wrote subtitles to $srt_filename";
      }
      else {
        info "Couldn't download subtitles: " . $browser->response->status_line;
      }
    }
    else {
      debug "No Seesaw subtitles available (or couldn't extract URL)";
    }
  }

  return {
    flv      => title_to_filename($title, $prefix),
    rtmp     => $rtmp->{url},
    app      => $app,
    playpath => "$prefix:$playpath$query"
  }
}

sub search {
  my($self, $search, $type) = @_;

  my $series  = $search =~ s/(?:series |\bs)(\d+)//i ? int $1 : "";
  my $episode = $search =~ s/(?:episode |\be)(\d+)//i ? int $1 : "";

  my $browser = FlashVideo::Mechanize->new;

  _update_with_content($browser,
    "http://www.seesaw.com/start.layout.searchsuggest:inputtextevent?search="
    . uri_escape($search));

  my @urls = map  {
    chomp(my $name = $_->text);
    { name => $name, url => $_->url_abs->as_string }
  } $browser->find_all_links(text_regex => qr/.+/);

  my @words = split " ", $search;
  @urls = grep { my $a = $_; @words == grep { $a->{name} =~ /\Q$_\E/i } @words } @urls;

  if(@urls == 1) {
    $browser->get($urls[0]->{url});
    my $main_title = ($browser->content =~ m{<h1>(.*?)</h1>}s)[0];
    $main_title =~ s/<[^>]+>//g;
    $main_title =~ s/\s+/ /g;

    my $cur_series = ($browser->content =~ /<li class="current">.*?>\w+ (\d+)/i)[0];
    if($main_title =~ s/\s*series (\d+)\s*//i && !$cur_series) {
      $cur_series = $1;
    }

    my %series = reverse(
      ($browser->content =~ m{<ul class="seriesList">(.*?)</ul>}i)[0]
      =~ /<li.*?href="\?([^"]+)".*?>\s*(?:series\s*)?([^<]+)/gi);

    my $episode_list;
    if($series && $cur_series ne $series) {
      if(!$series{$series}) {
        error "No such series number ($series).";
        return;
      }
      _update_with_content($browser, $series{$series});
      $episode_list = $browser->content;
      $cur_series = $series;

    } elsif(!$series && keys %series > 1) {
      my @series = sort { $a <=> $b } map { s/series\s+//i; $_ } keys %series;
      info "Viewing series $cur_series; series " . join(", ", @series) . " also available.";
      info "Search for 'seesaw $main_title series $series[0]' to view a specific series.";
    }

    if(!$episode_list) {
      $episode_list = ($browser->content
        =~ m{<table id="episodeListTble">(.*?)</table>}is)[0];
    }

    @urls = ();
    for my $episode_html($episode_list =~ m{<tr.*?</tr>}gis) {
      my %info;
      for(qw(number date title action)) {
        my $class = "episode" . ucfirst;
        $episode_html =~ m{<td class=['"]$class['"]>(.*?)</td>}gis
          && ($info{$_} = $1);
      }

      $info{number}   = ($info{number} =~ /ep\.?\w*\s*(\d+)/i)[0];
      $info{date}     = ($info{date}   =~ />(\w+[^<]+)/)[0];
      $info{number} ||= ($info{title}  =~ /ep\.?\w*\s*(\d+)/i)[0];
      $info{title}    = ($info{title}  =~ />\s*([^<].*?)\s*</s)[0];
      $info{url}      = ($info{action} =~ /href=['"]([^'"]+)/)[0];

      my $title = join " - ", $main_title,
        ($cur_series
          ? sprintf("S%02dE%02d", $cur_series, $info{number})
          : $info{number} ? sprintf("E%02d", $info{number})
        : ()), $info{title};

      my $result = {
        name => $title,
        url  => URI->new_abs($info{url}, $browser->uri)
      };

      if($episode && $info{number} == $episode) {
        return $result;
      }

      push @urls, $result;
    }
  } else {
    info "Please specify a more specific title to download a particular programme." if @urls > 1;
  }

  return @urls;
}

sub _update_with_content {
  my($browser, $url) = @_;

  $browser->get($url,
    X_Requested_With => 'XMLHttpRequest',
    X_Prototype_Version => '1.6.0.3');

  my($content) = $browser->content =~ /content":\s*"(.*?)"\s*}/;
  $content = json_unescape($content);
  debug "Content is '$content'";
  $browser->update_html($content);
}

sub trim {
  local $_ = shift;

  s/^\s+|\s+$//g;

  return $_;
}

1;
}
##} blib/lib/FlashVideo/Site/Seesaw.pm
BEGIN { $INC{'FlashVideo/Site/Sevenload.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Sevenload.pm
{
package FlashVideo::Site::Sevenload;

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 HTML::Entities;
use URI::Escape;

sub find_video {
  my ($self, $browser) = @_;

  die "Could not find configPath" unless $browser->content =~ /configPath=([^"']+)/;
  my $configpath = uri_unescape(decode_entities($1));
  $browser->get($configpath);

  my $config = from_xml($browser);
  
  my($title, $location);

  eval {
    my $item = $config->{playlists}->{playlist}->{items}->{item};
    $title = title_to_filename($item->{title});

    my $streams = $item->{videos}->{video}->{streams}->{stream};
    $streams = [ $streams ] unless ref $streams eq 'ARRAY';

    $location = (sort { $b->{width} <=> $a->{width} } @$streams)[0]
      ->{locations}->{location}->{content};
  };

  return $location, $title if $location;

  die "Unable to get stream location" . ($@ ? ": $@" : "");
}

1;
}
##} blib/lib/FlashVideo/Site/Sevenload.pm
BEGIN { $INC{'FlashVideo/Site/Slashcontrol.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Slashcontrol.pm
{
package FlashVideo::Site::Slashcontrol;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  my $config;
  my $mediaKey;
  if ($browser->content =~ /<param name="flashvars" value="config=([^&]*)&mediaKey=([^"]*)"\/>/) {
    $config = $1;
    $mediaKey = $2;
  } else {
    die "Couldn't find flashvars param in " . $browser->uri->as_string;
  }
  my $root;
  if ($browser->content =~ /<embed src="(.*)\/[^\/]*\.swf"/) {
    $root = $1;
  } else {
    die "Couldn't find embeded swf " . $browser->uri->as_string;
  }
  my $config_url;
  $config_url = $1 . "/" . $config;

  $browser->allow_redirects;
  $browser->get($config_url);
  if (!$browser->success) {
    die "Couldn't download config.xml $config_url: " . $browser->response->status_line;
  }

  my $xml = from_xml($browser);
  my $domain = $xml->{mfs}->{mfsUrl};
  my $version = $xml->{mfs}->{mfsVersion};
  my $account = $xml->{mfs}->{mfsAccount};
  my $partner = $xml->{mfs}->{mfsPartnerId};

  my $asset_url = "$domain/$version/$account/assets/$mediaKey/partner/$partner?format=json";
  $browser->get($asset_url);
  if (!$browser->success) {
    die "Couldn't download asset file $asset_url: " . $browser->response->status_line;
  }

  my $asset_data = from_json($browser->content);
  my $videos = $asset_data->{videos};

  my $title = title_to_filename($asset_data->{assetFields}->{seriesName} . " - " . $asset_data->{assetFields}->{title});

  my $video = $videos->{limelight700};

  my $rtmp = $video->{uri};

  return {
    flv => $title,
    rtmp => $rtmp,
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Slashcontrol.pm
BEGIN { $INC{'FlashVideo/Site/Spiegel.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Spiegel.pm
{
package FlashVideo::Site::Spiegel;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my ($video_id, $xmlurl, $filename, $videourl, $quality);

  debug "Spiegel::find_video called, embed_url = \"$embed_url\"\n";
  
  $quality = {
      high => '.mp4',
      medium => 'VP6_928.flv',
      low => 'VP6_576.flv'}->{$prefs->{quality}};

  if($embed_url =~ /.*?www.spiegel.de\/video\/video-(\d*).html/) {
    $video_id = $1;
    $xmlurl = "http://video.spiegel.de/flash/$video_id.xml";
  } else {
    die "Only works for http://www.spiegel/de/video/video... urls\n";
  }

  if($browser->content =~ /<title>(.*?) -Video/) {
    $filename = "Spiegel_$1_${video_id}_$quality";
    $filename = title_to_filename($filename, $quality);
    $filename =~ s/__/_/g;
  } else {
    die "Unable to find <title> on page $embed_url\n";
  }

  $browser->get($xmlurl);

  if($browser->content =~ /<filename>(.*?$quality)<\/filename>/) {
    $videourl = "http://video.spiegel.de/flash/$1";
  } else {
    die "could not find video url\n";
  }

  return $videourl, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Spiegel.pm
BEGIN { $INC{'FlashVideo/Site/Spike.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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'; *from_xml = \&FlashVideo::Utils::from_xml; }
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  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 = from_xml($browser);

  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;
}
##} blib/lib/FlashVideo/Site/Spike.pm
BEGIN { $INC{'FlashVideo/Site/Stagevu.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Stagevu.pm
{
package FlashVideo::Site::Stagevu;

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($title) = $browser->content =~ /<title>(.*?)<\/title>/;
  $title =~ s/\s*-\s*Stagevu.*?$//;

  my($url) = FlashVideo::Generic->find_video($browser);

  return $url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Stagevu.pm
BEGIN { $INC{'FlashVideo/Site/Starwars.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Starwars.pm
{
package FlashVideo::Site::Starwars;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id;
  if ($browser->uri->as_string =~ /view\/([0-9]+)\.html$/) {
    $video_id = $1;
  }

  my $page_url = $browser->uri->as_string;

  $browser->get("http://starwars.com/webapps/video/item/$video_id");
  my $xml = from_xml($browser);

  my $items = $xml->{channel}->{item};
  my $item = ref $items eq 'ARRAY' ?
    (grep { $_->{link}->{content} eq "/video/view/" . $video_id . ".html" } @$items)[0] :
    $items;

  debug $item->{enclosure}->{url};

  my $rtmpurl = $item->{enclosure}->{url};
  $rtmpurl =~ s/^rtmp:/rtmpe:/; # for some reason it only works with rtmpe

  my $title = $item->{title}; # is there a way to unencrypt <CDATA> tags? or does the xml handler do this for us?

  return {
    flv => $title,
    rtmp => title_to_filename($rtmpurl),
    playpath => $item->{content}->{url}
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Starwars.pm
BEGIN { $INC{'FlashVideo/Site/Stickam.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Stickam.pm
{
package FlashVideo::Site::Stickam;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *swfhash = \&FlashVideo::Utils::swfhash; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  my $perfomer_id;

  if ($browser->content =~ /profileUserId=(\d+)/) {
    $perfomer_id = $1;  
  }
  else {
    die "Can't get performer ID";
  }

  my $filename;
  if ($browser->content =~ /userName=([^&]+)/) {
    $filename = $1;
  }
  else {
    $filename = $perfomer_id;
  }

  my $stream_info_url = sprintf
    "http://player.stickam.com/servlet/flash/getChannel?" .
    "type=join&performerID=%d", $perfomer_id;

  $browser->get($stream_info_url);

  if (!$browser->success) {
    die "Couldn't get stream info: " . $browser->response->status_line;
  }

  my %stream_info;

  foreach my $pair (split /&/, $browser->content) {
    my ($name, $value) = split /=/, $pair;

    if ($name eq 'freeServerIP') {
      $value = (split /,/, $value)[0];
    }
    
    $stream_info{$name} = $value;
  }

  if ($stream_info{errorCode}) {
    die "Stickam returned error $stream_info{errorCode}: $stream_info{errorMessage}";
  }

  my $rtmp_stream_url = sprintf
    "rtmp://%s/video_chat2_stickam_peep/%d/public/mainHostFeed",
    $stream_info{freeServerIP},
    $stream_info{channelID};

  return {
    rtmp => $rtmp_stream_url,
    flv => title_to_filename($filename),
    live => '',
    conn => [
      'O:1',
      "NS:channel:$perfomer_id",
      'O:1',
    ],
    swfhash($browser,
      "http://player.stickam.com/flash/stickam/stickam_simple_video_player.swf")
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Stickam.pm
BEGIN { $INC{'FlashVideo/Site/Stupidvideos.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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;
}
##} blib/lib/FlashVideo/Site/Stupidvideos.pm
BEGIN { $INC{'FlashVideo/Site/Svtplay.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Svtplay.pm
{
package FlashVideo::Site::Svtplay;

use strict;
use warnings;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my @rtmpdump_commands;
    
  if ($browser->uri->as_string !~ m/video\/([0-9]*)/) {
    die "No video id found in url";
  }

  my $video_id = $1;
  my $info_url = "http://www.svtplay.se/video/$video_id?output=json";

  $browser->get($info_url);
    
  if (!$browser->success) {
    die "Couldn't download $info_url: " . $browser->response->status_line;
  }

  my $video_data = from_json($browser->content);
  my $name = $video_data->{context}->{title};
  my $bitrate = 0;
  my $rtmp_url;

  foreach my $video (@{ $video_data->{video}->{videoReferences} }) {
    my $rate = int $video->{bitrate};

    if ($bitrate < $rate && $video->{playerType} eq "flash") {
      $rtmp_url = $video->{url};
      $bitrate = $rate;
    }
  }

  if ($prefs->{subtitles}) {
    if (my $subtitles_url = $video_data->{video}->{subtitleReferences}[0]->{url}) {
      info "Found subtitles URL: $subtitles_url";

      $browser->get($subtitles_url);

      if (!$browser->success) {
        info "Couldn't download subtitles: " . $browser->status_line;
      }

      my $srt_filename = title_to_filename($name, "srt"); 

      open my $srt_fh, '>', $srt_filename
        or die "Can't open subtitles file $srt_filename: $!";
      binmode $srt_fh, ':utf8';
      print $srt_fh $browser->content;
      close $srt_fh;
    }
    else {
      info "No subtitles found!";
    }
  }

  return {
	  flv    => title_to_filename($name, "flv"),
	  rtmp   => $rtmp_url,
	  swfVfy => "http://www.svtplay.se/public/swf/video/svtplayer-2012.15.swf",
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Svtplay.pm
BEGIN { $INC{'FlashVideo/Site/Tbs.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tbs.pm
{
package FlashVideo::Site::Tbs;

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 $oid;
  if ($browser->uri->as_string =~ /oid=([0-9]*)/) {
    $oid = $1;
  }

  $browser->get("http://www.tbs.com/video/cvp/videoData.jsp?oid=$oid");

  my $xml = from_xml($browser);

  my $headline = $xml->{headline};

  my $akamai;
  if ($xml->{akamai}->{src} =~ /[^,]*,([^,]*)/){
    $akamai = $1;
  }

  my $files = $xml->{files}->{file};
  my $file = ref $files eq 'ARRAY' ?
    (grep { $_->{type} eq "standard" } @$files)[0] :
    $files;

  if($akamai) {
    my $rtmpurl = $akamai . $file->{content};
    die "Unable to find RTMP URL\n" unless $rtmpurl;

    return {
      flv => title_to_filename($headline),
      rtmp => $rtmpurl
    };
  } else {
    return $file->{content}, title_to_filename($headline);
  }
}

1;
}
##} blib/lib/FlashVideo/Site/Tbs.pm
BEGIN { $INC{'FlashVideo/Site/Techcast.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Techcast.pm
{
package FlashVideo::Site::Techcast;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use HTML::Entities;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my($clip_url) = $browser->content =~ /clip:\s*{\s*url:\s*['"]([^"']+)/;
  die "Unable to extract clip URL" unless $clip_url;
  $clip_url = URI->new_abs($clip_url, $browser->uri);

  my($talk) = $browser->content =~ /class="lecture_archive"[^>]+>([^<]+)/i;
  $talk = decode_entities($talk);

  my($author) = $browser->content =~ /class="speaker_archive"[^>]+>([^<]+)/i;
  $author = decode_entities($author);

  return $clip_url, title_to_filename($talk ? "$author - $talk" : $clip_url);
}

1;
}
##} blib/lib/FlashVideo/Site/Techcast.pm
BEGIN { $INC{'FlashVideo/Site/Ted.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Ted.pm
{
package FlashVideo::Site::Ted;
use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; *error = \&FlashVideo::Utils::error; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  my $basefilename;
  if ($browser->content =~ m{<noscript.*download.ted.com/talks/([^.]+)\.mp4.*noscript>}s) {
    $basefilename = $1;
  } else {
    die "Unable to find download link";
  }

  if ($prefs->subtitles) {
    my $lang = "";
    if ($browser->content =~ m{talkID = (\d+);}s) {
      my $talkID = $1;
      my $intro_time = 15000;
      if ($browser->content =~ m{introDuration:(\d+)}s) {
        $intro_time = int($1);
      } else {
        error "Can't find the intro duration, so guessing at 15 seconds.";
      }
      $ENV{LANG} =~ /^([^_]*)/;
      $lang = $1;
      if (!$lang) {
        info "Unable to determine your language, using English";
        $lang = "en";
      }
      info "Downloading subtitles";
      get_subtitles($browser, $basefilename . ".srt", $intro_time,
                    "http://www.ted.com/talks/subtitles/id/$talkID/lang/$lang/format/json");
    } else {
      error "Unable to determine the talk ID, so can't get the subtitles";
    }
  }

  my $quality = $prefs->{quality};
  if ($quality eq "low") {
    $quality = "-light";
  } elsif ($quality eq "medium") {
    $quality = "";
  } elsif ($quality eq "high") {
    $quality = "-480p";
  } else {
    die "Unknown quality setting";
  }

  my $url = "http://download.ted.com/talks/" . $basefilename . $quality . ".mp4";

  $browser->allow_redirects;
  return $url, $basefilename . ".mp4";
}

sub get_subtitles {
  my ($browser, $filename, $intro_time, $url) = @_;
  $browser->get($url);
  if (!$browser->success) {
    error "Couldn't download subtitles: " . $browser->response->status_line;
    return;
  }
  json_to_srt($browser->content, $filename, $intro_time);
}


sub json_to_srt {
  my ($subdata, $filename, $intro_time) = @_;
  open (SRT, '>', $filename) or die "Can't open subtitles file $filename: $!";

  my $subtitle_count = 0;
  my $subdata = from_json($subdata);

  foreach my $subtitle (@{ $subdata->{captions} }) {
    $subtitle_count++; # SubRip starts at 1

    my ($srt_start, $srt_end) = convert_to_srt_time(
      $subtitle->{startTime} + $intro_time,
      $subtitle->{duration},
    );

    print SRT "$subtitle_count\n" .
          "$srt_start --> $srt_end\n" .
          "$subtitle->{content}\n\n";
  }

  close SRT;
}

sub convert_to_srt_time {
  my ($start, $duration) = @_;

  return format_srt_time($start),
         format_srt_time($start + $duration);
}

sub format_srt_time {
  my $time = shift;

  my $seconds = int($time / 1000);
  my $milliseconds = $time - ($seconds * 1_000);

  return sprintf "%02d:%02d:%02d,%03d", (gmtime $seconds)[2, 1, 0],
                                        $milliseconds;
}

1;
}
##} blib/lib/FlashVideo/Site/Ted.pm
BEGIN { $INC{'FlashVideo/Site/Theonion.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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'; *info = \&FlashVideo::Utils::info; *extract_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }

sub find_video {
  my ($self, $browser) = @_;

  if ($browser->response->is_redirect) {
    $browser->get( $browser->response->header('Location') );

    if (!$browser->success) {
      die "Couldn't follow Onion redirect: " .
        $browser->response->status_line;
    }
  }

  my $title;
  if ($browser->content =~ /var video_title = "([^"]+)"/) {
    $title = $1;
  }
  else {
    $title = extract_info($browser)->{meta_title};
  }

  my $filename = title_to_filename($title);

  my $url = (FlashVideo::Generic->find_video($browser, $browser->uri))[0];

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Theonion.pm
BEGIN { $INC{'FlashVideo/Site/Thirteen.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Thirteen.pm
{
package FlashVideo::Site::Thirteen;
use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  my $iframe;
  if ($browser->content =~ /<iframe src="([^"]*)" /) {
    $iframe = $1;
  } else {
    die "Couln't find iframe in " . $browser->uri->as_string;
  }

  my $url = 'http://www.thirteen.org' . $iframe;
  $browser->get($url);
  if (!$browser->success) {
    die "Couldn't download iframe $url: " . $browser->response->status_line;
  }



  my $pid;
  if ($browser->content =~ /var pid = "([^"]*)";/) {
    $pid = $1;
  } elsif ($browser->uri->as_string =~ /&pid=([^&]*)&/) {
    $pid = $1;
  } else {
    die "Could not find pid for $url";
  }

  my $release_url;
  if ($browser->content =~ /so.addVariable\("releaseURL", "([^"]*)"+pid+"([^"]*)"\);/) {
    $release_url = $1 . $pid . $2;
  } else {
    $release_url = "http://release.theplatform.com/content.select?pid=" . $pid . "&amp;format=SMIL&amp;Tracking=true";
  }

  $browser->get($release_url);
  my $rtmp_url;
  if ($browser->response->is_redirect) {
    $rtmp_url = $browser->response->header("Location");
  } else {
    die "No redirect found for $release_url";
  }

  $rtmp_url =~ s/<break>//;

  my $filename;
  if ($rtmp_url =~ /mp4:(.*)\.mp4$/) {
    $filename = title_to_filename($1);
  } else {
    $filename = title_to_filename("");
  }


  return {
    rtmp => $rtmp_url,
    flv => $filename,
  };
}

1;
}
##} blib/lib/FlashVideo/Site/Thirteen.pm
BEGIN { $INC{'FlashVideo/Site/Todaysbigthing.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Todaysbigthing.pm
{
package FlashVideo::Site::Todaysbigthing;

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; *from_xml = \&FlashVideo::Utils::from_xml; }

my $base = "http://www.todaysbigthing.com/betamax";

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $id;
  if($browser->content =~ /item_id=(\d+)/) {
    $id = $1;
  } elsif($embed_url =~ m![/:](\d+)!) {
    $id = $1;
  }
  die "No ID found\n" unless $id;

  $browser->get("$base:$id");

  my $xml = from_xml($browser);

  my $title = $xml->{title};
  $title = extract_title($browser) if ref $title;
  my $filename = title_to_filename($title);

  my $url = $xml->{flv};
  die "No FLV location" unless $url;

  return $url, $filename;
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return $browser->content =~ $base;
}

1;
}
##} blib/lib/FlashVideo/Site/Todaysbigthing.pm
BEGIN { $INC{'FlashVideo/Site/Tou.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
#
#################################################
# tou.tv
#
#	Reverse-engineering details at http://store-it.appspot.com/tou/tou.html
#	by Sylvain Fourmanoit
#
#	un grand merci a Sylvain qui a tout debrousaille!
#
#	Stavr0
#
##{ blib/lib/FlashVideo/Site/Tou.pm
{
package FlashVideo::Site::Tou;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
use URI::Escape;

sub find_video {
  my ($self, $browser) = @_;

  my $video_id;
  if ($browser->content =~ /,"pid":"(\w+)"/i) {
    $video_id = $1;
  }
  debug "Video ID = " . $video_id;

  die "Couldn't find TOU.TV video ID" unless $video_id;

  my $filename;
  if ($browser->content =~ /,"titleId":"([^"]+)"/i) {
    $filename =  $1 ;
  }
  debug "Filename = " . $filename;

  $browser->get("http://release.theplatform.com/content.select?pid=$video_id");

  die "Couldn't download TOU.TV XML: " . $browser->response->status_line
    if !$browser->success;

  my $url;
  if ($browser->content =~ /(rtmp:[^\<]+)/i) {
    $url = uri_unescape($1);
  }
  debug "URL = " . $url;

  my $auth;
  if ($url =~ /auth=([^&]+)/i) {
    $auth = uri_unescape($1);
  }
  debug "AUTH = " . $auth;

  my $app;
  if ($url =~ /(ondemand\/.+)/i) {
    $app = uri_unescape($1);
  }
  debug "APP = " . $app;

  my $playpath;
  if ($url =~ /&lt;break&gt;(.+)/i) {
    $playpath = uri_unescape($1);
  }
  debug "PLAYPATH = " . $playpath;


  return {
      app => $app,
      pageUrl => $url,
      swfUrl => "http://static.tou.tv/lib/ThePlatform/4.1.2/swf/flvPlayer.swf",
      tcUrl => $url,
      auth => $auth,
      rtmp => $url,
      playpath => $playpath,
      flv => "$filename.flv",
  };
}

sub search {
  my($self, $search, $type) = @_;

  my $browser = FlashVideo::Mechanize->new;
  $browser->get("http://www.tou.tv/recherche?q=" . uri_escape($search));
  return unless $browser->success;

  my $results = $browser->content;

  my @emissions;
  my @links;

  while($results =~ /<a\s+href="([^"]+)"\s+id="[^"]+"\s+class="([^"]+)/g) {
    debug $1;
    if($2 eq "tousEpisodes") {
      push @emissions, $1;
    }
  }

  for my $emission (@emissions) {
    $browser->get($emission);
    my $liste = $browser->content;

    while($liste =~ /<a.+class="episode".+href="([^"]+)".+>(.+)<\/a>/g) {
      push @links, { name => $1, url => "http://www.tou.tv$1", description => $2 };
    }
  }

  return @links;
}

1;
}
##} blib/lib/FlashVideo/Site/Tou.pm
BEGIN { $INC{'FlashVideo/Site/Traileraddict.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Traileraddict.pm
{
package FlashVideo::Site::Traileraddict;

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; }
use URI::Escape;

sub find_video {
  my ($self, $browser) = @_;

  my $video_id;
  if ($browser->content =~ m'/em[db]/(\d+)') {
    $video_id = $1;
  }
  else {
    die "Unable to get Traileraddict video ID";
  }

  my $video_info_url = "http://www.traileraddict.com/fvar.php?tid=$video_id";

  $browser->get($video_info_url);

  if (!$browser->success) {
    die "Couldn't download Traileraddict video info URL: " .
        $browser->response->status_line;
  }

  my %info = parse_video_info($browser->content);

  die "Couldn't find Traileraddict video URL" unless $info{fileurl};

  $browser->head($info{fileurl});
  if ($browser->response->is_redirect()) {
    $info{fileurl} = $browser->response->header('Location');
  }

  my $type = $info{fileurl} =~ /\.mp4/i ? 'mp4' : 'flv';
  
  return $info{fileurl}, title_to_filename($info{title}, $type);
}

sub parse_video_info {
  my $raw_video_info = shift;

  my %info;

  foreach my $pair (split /&/, $raw_video_info) {
    $pair = uri_unescape($pair);

    my ($name, $value) = split /=/, $pair;

    $info{$name} = $value;
  }

  return %info;
}

1;
}
##} blib/lib/FlashVideo/Site/Traileraddict.pm
BEGIN { $INC{'FlashVideo/Site/Truveo.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Truveo.pm
{
package FlashVideo::Site::Truveo;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *url_exists = \&FlashVideo::Utils::url_exists; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  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, $prefs);
  } else {
    die "Redirect URL not found";
  }
}

1;
}
##} blib/lib/FlashVideo/Site/Truveo.pm
BEGIN { $INC{'FlashVideo/Site/Tudou.pm'}++; }
##{ blib/lib/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; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $check_response = sub {
    my ( $message ) = @_;
    return if $browser->success;
    die sprintf $message, $browser->response->code;
  };


  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`\.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 = from_xml($raw_xml, forcearray => [ 'f' ] );

  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{wwwFlv} ? 'wwwFlv'
      : exists $streams{f4v} ? 'f4v'
      : exists $streams{phoneMp4} ? 'phoneMp4'
      : '' );

  my $stream_formats = join ', ', ( keys %streams );
  die "Video is only available in unknown file formats ($stream_formats)",
    unless $stream;

  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;
}
##} blib/lib/FlashVideo/Site/Tudou.pm
BEGIN { $INC{'FlashVideo/Site/Tv.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tv.pm
{
package FlashVideo::Site::Tv;

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; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }

sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;


  my $pid;
  if ($browser->content =~ /so.addVariable\("pid", "([^"]*)"\);/) {
    $pid = $1;
  } else {
    die "Could not find PID for video! " . $browser->uri->as_string;
  }

  my $url = "http://release.theplatform.com/content.select?format=SMIL&Tracking=true&balance=true&pid=$pid";
  $browser->get($url);
  if (!$browser->success) {
    die "Couldn't download content.select $url: " . $browser->response->status_line;
  }

  my $xml = from_xml($browser);
  my $items = $xml->{body}->{ref};
  my $item = ref $items eq 'ARRAY' ?
    (grep { $_->{src} =~ /^rtmp:\/\// } @$items)[0] :
    $items;

  my $filename = title_to_filename($item->{title});

  my $playpath = "";
  my $rtmpurl = $item->{src};

  $rtmpurl =~ s/<break>.*//;

  return {
    flv => $filename,
    rtmp => $rtmpurl,
  };
}

sub can_handle {
  my($self, $browser, $url) = @_;
  return $browser->uri->host =~ /(^|\.)tv\.com$/;
}

1;
}
##} blib/lib/FlashVideo/Site/Tv.pm
BEGIN { $INC{'FlashVideo/Site/Tv3play.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tv3play.pm
{
package FlashVideo::Site::Tv3play;
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; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; }


sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  return $self->find_video_viasat($browser,$embed_url,$prefs);
}

sub find_video_viasat {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my $video_id = ($browser->content =~ /id:([0-9]*),/)[0];
  info "Got video_id: $video_id";
  my $info_url = "http://viastream.viasat.tv/PlayProduct/$video_id";
  $browser->get($info_url);
  my $variable = $browser->content;
  $variable =~ s/\n//g;
  my $title = ($variable =~ /<Title><!\[CDATA\[(.*?)\]\]><\/Title>/)[0];
  my $flv_filename = title_to_filename($title, "flv");



  my @urls;
  my $count = 0;
  my $base = ($variable =~ /<Videos>(.*)<\/Videos>/)[0];
  for ($count = 0; $count < 3; $count++){
    my $video = ($base =~ /<Video>(.+)<\/Video>/p)[0];
    if ($video eq ''){last;};
    $base = ${^POSTMATCH};    
    my $bitrate = ($video =~ /<BitRate>([0-9]*)<\/BitRate>/)[0];
    my $url = ($video =~ /<Url><!\[CDATA\[(.*)]]><\/Url>/)[0];
    if (not (($url =~ /http:\/\//)[0] eq '')){
      $browser->get($url);
      $variable = $browser->content;
      $variable =~ s/\n//g;
      $url = ($variable =~ /<Url>(.*)<\/Url>/)[0];
    }
    
    $urls[$count++] = { 'bitrate' => $bitrate,
		      'rtmp' => $url
		    };
  }
  my $bitrate = 0;
  my $rtmp;
  my $new_bitrate;

  foreach (@urls) {
    $new_bitrate = int($_->{bitrate});
    if($new_bitrate > $bitrate){
        $bitrate = int($_->{bitrate});
        $rtmp = $_->{rtmp};
    }
  };


  return{
      rtmp => $rtmp,
      swfVfy => "http://flvplayer-viastream-viasat-tv.origin.vss.viasat.tv/play/swf/player110420.swf",
      flv => $flv_filename
  };


}

1;
}
##} blib/lib/FlashVideo/Site/Tv3play.pm
BEGIN { $INC{'FlashVideo/Site/Tv4play.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tv4play.pm
{
package FlashVideo::Site::Tv4play;
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; *convert_sami_subtitles_to_srt = \&FlashVideo::Utils::convert_sami_subtitles_to_srt; *from_xml = \&FlashVideo::Utils::from_xml; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my $vid = ($embed_url =~ /videoid=([0-9]*)/)[0];
  my $smi_url = "http://premium.tv4play.se/api/web/asset/$vid/play";
 
  my $title = ($browser->content =~ /property="og:title" content="(.*?)"/)[0];
  my $flv_filename = title_to_filename($title, "flv");

  $browser->get($smi_url);
  my $content = from_xml($browser);
  my $i = 0;
  my @dump;
  my $subtitle_url;
  for ($i = 0; $i < 5; $i++){
    my $format = $content->{items}->{item}[$i]->{mediaFormat};
    my $bitrate = $content->{items}->{item}[$i]->{bitrate};
    my $rtmp = $content->{items}->{item}[$i]->{base};
    my $mp4 = $content->{items}->{item}[$i]->{url};
    @dump[$i] = { 'rtmp' => $rtmp,
		  'bitrate' => $bitrate,
		  'mp4' => $mp4,
		  'format' => $format
		};
  }  
  foreach (@dump) {
    if($_->{format} eq 'smi'){ $subtitle_url = $_->{mp4};}
  }
  debug "Subtitle_url: $subtitle_url";


  
  return {
      rtmp => $dump[0]->{rtmp},
      swfVfy => "http://www.tv4play.se/flash/tv4playflashlets.swf",
      playpath =>  $dump[0]->{mp4},
      flv => $flv_filename
  };
  
}

1;
}
##} blib/lib/FlashVideo/Site/Tv4play.pm
BEGIN { $INC{'FlashVideo/Site/Tv6play.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tv6play.pm
{
package FlashVideo::Site::Tv6play;
use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
BEGIN { FlashVideo::Site::Tv3play->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Tv3play';


sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  return $self->find_video_viasat($browser,$embed_url,$prefs);
}
1;
}
##} blib/lib/FlashVideo/Site/Tv6play.pm
BEGIN { $INC{'FlashVideo/Site/Tv8play.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tv8play.pm
{
package FlashVideo::Site::Tv8play;
use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }
BEGIN { FlashVideo::Site::Tv3play->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Tv3play';


sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  return $self->find_video_viasat($browser,$embed_url,$prefs);
}
1;
}
##} blib/lib/FlashVideo/Site/Tv8play.pm
BEGIN { $INC{'FlashVideo/Site/Tva.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Tva.pm
{
package FlashVideo::Site::Tva;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; }
BEGIN { FlashVideo::Site::Brightcove->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Brightcove';

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $video_id  = ($browser->content =~ /player.SetVideo.(\d+)/i)[0];
  my $player_id = ($browser->content =~ /player.SetPlayer.(\d+)/i)[0];

  debug "Extracted playerId: $player_id, videoId: $video_id"
    if $player_id or $video_id;

  if(!$video_id) {
    my $video_offset = ($browser->content =~ /player.SetVideo.\w+\[(\d+)/i)[0];
    $video_id = ($browser->content =~ /videos\[$video_offset\].+'(\d+)'\s*\]/)[0];
  }

  die "Unable to extract Brightcove IDs from page"
    unless $player_id and $video_id;

  return $self->amfgateway($browser, $player_id, { videoId => $video_id, } );
}

sub can_handle {
  my($self, $browser, $url) = @_;

  return $browser->content =~ /player = CanoeVideoStandalone\.create\(\);/i;
}

1;
}
##} blib/lib/FlashVideo/Site/Tva.pm
BEGIN { $INC{'FlashVideo/Site/Ustream.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Ustream.pm
{
package FlashVideo::Site::Ustream;

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; }
use MIME::Base64;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  unless(eval { require Data::AMF::Packet }) {
    die "Must have Data::AMF::Packet installed to download ustream videos";
  }

  my $packet = Data::AMF::Packet->deserialize(decode_base64(<<EOF));
AAAAAAABAA9WaWV3ZXIuZ2V0VmlkZW8AAi8xAAAAiAoAAAABAwAIYXV0b3BsYXkBAQAEcnBpbgIA
GHJwaW4uMC4xODM2MDk4NTkzMTY0Njg5OAAHdmlkZW9JZAIABzIzNTU3MzYAB3BhZ2VVcmwCACZo
dHRwOi8vd3d3LnVzdHJlYW0udHYvcmVjb3JkZWQvMjM1NTczNgAHYnJhbmRJZAIAATEAAAkK
EOF

  my $title = extract_info($browser)->{meta_title};

  my($video_id) = $browser->uri =~ m{recorded/(\d+)};
  $video_id ||= $browser->content =~ m{vid\s*=\s*["']?(\d+)};

  $packet->messages->[0]->{value}->[0]->{videoId} = $video_id;

  my $data = $packet->serialize;

  $browser->post(
    "http://rgw.ustream.tv/gateway.php",
    Content_Type => "application/x-amf",
    Content => $data
  );

  die "Failed to post to Ustream AMF gateway"
    unless $browser->response->is_success;

  my($flv_url) = $browser->content =~ /flv.{3,5}(http:[^\0]+)/;

  return $flv_url, title_to_filename($title);
}

1;
}
##} blib/lib/FlashVideo/Site/Ustream.pm
BEGIN { $INC{'FlashVideo/Site/Videobb.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Videobb.pm
{
package FlashVideo::Site::Videobb;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
use MIME::Base64;

sub find_video {
  my ($self, $browser) = @_;

  if($browser->status == 302) {
    $browser->allow_redirects;
    $browser->get;
  }
  my $flash_settings_b64 = ($browser->content =~ /<param value="setting=([^"]+)" name="FlashVars">/s)[0];
  my $flash_settings = decode_base64($flash_settings_b64);

  $browser->get($flash_settings);

  if (!$browser->success) {
    die "Couldn't download video settings: " . $browser->response->status_line;
  }

  my $settings_data = from_json($browser->content);

  my $url = decode_base64($settings_data->{settings}{res}->[-1]->{u});
  
  my $title  = $settings_data->{settings}{video_details}{video}{title};
  my $filename = title_to_filename($title);

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Videobb.pm
BEGIN { $INC{'FlashVideo/Site/Videojug.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Videojug.pm
{
package FlashVideo::Site::Videojug;

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; }

my $playlist_url = "http://www.videojug.com/views/film/playlist.aspx?items=&userName=&ar=16_9&id=";

sub find_video {
  my ($self, $browser) = @_;

  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 =~
    /<meta name=["']video-id["'] content="([A-F0-9a-f\-]+)"/) {
    $video_id = $1;
  } else {
    die "Couldn't find video ID in Videojug page";
  }

  $browser->get($playlist_url . $video_id);


  my($video_url, $filename);
  eval {
    my $xml = from_xml($browser);

    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;
}
##} blib/lib/FlashVideo/Site/Videojug.pm
BEGIN { $INC{'FlashVideo/Site/Videolectures.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Videolectures.pm
{
package FlashVideo::Site::Videolectures;

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 $author = ($browser->content =~ /author:\s*<\/span><a [^>]+>([^<]+)/s)[0];
  my $title  = ($browser->content =~ /<h2>([^<]+)/)[0];

  my $streamer = ($browser->content =~ /clip\.netConnectionUrl\s*=\s*["']([^"']+)/)[0];
  my $playpath = ($browser->content =~ /clip\.url\s*=\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;
}
##} blib/lib/FlashVideo/Site/Videolectures.pm
BEGIN { $INC{'FlashVideo/Site/Vimeo.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Vimeo.pm
{
package FlashVideo::Site::Vimeo;

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 $base = "http://vimeo.com/moogaloop";

  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&param_clip_id=$id&param_show_byline=0&param_server=vimeo.com&param_color=cc6600&param_show_portrait=0&param_show_title=1");

  my $xml = from_xml($browser);
  my $filename = title_to_filename($xml->{video}->{caption});
  my $request_signature = $xml->{request_signature};
  my $request_signature_expires = $xml->{request_signature_expires};
  my $isHD = $xml->{video}->{isHD};

  $browser->allow_redirects;
  
  my $url = "$base/play/clip:$id/$request_signature/$request_signature_expires/?q=hd&type=embed";
  if ($isHD == '1') { 
      return $url, $filename;
  };
  $url = "$base/play/clip:$id/$request_signature/$request_signature_expires/?q=sd&type=embed";
  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Vimeo.pm
BEGIN { $INC{'FlashVideo/Site/Vrak.pm'}++; }
##{ blib/lib/FlashVideo/Site/Vrak.pm
{
package FlashVideo::Site::Vrak;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *from_xml = \&FlashVideo::Utils::from_xml; }
no strict 'refs';



sub find_video {
  my($self, $browser, $embed_url, $prefs) = @_;

  my $check_response = sub {
    my ( $message ) = @_;
    return if $browser->success;
    die sprintf $message, $browser->response->code;
  };


  my $videoID = 0;

  ( $videoID ) = ( $browser->content =~ /var\s+videoId\s*=\s*(\d+)\s*;/i );
  debug "VIDEOID = " . $videoID;
  
  die "No Vrak Video ID found" unless  $videoID;
  
  my $title;
  ( $title ) = ( $browser->content =~ /var\s+videoTitle\s*=\s*"([^"]+)/i );
  
  debug "TITLE = " . $title . " " . title_to_filename($title, 'flv');
 
  my $xmlurl = 'http://www.vrak.tv/webtele/_dyn/getVideoDataXml.jsp?videoId=' . $videoID;
  $browser->get($xmlurl);
  my $xml = from_xml($browser);
  
  my $url;
  if ( $prefs->{quality} == "high" ) {
        $url = $xml->{video}->{highFlvUrl};
  } else {              
        $url = $xml->{video}->{lowFlvUrl};
  }
  debug "URL = " . $url;
  
  my $ext;
  ( $ext ) = ( $url =~ /\.(.+)$/i );

  die "No (high|low)FlvUrl found in XML ". $xmlurl unless $url;
  
  return $url, title_to_filename($title);
  
 }

1;

}
##} blib/lib/FlashVideo/Site/Vrak.pm
BEGIN { $INC{'FlashVideo/Site/Wat.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Wat.pm
{
package FlashVideo::Site::Wat;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *json_unescape = \&FlashVideo::Utils::json_unescape; }
use HTML::Entities;
use URI::Escape;

die "Must have Digest::MD5 for this download\n" 
  unless eval {
    require Digest::MD5;
  };

sub token {
  my $url = shift;
  my $hexdate = sprintf("%x",time());
  $hexdate .= "0" x (length($hexdate) - 8);
  my $key = "9b673b13fa4682ed14c3cfa5af5310274b514c4133e9b3a81e6e3aba00912564";
  return Digest::MD5::md5_hex($key . $url . $hexdate)."/".$hexdate;
}


sub find_video {
  my ($self, $browser) = @_;

  $browser->content =~ /url\s*:\s*["'].*?nIc0K11(\d+)["']/i
    || die "No video ID found";
  my $video_id = $1;

  $browser->get("http://www.wat.tv/interface/contentv3/$video_id");

  my $title = json_unescape(($browser->content =~ /title":"(.*?)",/)[0]);

  my $location = "/web/$video_id";
  my $token = &token($location);

  my $url = "http://www.wat.tv/get".$location.
         "?token=".$token.
         "&context=swf2&getURL=1&version=WIN%2010,3,181,14";

  my $file_type = 'flv';

  $browser->head($url);
  
  if (!$browser->success) {
    die "Couldn't do HEAD request $url: " . $browser->response->status_line;
  }

  my $content_type = $browser->response->header('Content-Type');
  if ($content_type =~ /text/) {
    $browser->get($url);

    if (!$browser->success) {
      die "Couldn't get $url: " . $browser->response->status_line;
    }

    if ($browser->content =~ m'^(http://\S+)') {
      $url = $1;

      if ($url =~ /\.h264/) {
        $file_type = 'mp4';
      }
    }
  }
  else {
    die "Unexpected Content-Type ($content_type) from Wat server."; 
  }

  my $filename = title_to_filename($title, $file_type);

  $browser->allow_redirects;

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Wat.pm
BEGIN { $INC{'FlashVideo/Site/Xhamster.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Xhamster.pm
{
package FlashVideo::Site::Xhamster;

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 $server;
  if ($browser->content =~ m{'srv': '(http://[^'"]+)'}) {
    $server = $1;
  }
  else {
    die "Couldn't determine xhamster server";
  }

  my $video_file;
  if ($browser->content =~ m{'file': '([^'"]+\.flv)'}) {
    $video_file = $1;
  }
  else {
    die "Couldn't determine xhamster video filename";
  }

  my $filename = title_to_filename(extract_title($browser));
 
  my $url = sprintf "%s/flv2/%s", $server, $video_file;

  $browser->allow_redirects;

  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Xhamster.pm
BEGIN { $INC{'FlashVideo/Site/Xnxx.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Xnxx.pm
{
package FlashVideo::Site::Xnxx;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }
use URI::Escape;

sub find_video {
  my ($self, $browser, $embed_url) = @_;

  my $url = ($browser->content =~ /flv_url=(.+?)&/)[0];
  $url = uri_unescape($url);
  die "Unable to extract url" unless $url;

  $browser->content =~ /(?:<span class="style5">|<td style="font-size: 20px;">\s*)<strong>([^<]+)/;

  my $filename = title_to_filename($1);
    
  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Xnxx.pm
BEGIN { $INC{'FlashVideo/Site/Xvideos.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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;
}
##} blib/lib/FlashVideo/Site/Xvideos.pm
BEGIN { $INC{'FlashVideo/Site/Youku.pm'}++; }
##{ blib/lib/FlashVideo/Site/Youku.pm
{
package FlashVideo::Site::Youku;

use strict;
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
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; *get_video_filename = \&FlashVideo::Utils::get_video_filename; }

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 );
}

sub extract {
  my ($json, $key, $type) = @_;
  die "Can't find '$key' key in the JSON data"
    unless exists $json->{$key};
  my $data = $json->{$key};
  if (defined $type) {
    my $dtype = ref $data || 'DATA';
    die "JSON data under '$key' is not the right type"
      . " (expecting $type, but got $dtype)"
      unless $dtype eq $type;
  }
  return $data;
}

sub parse_video_info {
  my ($browser) = @_;

  my $jsonstr = $browser->content;
  debug "Video data: $jsonstr";

  my $json = from_json($jsonstr);

  my $data_array = extract($json, data => 'ARRAY');
  die "No elements found in 'data' array" unless @$data_array;
  my $data = $data_array->[0];

  my $segmap = extract($data, segs => 'HASH');

  my @streamtype_preferences = qw(mp4 flv);
  my @streamtypes = keys %$segmap;

  my $stream = $streamtypes[0];

  for my $pref (@streamtype_preferences) {
    if (grep { $_ eq $pref } @streamtypes) {
      $stream = $pref;
      last;
    }
  }

  my $streams = join ' ', @streamtypes;
  debug "Choosing to use the $stream stream (available: $streams)";

  my $fileID;
  if (exists $data->{streamfileids}) {
    my $streamfileids = extract($data, streamfileids => 'HASH');

    $fileID = extract($streamfileids, $stream)
      if exists $streamfileids->{$stream};
  }

  $fileID = extract($data, 'fileid')
    if not $fileID and exists $data->{fileid};

  die "Can't find the encrypted file ID in the video info JSON"
    unless $fileID;
  debug "Encrypted file ID: $fileID";

  my $shuffle_seed = extract($data, 'seed');

  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 $key1 = extract($data, 'key1');
  my $key2 = extract($data, 'key2');
  my $key = sprintf "%s%x", $key2, hex( $key1 ) ^ hex( 'a55aa5a5' );

  my $title = extract($data, '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 $segs = extract($segmap, $stream, 'ARRAY');

  my @urls;
  my $segment_count = 0;

  for my $seg (@$segs) {
    my $segment_number = extract($seg, 'no');
    my $segment_size = extract($seg, 'size');
    my $segment_seconds = extract($seg, 'seconds');
    $key = extract($seg, 'k') if exists $seg->{'k'};

    my $segment_number_str = sprintf '%02X', $segment_number;
    my $segment_fileID = $fileID;
    substr $segment_fileID, 8, 2, $segment_number_str;

    $browser->get(
      sprintf "http://f.youku.com/player/getFlvPath/sid/%s/st/%s/fileid/%s?K=%s&myp=0&ts=%s",
        $sID, $stream, $segment_fileID, $key, $segment_seconds );

    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 for segment $segment_number is $url";
    $url = "$url.$stream" unless $url =~ /$stream$/;

    debug sprintf "%s, segment %d, %s seconds, %s bytes",
      $title, $segment_number, $segment_seconds, $segment_size
      if ( $title and $segment_seconds and $segment_size );

    push @urls, [$url, ++$segment_count, 0, $segment_size];
  }

  $_->[2] = $segment_count for @urls;

  return ( \@urls, $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;
}
##} blib/lib/FlashVideo/Site/Youku.pm
BEGIN { $INC{'FlashVideo/Site/Youtu.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
BEGIN { $INC{'FlashVideo/Site/Youtube.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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_info = \&FlashVideo::Utils::extract_info; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *url_exists = \&FlashVideo::Utils::url_exists; *swfhash = \&FlashVideo::Utils::swfhash; *json_unescape = \&FlashVideo::Utils::json_unescape; }
BEGIN { FlashVideo::JSON->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *from_json = \&FlashVideo::JSON::from_json; }
use URI::Escape;

my @formats = (
  { id => 38, resolution => [4096, 2304] },
  { id => 37, resolution => [1920, 1080] },
  { id => 22, resolution => [1280, 720] },
  { id => 35, resolution => [854, 480] },
  { id => 34, resolution => [640, 360] },
  { id => 18, resolution => [480, 270] },
  { id => 5,  resolution => [400, 224] },
  { id => 17, resolution => [176, 144] },
  { id => 13, resolution => [176, 144] },
);

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  if($embed_url !~ m!youtube\.com/watch!) {
    $browser->get($embed_url);
    if ($browser->response->header('Location') =~ m!/swf/.*video_id=([^&]+)!
        || $browser->content =~ m!\<iframe[^\>]*src="http://www.youtube.com/embed/([^"]+)"!i
        || $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) {
    verify_age($browser, $prefs);
  }

  my $title = extract_info($browser)->{meta_title};
  if (!$title and
    $browser->content =~ /<div id="vidTitle">\s+<span ?>(.+?)<\/span>/ or
      $browser->content =~ /<div id="watch-vid-title">\s*<div ?>(.+?)<\/div>/) {
    $title = $1;
  }

  if ($browser->content =~ /["']fmt_url_map["']:\s{0,3}(["'][^"']+["'])/) {
    my $fmt_map = $1;
    if ($fmt_map !~ /\|/) {
      $fmt_map = uri_unescape($fmt_map);
    }
    debug "Using fmt_url_map method from page ($fmt_map)";
    return $self->download_fmt_map($prefs, $browser, $title, {}, @{from_json $fmt_map});
  }

  my $video_id;
  if ($browser->content =~ /(?:var pageVideoId =|(?:CFG_)?VIDEO_ID'?\s*:)\s*'(.+?)'/
      || $browser->content =~ /"video_id": "([^"]+)"/
      || $embed_url =~ /v=([^&]+)/
      || $browser->content =~ /&amp;video_id=([^&]+)&amp;/) {
    $video_id = $1;
  } else {
    check_die($browser, "Couldn't extract video ID");
  }

  my $t;
  if ($browser->content =~ /\W['"]?t['"]?: ?['"](.+?)['"]/) {
    $t = $1;
  }

  my $video_page_url = $browser->uri->as_string;

  if (my %info = get_youtube_video_info($browser->clone, $video_id, $video_page_url, $t)) {
    if($self->debug) {
      require Data::Dumper;
      debug Data::Dumper::Dumper(\%info);
    }

    if ($info{conn} =~ /^rtmp/) {
      my ($season, $episode);

      if ($browser->content =~ m{<span[^>]*>Season ?(\d+)}i) {
        $season = $1;
      }

      if ($browser->content =~ m{<span[^>]*>[^<]+Ep\.?\w* ?(\d+)\W*\s*</span>}i) {
        $episode = $1;
      }

      if ($season and $episode) {
        $title .= sprintf " S%02dE%02d", $season, $episode;
      }

      my $swf_url;
      if ($browser->content =~ /SWF_URL['"] ?: ?.{0,90}?(http:\/\/[^ ]+\.swf)/) {
        $swf_url = $1;
      } elsif($browser->content =~ /swfConfig\s*=\s*(\{.*?\});/ && (my $swf = from_json($1))) {
        $swf_url = $swf->{url};
      } elsif($browser->content =~ /src=\\['"]([^'"]+\.swf)/) {
        $swf_url = json_unescape($1);
      } else {
        die "Couldn't extract SWF URL";
      }

      my $rtmp_url = $info{conn};

      if($info{fmt_stream_map}) {
        my $fmt_stream_map = parse_youtube_format_url_map($info{fmt_stream_map}, 1);

        my $preferred_quality = $prefs->quality->choose(map { $fmt_stream_map->{$_->{id}}
            ? { resolution => $_->{resolution}, url => $fmt_stream_map->{$_->{id}} }
            : () } @formats);

        $rtmp_url = $preferred_quality->{url};
      }

      return {
        flv => title_to_filename($title),
        rtmp => $rtmp_url,
        swfhash($browser, $swf_url)
      };
    } elsif($info{fmt_url_map}) {
      debug "Using fmt_url_map method from info";
      return $self->download_fmt_map($prefs, $browser, $title, \%info, $info{fmt_url_map});
    } elsif($info{url_encoded_fmt_stream_map}) {
      debug "Using url_encoded_fmt_stream_map method from info";
      if ($info{title}) {
        $title=$info{title};
      }
      return $self->download_url_encoded_fmt_stream_map($prefs, $browser, $title, \%info, $info{url_encoded_fmt_stream_map});
    }
  }

  return download_get_video($browser, $prefs, $video_id, $title, $t);
}

sub download_url_encoded_fmt_stream_map {
  my($self, $prefs, $browser, $title, $info, $fmt_map) = @_;

  my $fmt_url_map = parse_youtube_url_encoded_fmt_stream_map($fmt_map);

  if (!$title and $browser->uri->as_string =~ m'/user/.*?#') {
    my $video_id = (split /\//, $browser->uri->fragment)[-1];

    my %info = get_youtube_video_info($browser->clone, $video_id);

    $title = $info->{title};
  }

  my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}}
      ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} }
      : () } @formats);

  $browser->allow_redirects;

  return $preferred_quality->{url}, title_to_filename($title, "mp4");
}

sub parse_youtube_url_encoded_fmt_stream_map {
  my($raw_map) = @_;;

  my $map = {};

  foreach my $params (split /,/, $raw_map) {
    
    my $format = "";
    my $url = "";
    
    foreach my $pair (split /&/, $params) {
      my ($name, $value) = split /=/, $pair;
      if ($name eq "itag"){
        $format = $value;
      } elsif ($name eq "url") {
        $url = uri_unescape($value);
      }
    }
    
    $map->{$format} = $url;
  }
  
  return $map;
}

sub download_fmt_map {
  my($self, $prefs, $browser, $title, $info, $fmt_map) = @_;

  my $fmt_url_map = parse_youtube_format_url_map($fmt_map);

  if (!$title and $browser->uri->as_string =~ m'/user/.*?#') {
    my $video_id = (split /\//, $browser->uri->fragment)[-1];

    my %info = get_youtube_video_info($browser->clone, $video_id);

    $title = $info->{title};
  }

  my $preferred_quality = $prefs->quality->choose(map { $fmt_url_map->{$_->{id}}
      ? { resolution => $_->{resolution}, url => $fmt_url_map->{$_->{id}} }
      : () } @formats);

  $browser->allow_redirects;

  return $preferred_quality->{url}, title_to_filename($title, "mp4");
}

sub download_get_video {
  my($browser, $prefs, $video_id, $title, $t) = @_;

  my $fetcher = sub {
    my($url, $filename) = @_;
    $url = url_exists($browser->clone, $url, 1);
    return $url, $filename if $url;
    return;
  };

  my @formats_to_try = @formats;

  while(my $fmt = $prefs->quality->choose(@formats_to_try)) {
    @formats_to_try = grep { $_ != $fmt } @formats_to_try;

    my @ret = $fetcher->("http://www.youtube.com/get_video?fmt=$fmt->{id}&video_id=$video_id&t=$t",
      title_to_filename($title, "mp4"));
    return @ret if @ret;
  }

  my @ret = $fetcher->("http://www.youtube.com/get_video?video_id=$video_id&t=$t",
    title_to_filename($title));

  check_die($browser, "Unable to find video URL") unless @ret;

  $browser->allow_redirects;

  return @ret;
}

sub check_die {
  my($browser, $message) = @_;

  if($browser->content =~ m{class="yt-alert-content">([^<]+)}) {
    my $alert = $1;
    $alert =~ s/(^\s+|\s+$)//g;
    $message .= "\nYouTube: $alert";
    error $message;
    exit 1;
  } else {
    die "$message\n";
  }
}

sub verify_age {
  my($browser, $prefs) = @_;
  my $orig_uri = $browser->uri;

  if ($browser->response->code == 303 
    && $browser->response->header('Location') =~ m!/verify_age|/accounts/!) {

    my $confirmation_url = $browser->response->header('Location');
    $browser->get($confirmation_url);

    if($browser->content =~ /has_verified=1/) {
      my($verify_url) = $browser->content =~ /href="(.*?has_verified=1)"/;
      $verify_url = decode_entities($verify_url);
      $browser->get($verify_url);
      return if $browser->response->code == 200;
    }

    my $account = $prefs->account("youtube", <<EOT);
Unfortunately, due to Youtube being lame, you have to have
an account to download this video. (See the documentation for how to configure
~/.netrc)

EOT

    unless ($account->username and $account->password) {
      error "You must supply Youtube account details.";
      exit 1;
    }

    $browser->get("http://www.youtube.com/login");
    if ($browser->response->code != 303) {
      die "Unexpected response from Youtube login.\n";
    }

    my $real_login_url = $browser->response->header('Location');
    $browser->get($real_login_url);

    $browser->form_with_fields('Email', 'Passwd');
    $browser->set_fields(
      Email  => $account->username,
      Passwd => $account->password,
    );
    $browser->submit();

    if ($browser->content =~ /your login was incorrect/) {
      error "Couldn't log you in, check your username and password.";
      exit 1;
    } elsif ($browser->response->code == 302) {
      my $check_cookie_url = $browser->response->header('Location');
      $browser->get($check_cookie_url);

      if ($browser->content =~ /<meta.*"refresh".*?url=&#39;(.*?)&#39;"/i) {
        my $redirected = decode_entities($1);
        $browser->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($orig_uri);

    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->response->code == 303) {
      debug "Video not available (303), trying " . $browser->response->header('Location');
      $browser->get($browser->response->header('Location'));
    }

    if (!$browser->success) {
      die "Couldn't download URL: " . $browser->response->status_line;
    }
  }
}

sub get_youtube_video_info {
  my ($browser, $video_id, $url, $t) = @_;

  $url ||= "http://www.youtube.com/watch?v=$video_id";

  for my $el(qw(profilepage detailpage)) {
    my $video_info_url_template =
      "http://www.youtube.com/get_video_info?&video_id=%s&el=$el&ps=default&eurl=%s&hl=en_US&t=%s";

    my $video_info_url = sprintf $video_info_url_template,
      uri_escape($video_id), uri_escape($url), uri_escape_utf8($t);

    debug "get_youtube_video_info: $video_info_url";

    $browser->get($video_info_url);

    next unless $browser->success;

    my %info = parse_youtube_video_info($browser->content);
    next if $info{status} eq 'fail';

    return %info;
  }

  error "Unable to get YouTube video information.";
}

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;
}

sub parse_youtube_format_url_map {
  my($raw_map, $param_idx) = @_;

  $param_idx = 0 unless defined $param_idx;

  my $map = {};

  foreach my $pair (split /,/, $raw_map) {
    my ($format, @params) = split /\|/, $pair;

    my $url = $params[$param_idx];

    $url = uri_unescape($url);

    $map->{$format} = $url;
  }
  
  return $map;
}

1;
}
##} blib/lib/FlashVideo/Site/Youtube.pm
##{ blib/lib/FlashVideo/Site/Youtu.pm
{
package FlashVideo::Site::Youtu;

BEGIN { FlashVideo::Site::Youtube->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Youtube';

1;
}
##} blib/lib/FlashVideo/Site/Youtu.pm
BEGIN { $INC{'FlashVideo/Site/Youtubenocookie.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Youtubenocookie.pm
{
package FlashVideo::Site::Youtubenocookie;

use strict;
BEGIN { FlashVideo::Site::Youtube->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Site::Youtube';

1;
}
##} blib/lib/FlashVideo/Site/Youtubenocookie.pm
BEGIN { $INC{'FlashVideo/Site/Zdf.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Site/Zdf.pm
{
package FlashVideo::Site::Zdf;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *title_to_filename = \&FlashVideo::Utils::title_to_filename; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  my ($id, $filename, $videourl, $quality);

  $quality = {high => 'veryhigh', low => 'low'}->{$prefs->{quality}};

  debug "Zdf::find_video called, embed_url = \"$embed_url\"\n";

  if($browser->content =~ /\/video\/(\d*)\/(.*)"/) {
    $id = $1;
    debug "found video $1 $2\n";
    $filename = title_to_filename($2);

    $browser->get("http://www.zdf.de/ZDFmediathek/xmlservice/web/beitragsDetails?id=$id&ak=web");

    if($browser->content =~ /(http:\/\/fstreaming\.zdf\.de\/zdf\/$quality\/.*\.meta)/) {
        $browser->get($1);
        if($browser->content =~ /(rtmp.*)</) {
            debug "found rtmp url\"$1\"\n";
            $videourl = {
                rtmp => $1,
                flv => $filename,
                swfVfy => "http://www.zdf.de/ZDFmediatek/flash/player.swf"
            };
        }
    }
  }
  return $videourl, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Zdf.pm
BEGIN { $INC{'FlashVideo/Site/Zshare.pm'}++; }
# A get-flash-videos module for the zshare.net website
#################################################
#
# 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
#
#################################################
# Copyright (C) 2011 Rudolf Olah <rolah@goaugust.com>
# Licensed under the GNU GPL v3 or later

# Created using the instructions from: http://code.google.com/p/get-flash-videos/wiki/AddingSite

##{ blib/lib/FlashVideo/Site/Zshare.pm
{
package FlashVideo::Site::Zshare;

use strict;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; }

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;
  $embed_url = ($browser->content =~ /iframe src="(.*videoplayer.*?)"/i)[0];
  $browser->get($embed_url);
  my $url = ($browser->content =~ /file:.*"(.*?)"/i)[0];
  my $filename = ($browser->content =~ /<title>.*?- (.*)<\/title>/i)[0];
  return $url, $filename;
}

1;
}
##} blib/lib/FlashVideo/Site/Zshare.pm
##{ .sitemodules
{
package main;
}
##} .sitemodules
#!/usr/bin/perl
BEGIN { $INC{'FlashVideo/URLFinder.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
BEGIN { $INC{'FlashVideo/Generic.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/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; *extract_title = \&FlashVideo::Utils::extract_title; *title_to_filename = \&FlashVideo::Utils::title_to_filename; *get_video_filename = \&FlashVideo::Utils::get_video_filename; *url_exists = \&FlashVideo::Utils::url_exists; *EXTENSIONS = \&FlashVideo::Utils::EXTENSIONS; }
use URI;
BEGIN { FlashVideo::URLFinder->import(); } # (added by utils/combine-perl.pl)
use URI::Escape qw(uri_unescape);

my $video_re = qr!http[-:/a-z0-9%_.?=&]+@{[EXTENSIONS]}
                  (?:\?[-:/a-z0-9%_.?=&]+)?!xi;

sub find_video {
  my ($self, $browser, $embed_url, $prefs) = @_;

  if (!$browser->success) {
    $browser->get($browser->response->header('Location'));
    die "Couldn't download URL: " . $browser->response->status_line
      unless $browser->success;
  }

  my ($possible_filename, $actual_url, $title);
  $title = extract_title($browser);

  my @flv_urls = map {
    (m{http://.+?(http://.+?@{[EXTENSIONS]})}i) ? $1 : $_
  } ($browser->content =~ m{($video_re)}gi);
  if (@flv_urls) {
    require LWP::Simple;
    require Memoize;
    Memoize::memoize("LWP::Simple::head");
    @flv_urls = sort { (LWP::Simple::head($a))[1] <=> (LWP::Simple::head($b))[1] } @flv_urls;
    $possible_filename = (split /\//, $flv_urls[-1])[-1];

    if ($flv_urls[-1] =~ /^http%3a%2f%2f/) {
      $flv_urls[-1] = uri_unescape($flv_urls[-1])
    }
    
    $actual_url = url_exists($browser->clone, $flv_urls[-1]);
  }

  my $filename_is_reliable;

  if(!$actual_url) {
    RE: for my $regex(
        qr{(?si)<embed.*?flashvars=["']?([^"'>]+)},
        qr{(?si)<embed.*?src=["']?([^"'>]+)},
        qr{(?si)<a[^>]* href=["']?([^"'>]+?@{[EXTENSIONS]})},
        qr{(?si)<object[^>]*>.*?<param [^>]*value=["']?([^"'>]+)},
        qr{(?si)<object[^>]*>(.*?)</object>},
        qr{(?si)<script[^>]*>(.*?)</script>}) {

      for my $param($browser->content =~ /$regex/gi) {
        (my $url, $possible_filename, $filename_is_reliable) = find_file_param($browser->clone, $param, $prefs);

        if($url) {
          my $resolved_url = url_exists($browser->clone, $url);
          if($resolved_url) {
            $actual_url = $resolved_url;
            last RE;
          }
        }
      }
    }

    if(!$actual_url) {
      for my $iframe($browser->content =~ /<iframe[^>]+src=["']?([^"'>]+)/gi) {
        $iframe = URI->new_abs($iframe, $browser->uri);
        debug "Found iframe: $iframe";
        my $sub_browser = $browser->clone;
        $sub_browser->get($iframe);
        my($package, $possible_url) = FlashVideo::URLFinder->find_package($iframe, $sub_browser);

        if($package->can("pre_find")) {
          $package->pre_find($sub_browser);
        }

        info "Downloading $iframe";
        $sub_browser->get($iframe);

        my($actual_url, @suggested_fnames) = eval {
          $package->find_video($sub_browser, $possible_url, $prefs);
        };
        return $actual_url, @suggested_fnames if $actual_url;
      }
    }
  }

  my @filenames;
  
  return $actual_url, $possible_filename if $filename_is_reliable;

  $possible_filename =~ s/\?.*//;
  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;


  my %swf_urls;

  if (eval { require URI::Find }) {
    my $finder = URI::Find->new(
      sub { $swf_urls{$_[1]}++ if $_[1] =~ /\.swf$/i }
    );
    $finder->find(\$browser->content);
  }
  else {
    my $content = $browser->content;
    while($content =~ m{(http://[^ "']+?\.swf)}ig) {
      $swf_urls{$1}++;
    }
  }

  if (%swf_urls) {
    foreach my $swf_url (keys %swf_urls) {
      if (my ($flv_url, $title) = search_for_flv_in_swf($browser, $swf_url)) {
        return $flv_url, title_to_filename($title);
      }
    }
  }

  die "No URLs found";
}

sub search_for_flv_in_swf {
  my ($browser, $swf_url) = @_;

  $browser = $browser->clone();

  $browser->get($swf_url);

  if (!$browser->success) {
    die "Couldn't download SWF URL $swf_url: " .
      $browser->response->status_line();
  }

  my $swf_data = $browser->content;

  if ('C' eq substr $swf_data, 0, 1) {
    if (eval { require Compress::Zlib }) {
      $swf_data = Compress::Zlib::uncompress(substr $swf_data, 8);
    }
    else {
      die "Compress::Zlib is required to uncompress compressed SWF files.\n";
    }
  }

  if ($swf_data =~ m{(http://.{10,300}?\.flv)}i) {
    my $flv_url = $1;

    my $filename = uri_unescape(File::Basename::basename(URI->new($flv_url)->path()));
    $filename =~ s/\.flv$//i;

    return ($flv_url, $filename);
  }

  return;
}

sub find_file_param {
  my($browser, $param, $prefs) = @_;

  for my $file($param =~ /(?:video|movie|file|path)_?(?:href|src|url)?['"]?\s*[=:,]\s*['"]?([^&'" ]+)/gi,
      $param =~ /(?:config|playlist|options)['"]?\s*[,:=]\s*['"]?(http[^'"&]+)/gi,
      $param =~ /['"=](.*?@{[EXTENSIONS]})/gi,
      $param =~ /([^ ]+@{[EXTENSIONS]})/gi,
      $param =~ /SWFObject\(["']([^"']+)/) {

    debug "Found $file";

    my ($actual_url, $filename, $filename_is_reliable) = guess_file($browser, $file, '', $prefs);

    if(!$actual_url && $file =~ /\?(.*)/) {
      debug "Trying query param on $1";

      for my $query_param(split /[;&]/, $1) {
        my($query_key, $query_value) = split /=/, $query_param;
        debug "Found $query_value from $query_key";

        ($actual_url, $filename, $filename_is_reliable)
          = guess_file($browser, $query_value, '', $prefs);

        last if $actual_url;
      }
    }

    if($actual_url) {
      my $possible_filename = $filename || (split /\//, $actual_url)[-1];

      return $actual_url, $possible_filename, $filename_is_reliable;
    }
  }

  if($param =~ m{(rtmp://[^ &"']+)}) {
    info "This looks like RTMP ($1), no generic support yet..";
  }
  
  return;
}

sub guess_file {
  my($browser, $file, $once, $prefs) = @_;

  $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 ($package, $url) = FlashVideo::URLFinder->find_package($uri,
        $browser->clone);

      if($package && $package ne __PACKAGE__) {
        debug "$uri is supported by $package.";
        (my $browser_on_supported_site = $browser->clone())->get($uri);
        return $package->find_video($browser_on_supported_site, $uri, $prefs), 1;
      }

      my $content_type = $browser->response->header("Content-type");

      if($content_type =~ m!^(text|application/xml)!) {
        $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 =~ /<html[^>]*>/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, $prefs);
        } 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, $prefs);
          }
        }
      }
    }
  }

  return;
}

1;
}
##} blib/lib/FlashVideo/Generic.pm
##{ blib/lib/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::Site->import(); } # (added by utils/combine-perl.pl)
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *info = \&FlashVideo::Utils::info; }
use URI;


my @extra_can_handle = qw(Brightcove Mtvnservices Gawker Ooyala Gorillavid);

sub find_package {
  my($class, $url, $browser) = @_;
  my $package = _find_package_url($url, $browser);

  if(!defined $package) {

    for my $possible_url($browser->content =~
        m!(?:<object[^>]+>.*?|<(?:script|embed|iframe|param) [^>]*(?:src=["']?|name=["']src["']\ value=["']))(http://[^"'> ]+)!gixs) {
      $package = _find_package_url($possible_url, $browser);

      return _found($package, $possible_url) if defined $package;
    }
  }

  if(!defined $package) {
    for(@extra_can_handle) {
      my $possible_package = _load($_);

      $browser->get($url);

      my $r = $possible_package->can_handle($browser, $url);
      if($r) {
        $package = $possible_package;
        last;
      }
    }
  }

  if(!defined $package) {
    $package = "FlashVideo::Generic";
  }

  return _found($package, $url);
}


sub _find_package_url {
  my($url, $browser) = @_;
  my $package;

  foreach my $host_part (split /\./, URI->new($url)->host) {
    $host_part = lc $host_part;
    $host_part =~ s/[^a-z0-9]//i;

    my $possible_package = _load($host_part);

    if($possible_package->can("find_video")) {

      if($possible_package->can("can_handle")) {
        next unless $possible_package->can_handle($browser, $url);
      }

      $package = $possible_package;
      last;
    }
  }

  return $package;
}

sub _found {
  my($package, $url) = @_;
  info "Using method '" . lc((split /::/, $package)[-1]) . "' for $url";
  return $package, $url;
}

sub _load {
  my($site) = @_;

  my $package = "FlashVideo::Site::" . ucfirst lc $site;

  if(eval "require $package") {
    no strict 'refs';
    push @{$package . "::ISA"}, "FlashVideo::Site";
  }
  return $package;
}

1;
}
##} blib/lib/FlashVideo/URLFinder.pm
BEGIN { $INC{'FlashVideo/RTMPDownloader.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/RTMPDownloader.pm
{
package FlashVideo::RTMPDownloader;

use strict;
BEGIN { FlashVideo::Downloader->import(); } # (added by utils/combine-perl.pl)
use base 'FlashVideo::Downloader';
use IPC::Open3;
use Fcntl ();
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; *swfhash = \&FlashVideo::Utils::swfhash; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; }

use constant LATEST_RTMPDUMP => 2.2;

sub download {
  my ($self, $rtmp_data, $file) = @_;

  $self->{printable_filename} = $file;

  $file = $rtmp_data->{flv} = $self->get_filename($file);

  if (-s $file && !$rtmp_data->{live}) {
    info "RTMP output filename '$self->{printable_filename}' already " .
                 "exists, asking to resume...";
    $rtmp_data->{resume} = '';
  }

  if(my $socks = FlashVideo::Mechanize->new->get_socks_proxy) {
    $rtmp_data->{socks} = $socks;
  }

  my($r_fh, $w_fh); # So Perl doesn't close them behind our back..

  if ($rtmp_data->{live} && $self->action eq 'play') {

    pipe($r_fh, $w_fh);

    my $pid = fork;
    die "Fork failed" unless defined $pid;
    if(!$pid) {
      fcntl $r_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC();
      exec $self->replace_filename($self->player, "/dev/fd/" . fileno $r_fh);
      die "Exec failed\n";
    }

    fcntl $w_fh, Fcntl::F_SETFD(), ~Fcntl::FD_CLOEXEC();
    $rtmp_data->{flv} = "/dev/fd/" . fileno $w_fh;

    $self->{stream} = undef;
  }

  my $prog = $self->get_rtmp_program;

  if($prog eq 'flvstreamer' && ($rtmp_data->{rtmp} =~ /^rtmpe:/ || $rtmp_data->{swfhash})) {
    error "FLVStreamer does not support "
      . ($rtmp_data->{swfhash} ? "SWF hashing" : "RTMPE streams")
      . ", please install rtmpdump.";
    exit 1;
  }

  if($self->debug) {
    $rtmp_data->{verbose} = undef;
  }

  my($return, @errors) = $self->run($prog, $rtmp_data);

  if($return != 0 && "@errors" =~ /failed to connect/i) {
    info "Couldn't connect on RTMP port, trying port 443 instead";
    $rtmp_data->{port} = 443;
    ($return, @errors) = $self->run($prog, $rtmp_data);
  }

  if($file ne '-' && (-s $file < 100 || !$self->check_file($file))) {
    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 get_command {
  my($self, $rtmp_data, $debug) = @_;

  return map {
    my $arg = $_;

    (ref $rtmp_data->{$arg} eq 'ARRAY'
      ? (map {
        ("--$arg" => $debug
          ? $self->shell_escape($_)
          : $_) } @{$rtmp_data->{$arg}})
      : ("--$arg" => (($debug && $rtmp_data->{$arg})
        ? $self->shell_escape($rtmp_data->{$arg})
        : $rtmp_data->{$arg}) || ()))
  } keys %$rtmp_data;
}

sub run {
  my($self, $prog, $rtmp_data) = @_;

  debug "Running $prog", join(" ", $self->get_command($rtmp_data, 1));

  my($in, $out, $err);
  $err = gensym;
  my $pid = open3($in, $out, $err, $prog, $self->get_command($rtmp_data));

  local $SIG{INT};
  if ($^O =~ /mswin/i) {
    $SIG{INT} = sub {
      kill 'TERM', $pid;
      exit;
    };
  }

  my $complete = 0;
  my $buf = "";
  my @error;

  while(sysread($err, $buf, 128, length $buf) > 0) {
    $buf =~ s/\015\012/\012/g;

    my @parts = split /\015/, $buf;
    $buf = "";

    for(@parts) {
      if(/^((?:DEBUG:|WARNING:|Closing connection|ERROR: No playpath found).*)\n/) {
        debug "$prog: $1";
      } elsif(/^(ERROR: .*)\012/) {
        push @error, $1;
        info "$prog: $1";
      } elsif(/^([0-9.]+) kB(?:\s+\/ \S+ sec)?(?: \(([0-9.]+)%\))?/i) {
        $self->{downloaded} = $1 * 1024;
        my $percent = $2;

        if($self->{downloaded} && $percent != 0) {
          $self->{content_length} = $self->{downloaded} / ($percent / 100);
        }

        $self->progress;
      } elsif(/\012$/) {
        for my $l(split /\012/) {
          if($l =~ /^[A-F0-9]{,2}(?:\s+[A-F0-9]{2})*\s*$/) {
            debug $l;
          } elsif($l =~ /Download complete/) {
            $complete = 1;
          } elsif($l =~ /\s+filesize\s+(\d+)/) {
            $self->{content_length} = $1;
          } elsif($l =~ /\w/) {
            print STDERR "\r" if $self->{downloaded};
            info $l;

            if($l =~ /^RTMPDump v([0-9.]+)/ && $1 < LATEST_RTMPDUMP) {
              error "==== Using the latest version of RTMPDump (version "
                . LATEST_RTMPDUMP . ") is recommended. ====";
            }
          }
        }

        if(/open3/) {
          error "\nMake sure you have 'rtmpdump' or 'flvstreamer' installed and available on your PATH.";
          return 0;
        }
      } else {
        $buf = $_;
      }
    }

    if(defined $self->{stream} && $self->{downloaded} > 300_000) {
      $self->{stream}->();
    }
  }

  waitpid $pid, 0;
  return $? >> 8, @error;
}

1;
}
##} blib/lib/FlashVideo/RTMPDownloader.pm
BEGIN { $INC{'FlashVideo/Search.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/Search.pm
{
package FlashVideo::Search;

use strict;
use Carp;
BEGIN { FlashVideo::Utils->import(); } # (added by utils/combine-perl.pl)
BEGIN { no strict 'refs'; *debug = \&FlashVideo::Utils::debug; *info = \&FlashVideo::Utils::info; }

my @sites_with_search = ('4oD', 'GoogleVideoSearch');

sub search {
  my ($class, $search, $max_per_site, $max_results) = @_;

  my @search_sites = map { FlashVideo::URLFinder::_load($_) } @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::URLFinder::_load($possible_site);

    if ($possible_package->can("search")) {
      debug "Search for '$search' will only search $possible_site.";

      $search =~ s/^\w+ //;

      return search_site($possible_package, $search, "site", $max_results);
    }
  }

  my @plugins = App::get_flash_videos::get_installed_plugins();

  foreach my $plugin (@plugins) {
    $plugin =~ s/\.pm$//;

    my $plugin_package = FlashVideo::URLFinder::_load($plugin);

    if ($plugin_package->can("search")) {
      debug "Plugin '$plugin' has a search method.";

      unshift @search_sites, $plugin_package;
    }
    else {
      debug "Plugin '$plugin' doesn't have a search method.";
    }
  }

  my @results = map { search_site($_, $search, "all", $max_per_site) } @search_sites;

  trim_resultset(\@results, $max_results);

  return @results;
}

sub search_site {
  my($search_site, $search, $type, $max) = @_;

  debug "Searching '$search_site' for '$search'.";

  if (my @site_results = eval { $search_site->search($search, $type) }) {
    debug "Found " . @site_results . " results for $search.";

    trim_resultset(\@site_results, $max);
    return @site_results;
  }
  elsif($@) {
    info "Searching '$search_site' failed with: $@";
  }
  else {
    debug "No results found for '$search'.";
  }

  return ();
}

sub trim_resultset {
  my ($results, $max) = @_;

  croak "Must be supplied a reference to resultset" unless ref($results) eq 'ARRAY';
  croak "No max supplied" unless $max;

  if (@$results > $max) {
    debug "Found " . @$results . " results, trimming to $max.";
    splice @$results, $max;
  }
}

1;
}
##} blib/lib/FlashVideo/Search.pm
BEGIN { $INC{'FlashVideo/VideoPreferences.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
BEGIN { $INC{'FlashVideo/VideoPreferences/Quality.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/VideoPreferences/Quality.pm
{
package FlashVideo::VideoPreferences::Quality;

use strict;

my %format_map = (
  "240p"  => [320,  240,  "low"],
  "240w"  => [427,  240,  "low"],
  "480p"  => [640,  480,  "medium"],
  "480w"  => [854,  480,  "medium"],
  "576p"  => [720,  576,  "medium"],
  "720p"  => [1280, 720,  "high"],
  "1080p" => [1920, 1080, "high"],
);

sub new {
  my($class, $quality) = @_;

  return bless \$quality, $class;
}

sub name {
  my($self) = @_;
  return $$self;
}

sub choose {
  my($self, @available) = @_;

  

  my $max_preferred_res = $self->quality_to_resolution($self->name);
  my $max_preferred_size = $max_preferred_res->[0] * $max_preferred_res->[1];

  my @sorted = 
    sort { $a->[0] <=> $b->[0] }
    map { my $r = $_->{resolution}; $r = $r->[0] * $r->[1]; [$r, $_] } @available;

  if(my @at_or_under_preferred = grep { $_->[0] <= $max_preferred_size } @sorted) {
    return $at_or_under_preferred[-1]->[1];
  } else {
    return $sorted[0]->[1];
  }
}

sub format_to_resolution {
  my($self, $name) = @_;
  $name .= "p" if $name !~ /[a-z]$/i;

  if(my $resolution = $format_map{lc $name}) {
    return $resolution;
  } elsif(my $num = ($name =~ /(\d+)/)[0]) {
    my $resolution = [($num) x 2];
    return [@$resolution, $self->resolution_to_quality($resolution)];
  }

  die "Unknown format '$name'";
}

sub quality_to_resolution {
  my($self, $quality) = @_;

  if($quality =~ /^(\d+)x(\d+)$/) {
    my $resolution = [$1, $2];
    return [@$resolution, $self->resolution_to_quality($resolution)];

  } elsif(my $resolution = eval { $self->format_to_resolution($quality) }) {
    return $resolution;

  } else {
    for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) }
        values %format_map) {
      if($r->[2] eq lc $quality) {
        return $r;
      }
    }
  }

  die "Unknown quality '$quality'";
}

sub resolution_to_quality {
  my($self, $resolution) = @_;

  my $quality = "high";

  for my $r(sort { ($b->[0]*$b->[1]) <=> ($a->[0]*$a->[1]) }
      values %format_map) {
    $quality = $r->[2] if $r->[0] >= $resolution->[0];
  }

  return $quality;
}

1;
}
##} blib/lib/FlashVideo/VideoPreferences/Quality.pm
BEGIN { $INC{'FlashVideo/VideoPreferences/Account.pm'}++; }
# Part of get-flash-videos. See get_flash_videos for copyright.
##{ blib/lib/FlashVideo/VideoPreferences/Account.pm
{
package FlashVideo::VideoPreferences::Account;

use strict;

sub new {
  my($class, $site, $prompt) = @_;

  require Net::Netrc; # Core since 5.8

  my $record = Net::Netrc->lookup($site);
  my($user, $pass) = $record ? $record->lpa : ();


  if(!$user) {
    print $prompt;

    print "Username: ";
    chomp($user = <STDIN>);
  }

  if(!$pass) {
    print "Ok, need your password";
    if(eval { require Term::ReadKey }) {
      print ": ";
      Term::ReadKey::ReadMode(2);
      chomp($pass = <STDIN>);
      Term::ReadKey::ReadMode(0);
      print "\n";
    } else {
      print " (will be displayed): ";
      chomp($pass = <STDIN>);
    }
  }
  
  return bless {
    username => $user,
    password => $pass,
  }, $class;
}

sub username {
  my($self) = @_;
  return $self->{username};
}

sub password {
  my($self) = @_;
  return $self->{password};
}

1;
}
##} blib/lib/FlashVideo/VideoPreferences/Account.pm
##{ blib/lib/FlashVideo/VideoPreferences.pm
{
package FlashVideo::VideoPreferences;

use strict;
BEGIN { FlashVideo::VideoPreferences::Quality->import(); } # (added by utils/combine-perl.pl)
BEGIN { FlashVideo::VideoPreferences::Account->import(); } # (added by utils/combine-perl.pl)

sub new {
  my($class, %opt) = @_;

  return bless {
    quality => $opt{quality} || "high",
    subtitles => $opt{subtitles} || 0,
  }, $class;
}

sub quality {
  my($self) = @_;

  return FlashVideo::VideoPreferences::Quality->new($self->{quality});
}

sub subtitles {
  my($self) = @_;

  return $self->{subtitles};
}

sub account {
  my($self, $site, $prompt) = @_;

  return FlashVideo::VideoPreferences::Account->new($site, $prompt);
}

1;
}
##} blib/lib/FlashVideo/VideoPreferences.pm
##{ bin/get_flash_videos
{
package main;
$::SCRIPT_NAME = "get_flash_videos";
$::INSTALL_TYPE = "cpan-manual";

package App::get_flash_videos;
use strict;
use Encode ();
use File::Basename qw(basename);
use File::stat;
use Getopt::Long;
use Text::Wrap;

BEGIN {
  if(!$::SCRIPT_NAME) {
    require Cwd;
    require File::Spec;
    my($vol, $dir) = (File::Spec->splitpath(Cwd::realpath($0)))[0, 1];
    unshift @INC, File::Spec->catpath($vol, File::Spec->catdir($dir, "lib"));
  }
}

BEGIN { FlashVideo::URLFinder->import(); } # (added by utils/combine-perl.pl)
BEGIN { FlashVideo::Mechanize->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; *get_user_config_dir = \&FlashVideo::Utils::get_user_config_dir; *get_win_codepage = \&FlashVideo::Utils::get_win_codepage; *is_program_on_path = \&FlashVideo::Utils::is_program_on_path; *get_terminal_width = \&FlashVideo::Utils::get_terminal_width; }
BEGIN { FlashVideo::VideoPreferences->import(); } # (added by utils/combine-perl.pl)

unshift @INC, \&plugin_loader;

our $VERSION = "1.25";

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("xdg-open") && !is_program_on_path("mplayer")) {
    $player = "xdg-open";
  } elsif(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,
    quality => "high",
    subtitles => 0,
    info => 0
  );
}

use constant VER_INFO => <<EOF;
get_flash_videos version $VERSION (http://code.google.com/p/get-flash-videos/)
EOF

use constant USAGE => VER_INFO . <<EOF;

Usage: $0 [OPTION]... URL...
       $0 [OPTION]... search string

Downloads videos from the web pages given in URL or searches Google Video
Search for 'search string'. If the URL contains characters such as '&' you
will need to quote it.

Options:
     --add-plugin Add a plugin from a URL.
  -d --debug      Print extra debugging information.
  -f --filename   Filename to save the video as.
  -p --play       Start playing the video once enough has been downloaded.
     --player     Player to use for the video (default: $opt{player}).
     --proxy      Proxy to use, use host:port for SOCKS, or URL for HTTP.
     --subtitles  Download subtitles where available.
  -q --quiet      Be quiet (only print errors).
  -r --quality    Quality to download at (high|medium|low, or site specific).
  -u --update     Update to latest version.
  -v --version    Print version.
  -y --yes        Say yes to any questions (don't prompt for any information).
  -i --info       Print out info about video instead of downloading.

EOF

use constant REQ_INFO => <<EOF;

A required Perl module for downloading this video is not installed.
EOF

use constant FRIENDLY_FAILURE => <<EOF;

Couldn't extract Flash movie URL. This site may need specific support adding,
or fixing.

Please confirm the site is using Flash video and if you have Flash available
check that the URL really works(!).

Check for updates by running: $0 --update

If the latest version does not support this please open a bug (or
contribute a patch!) at http://code.google.com/p/get-flash-videos/
make sure you include the output with --debug enabled.
EOF

read_conf();

GetOptions(
  "yes|y"        => \$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},
  "quality|r=s"  => \$opt{quality},
  "subtitles"    => \$opt{subtitles},
  "info|i"       => \$opt{info},
) or die "Try $0 --help for more information.\n";

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 . " plugin" . (@plugins != 1 && "s") . " installed:";
    debug "- $_" for @plugins;
  } else {
    debug "No plugins installed";
  }
}

if($^O =~ /MSWin/i) {
  $opt{filename} = Encode::decode(get_win_codepage(), $opt{filename});
  binmode STDERR, ":encoding(" . get_win_codepage() . ")";
  binmode STDOUT, ":encoding(" . get_win_codepage() . ")";
} else {
  $opt{filename} = Encode::decode("utf-8", $opt{filename});
  binmode STDERR, '<:encoding(UTF-8)';
  binmode STDOUT, '<:encoding(UTF-8)';
}

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 $columns = get_terminal_width() - 5;
      local $Text::Wrap::columns = $columns;

      my $count = 1;
      for my $result(@results) {
        printf "[%2d] %s\n", $count, $result->{name};

        if ($result->{description}) {
          print wrap("     ", "     ",
                     substr($result->{description}, 0, $columns * 2)), "\n";
        }

        $count++;
      }

      print "Enter the number(s) or range (e.g. 1-3) of the videos to download " .
            "(separate multiple with comma or space): ";
      chomp(my $choice = <STDIN>);
      $choice ||= 1;

      for(split /[ ,]+/, $choice) {
        if (/-/) {
          my ($lower, $upper) = split /-/, $choice;
          if ($upper > $lower and $upper > 0) {
            push @download_urls, map { $results[$_]->{url} } $lower - 1 .. $upper - 1;
            next;
          }
          else {
            print STDERR "Search range '$_' is invalid.\n";
            exit 1;
          }
        }

        $_--;

        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;

my $prefs = FlashVideo::VideoPreferences->new(%opt);

foreach my $url (@download_urls) {
  if (download($url, $prefs, @download_urls - $download_count)) {
    $download_count++;
  }
}

if($download_count == 0) {
  info "Couldn't download any videos.";
  exit 1;
} elsif($download_count != @download_urls) {
  info "Problems downloading some videos.";
  exit 2;
}

exit 0;

sub download {
  my($url, $prefs, $remaining) = @_;

  $url = "http://$url" if $url !~ m!^\w+:!;

  my $browser = FlashVideo::Mechanize->new;

  my($package, $possible_url) = FlashVideo::URLFinder->find_package($url, $browser);

  if($package->can("pre_find")) {
    $package->pre_find($browser);
  }

  info "Downloading $url";
  $browser->get($url);

  if (!$browser->success and !$browser->response->is_redirect) {
    if ($opt{proxy}) {
      if ($browser->response->header('Client-Warning') eq 'Internal response') {
        info "Couldn't download $url - might not be able to contact " .
             "your proxy server ($opt{proxy})";
      }
    }

    error "Couldn't download '$url': " . $browser->response->status_line;
  }

  my($actual_url, @suggested_fnames) = eval {
    $package->find_video($browser, $possible_url, $prefs);
  };

  if(!$actual_url) {
    if($@ =~ /^Must have | requires /) {
      my $error = "$@";
      $error =~ s/at $0.*//;
      print STDERR "$error" . REQ_INFO;
      return 0;
    } else {
      print STDERR "Error: $@" . FRIENDLY_FAILURE;
      return 0;
    }
  }

  my $suggested_filename = $suggested_fnames[-1];
  if (ref($actual_url) eq 'ARRAY') {
      $suggested_filename ||= $actual_url->{flv};
  }

  if (!$opt{play}) {
    if (!$opt{yes} && !$opt{filename} && @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 = <STDIN>);

      $suggested_filename = $suggested_fnames[$chosen_fname - 1] ||
        $suggested_fnames[-1];
    }
  }

  my $save_as = $opt{filename} || $suggested_filename;

  if($opt{info}) {
    if(ref($actual_url) eq 'ARRAY') {
      for my $data(@$actual_url) {
        print "Filename: " . $data->{flv} . "\n";
        $_ = $suggested_filename || $data->{flv};
        s/_/ /g;
        s/\.[^\.]*$//;
        print "Title: " . $_ . "\n";
        print "Content-Location: " . $data->{rtmp} . "\n";
        print "\n";
      }
    } else {
      print "Filename: " . ($save_as || $actual_url->{flv}) . "\n";
      $_ = $suggested_filename || $actual_url->{flv};
      s/_/ /g;
      s/\.[^\.]*$//;
      print "Title: " . $_ . "\n";
      print "Content-Location: ";
      if(ref($actual_url) eq 'HASH') {
        print $actual_url->{rtmp} . "\n";
      } else {
        print $actual_url . "\n";
        $browser->head($actual_url);
        if($browser->response->header('Content-Length')) {
          print "Content-Length: " . $browser->response->header('Content-Length') . "\n";
        }
      }
    }
    exit;
  }

  my $action = $opt{play} ? "play" : "download";

  for my $data((ref($actual_url) eq 'ARRAY' ? @$actual_url : $actual_url)) {
    my $downloader;
    my $file = $save_as;

    if(ref $data eq 'HASH') {
      $downloader = FlashVideo::RTMPDownloader->new;
      $file ||= $data->{flv};
    } else {
      $downloader = FlashVideo::Downloader->new;
    }

    if (ref $data eq 'ARRAY') {
      my ($url, $part_number, $part_count, $part_size) = @$data;
      $data = $url;
      if (defined $part_number && defined $part_count) {
        my $part_suffix = sprintf('.part%02d_of_%02d', $part_number, $part_count);
        substr $file, rindex($file, '.'), 0, $part_suffix
          if $part_count > 1;
      }

      if (defined $part_size && -f $file && -s $file == $part_size) {
        info "Already downloaded $file ($part_size bytes)";
        next;
      }
    }

    my $size = $downloader->$action($data, $file, $browser) || return 0;

    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 {
  my %update_types = (
    'cpan-cpan' => [1, "cpan " . __PACKAGE__],
    'cpan-cpanp' => [1, "cpanp i " . __PACKAGE__],
    'cpan-cpanm' => [1, "cpanm " . __PACKAGE__],
    'cpan-manual' => [0, "Manual install"],
  );

  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 . "\n";
    }

    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";
      debug "(Install type: $::INSTALL_TYPE)";

      if($::INSTALL_TYPE =~ /^cpan-/) {

        my $update_method = $update_types{$::INSTALL_TYPE};
        if($update_method->[0]) {
          info "This was installed via CPAN, you may upgrade by running:";
          info $update_method->[1];

          my $run_cpan = $opt{yes} || do {
            info "Shall I run that for you? (Y/n)";
            <STDIN> =~ /(?:^\s*$|y)/i;
          };

          if($run_cpan) {
            system $update_method->[1];
          }
        } else {
          info "Please visit http://code.google.com/p/get-flash-videos to upgrade";
        }
      } else {
        update_script($browser, $url, $info);
      }
    } else {
      print STDERR "You already have the latest version.\n";
    }
  } else {
    info "Development version, not updated";
  }

  update_plugins();

  return 0; # exit code
}

sub update_script {
  my($browser, $url, $info) = @_;

  info "Downloading new version...";
  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;
  } else {
    die "Download failed: " . $browser->response->status_line;
  }
}

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";
}
}
##} bin/get_flash_videos
