In an attempt to merge
YouTube Video Downloader and my Tk front end to Mplayer at
Perl/Tk front-end to mplayer, here is a YouTube.com sampler. It is not perfect. The categories are hard coded in, and it only gets the first page of each category( maybe 10 videos each)
Also I hacked a quick Listbox widget to display the retreived files. But since I used a thread to download, I needed to update the listbox every 10 seconds manually, which can be annoying if you try to select a file right at update time.
Anyways, it will work on linux (X11) only, and you need an mplayer that can play .flv files.
I creatively named the downloaded files, by concating the titles and flv filename, so you can tell what they are more easily.
Start the app, if any flv files are present in the working dir, they will be listed. Otherwise, press the Select Catagories button, and select 1 or more categories to sample. Then the downloader will get the videos in the background.
#!/usr/bin/perl -w
use strict;
use Tk;
require Tk::Pane;
use Proc::Killfam;
+
use Tk::ROText;
use LWP::UserAgent;
use LWP::Simple;
use HTML::LinkExtor;
use URI::URL;
use threads;
use threads::shared;
# it will work on linux (X11) only, and you need an mplayer
# that can play .flv files.
#I creatively named the downloaded files, by concating the
# titles and flv filename, so you can tell what they are more
# easily.
# Start the app, if any flv files are present in the working dir,
# they will be listed. Otherwise, press the Select Catagories
# button, and select 1 or more categories to sample. Then the # downlo
+ader will get the videos in the background.
# must setup thread code before any Tk code is used
# to avoid Tk thread-safety problems
my $thread_die : shared;
my $thread_go : shared;
my @selected : shared;
my @ready : shared;
$thread_die = 0;
$thread_go = 0;
@selected = ();
@ready = ();
my $thread = threads->new( \&work );
###################################################
+
$|++;
my @links; #a global for Link extractor, funky callback hack
my $ua = LWP::UserAgent->new();
my @selected_cats =();
my @ready_lb; #local non-thread copy of @ready to prevent
#Tk from segfaulting
$SIG{INT} = sub { &close_it_up };
$SIG{PIPE} = 'IGNORE';
my $mpg_in = shift || ''; #mpg to play from command line
# needs an init.mpg which will be created if you
# don't supply one
if( ! -e 'init.mpg'){ &make_init}
#setup local files to play
@ready = <*.flv>;
#newly downloaded files will be pushed onto @ready
#if there are no .flv files in the dir, the first completed
#download will play upon arrival
@ready_lb = @ready;
my $cur_play;
my $title;
my $playing = 0; #flag used in auto-playing first completed download
my $timer;
my $timer1;
my $mw = MainWindow->new(-background =>'black');
$mw->geometry('530x650+20+30');
$mw->Tk::bind("<q>", sub{&close_it_up});
$mw->Tk::bind("<Escape>", sub{&close_it_up});
my $cframe1 = $mw->Frame(-background =>'black')
->pack( -fill =>'x');
my $cframe2 = $mw->Frame(-background =>'black')
->pack( -fill =>'x');
my $canv = $mw->Scrolled('Canvas',
-bg => 'black',
-borderwidth => 0,
-highlightthickness => 0,
-relief => 'sunken',
-width => 500,
-height => 400,
-scrollregion=>[0,0,500,400],
+
-scrollbars=>'osoe',
)->pack();
my $contWidth = 500;
my $contHeight = 400;
## this Frame is needed for including the window in Tk::Canvas
my $Container = $canv->Frame(-container => 1);
my $xtid = $Container->id();
# converting the id from HEX to decimal as xterm requires a decimal Id
my ($xtId) = sprintf hex $xtid;
my $dcontitem = $canv->createWindow(10,10,
-anchor=>'nw',
-window => $Container,
-width => $contWidth,
-height => $contHeight,
-state => 'hidden',
-tags => ['viewport'],
);
my $pid;
my @options = ( '-slave','-loop 0', '-zoom',
"-x $contWidth", "-y $contHeight",
'-really-quiet',
"-wid $xtId",
);
my $loadu_but = $cframe1->Button(-text => 'Select Category',
-padx => 0,
-command => sub{
my $url = &get_url;
})->pack(-side =>'left',-padx=>10 );
$cframe1->Button(-text => "Exit",
-padx => 0,
-command => [sub{&close_it_up}] )
->pack(-side=>'right', -padx =>10 );
$cframe1->Button(-text => "Stop Download",
-padx => 0,
-command => sub{ $thread_go = 0;
$timer1->cancel; #stop updating list
} )
->pack(-side=>'right', -padx =>10 );
my $sound = 1;
+
$cframe1->Checkbutton(
+
-text => 'Sound',
+
-background => 'lightblue',
-variable => \$sound,
+
-command => \&set_sound,
+
)->pack(-fill =>'y' );
+
$cframe2->Label(-text => 'SpaceBar->Pause q or esc -> exit left
+ and right arrow keys navigate',
-background => 'black',
-foreground => 'lightgreen',
)->pack(-expand=>1 );
$cframe2->Label( -textvariable => \$title ,
-background => 'black',
-foreground => 'lightblue',
)->pack(-expand=>1 );
&start_player;
if($mpg_in ne ''){ &play($mpg_in)}
$mw->Label( -text => 'Left Click Select...Right Click Play',
-background => 'black',
-foreground => 'green',
)->pack(-fill => 'x',-expand => 1 );
my $lb = $mw->Scrolled('Listbox',
-scrollbars=>'osow',
-listvariable => \@ready_lb,
-background => 'white',
)->pack(-fill => 'x',-expand=>1);
$lb->bind( '<ButtonPress-3>', sub{
my $file = $lb->get($lb->curselection);
$playing = 1; #set flag that we are playing a local file
&play($file);
});
MainLoop();
#########################################################
sub get_url{
my %cats = (
1 => 'Arts &Animation',
2 => 'Autos & Vehicles',
23 => 'Comedy',
24 => 'Entertainment',
10 => 'Music',
25 => 'News & Blogs',
22 => 'People',
15 => 'Pets & Animals',
26 => 'Science & Technology',
17 => 'Sports',
19 => 'Travel & Places',
20 => 'Video Games'
);
my $url_top = "http://youtube.com/categories_portal"; # for instanc
+e
@links = &get_links( $url_top );
# http://youtube.com/categories_portal?c=1&e=1
my $lead = 'http://youtube.com/categories_portal?c=';
my $rx = qr/\Q$lead\E(.*)/;
@links = grep{/$rx/} @links;
#remove dups
@links = keys %{{map{$_,1} @links}};
my %result_list =();
#sort the links according to category
my $rx1 = qr/\Q$lead\E(\d+).*/;
foreach my $link (@links){
$link =~ /$rx1/;
my $cat = $1;
push @{ $result_list{ $cat } }, $link;
}
my @hyperlinks =();
foreach my $key (keys %result_list){
# print $cats{$key},"\n";
# print join( "\n", @{ $result_list{ $key } } ), "\n\n\n";
push @hyperlinks, "$cats{$key}\n";
foreach( @{ $result_list{ $key } } ){
push @hyperlinks, "$_\n";
}
}
#popup
my $tl = MainWindow->new();
$tl->title("Select YouTube Categories");
$tl->fontCreate('big',
-family=>'arial',
-weight=>'bold',
-size=>int(-18*18/14));
my $t = $tl->Scrolled('ROText',
-width => 80,
-height => 30,
-background => 'white',
)->pack();
my $ebutton = $tl->Button(-text =>'Done Selecting',
-command => sub{
$tl->destroy;
#print "@selected_cats\n";
#now start to process links and download
#videos in the work thread
&start_downloads;
})->pack();
#add colors
$t->tagConfigure( 'tag1', -foreground => 'red', -font => 'big' );
my $tag = "tag000";
foreach (@hyperlinks) {
chomp;
my @res = split (/(http:\S+)/);
foreach (@res) {
if (/(http:\S+)/) {
$t->insert( 'end', $_, $tag );
$t->tagConfigure( $tag, -foreground => 'blue' );
$t->tagBind( $tag,
'<Any-Enter>' => [ \&manipulate_link, $tag, 'raised',
+'hand2' ]
);
$t->tagBind( $tag,
'<Any-Leave>' => [ \&manipulate_link, $tag, 'flat', 'x
+term' ] );
$t->tagBind( $tag,
'<Button-1>' => [ \&manipulate_link, $tag, 'sunken' ]
+);
$t->tagBind( $tag,
'<ButtonRelease-1>' =>
[ \&manipulate_link, $tag, 'raised', undef, \&printm
+e ] );
$tag++;
}
else {
$t->insert( 'end', $_ , 'tag1' );
}
}
$t->insert( 'end', "\n" );
}
}
##############################################
sub get_links{
my $url_in = shift;
# Set up a callback that collect image links
@links = (); # a global
# Make the parser. Unfortunately, we don't know the base yet
# (it might be diffent from $url)
my $p = HTML::LinkExtor->new(\&callback,\@links);
# Request document and parse it as it arrives
my $res = $ua->request( HTTP::Request->new( GET => $url_in ),
sub { $p->parse( $_[0] );
} );
# Expand all URLs to absolute ones
my $base = $res->base;
@links = map { $_ = url( $_, $base )->abs; } @links;
return @links;
}
#################################################
sub callback {
my ( $tag, %attr) = @_;
return if $tag ne 'a';
# we only look closer at <a href ...>
push( @links, values %attr );
}
####################################################
sub printme {
# print "@_\n";
$_[0]->tagConfigure( $_[2], -foreground => 'yellow', -background =
+> 'black' );
push @selected_cats, $_[1];
#now we have an array of urls to fetch and process for all
#video links
#this is done in the 'Done Selecting' callback
}
#######################################################
sub manipulate_link {
# manipulate the link as you press the mouse key
my ($a) = shift;
my ($tag) = shift;
my ($relief) = shift;
my ($cursor) = shift;
my ($after) = shift;
# by configuring the relief (to simulate a button press)
$a->tagConfigure( $tag, -relief => $relief, -borderwidth => 1 );
# by changing the cursor between hand and xterm
$a->configure( -cursor => $cursor ) if ($cursor);
# and by scheduling the specified action to run "soon"
if ($after) {
my ($s) = $a->get( $a->tagRanges($tag) );
$mw->after( 100, [ $after, $a, $s, $tag, @_ ] ) if ($after);
}
}
########################################################
sub get_file{
my @types =( ["mpeg,mp3,avi", [qw/.mpg .mpeg .mp3 .avi .flv/]],);
my $file = $mw->getOpenFile( -filetypes => \@types );
return $file;
}
###########################################################
sub set_sound{
&stop;
if($sound == 1 ){ @options = grep{ $_ ne '-nosound'} @options;}
else{ unshift @options, '-nosound';}
&start_player;
&play($cur_play);
}
##############################################################
sub start_player{
$pid = open(MP, "| mplayer @options init.mpg >/dev/null 2>&1 ");
$canv->itemconfigure($dcontitem,-state => 'normal');
}
##############################################################
sub play {
my $mpg = shift || 'init.mpg';
syswrite(MP, "loadfile $mpg\n");
$cur_play = $mpg;
my $filename = substr ($mpg, rindex ($mpg, "/") + 1);
$mw->configure(-title=>$filename);
$title = $filename;
}
###################################################################
sub stop{
syswrite(MP, "quit\n");
$canv->itemconfigure($dcontitem,-state => 'hidden');
killfam 9, $pid;
close MP;
}
#################################################################
sub close_it_up{
&stop;
$thread_die = 1;
$thread->join;
exit;
}
######################################################################
+########
sub start_downloads{
foreach my $page( @selected_cats ){
my @links1 = &get_links( $page );
# "http://youtube.com/watch?v=EkTpUxh8Vxc";
my $lead = 'http://youtube.com/watch?v=';
my $rx = qr/\Q$lead\E(.*)/;
@links1 = grep{/$rx/} @links1;
#remove dups
@links1 = keys %{{map{$_,1} @links1}};
#print "@links1\n";
foreach(@links1){ push @selected , $_ }
}
#print join "\n", @selected,"\n";
#start downloading thread if needed
if( scalar @selected > 0 ){
$thread_go = 1;
# timer to autoplay first download
$timer = $mw->repeat(500, sub{
if( scalar @ready > 0 ){
if( ! $playing ){ &play( $ready[0] ) };
$timer->cancel;
}
});
#update download list (hack for tk thread safety)
#use 10 seconds to allow time to make selections
#definitely a hack :-)
$timer1 =
$mw->repeat(10000, sub{
@ready_lb = @ready;
$lb->update;
});
}
}
#############################################################
sub work{
no warnings "all"; #stops a harmless shared var warning
my $received_size;
my $request_time;
my $last_update;
my $ua = LWP::UserAgent->new();
$|++;
while(1){
if($thread_die == 1){ goto END };
if ( $thread_go == 1 ){
print "starting next page retrieval\n";
my $urlin = shift @selected;
my $content = get( $urlin ) or die "$!\n";
print "done page retrieval\n";
#get human friendly title for video
$content =~ /<title>(.*)<\/title>/;
my $title = $1;
#put underscores for spaces in title
$title =~ tr/ /_/;
# regex for 2 key text strings which identify the video file
# the second one $2 is unique for each download attempt
$content =~ /player2\.swf\?video_id=([^&]+)&.*t=([^&]+)&/ ;
print $1, "\n" , $2, "\n";
#make add title to filename for ease of identification
my $infile = $title.'--'.$1.'.flv'; #add a .flv extension
#http://www.youtube.com/get_video?video_id=p_YMigZmUuk&t=OEgsToPD
+skLRl9-iKyfQVcNT8xes2OIT
my $get_url = 'http://www.youtube.com/get_video?video_id='.$1.'&t
+='.$2;
print "gettin video file $get_url\n";
# don't buffer the prints to make the status update
$| = 1;
open(IN,"> $infile") or die "$_\n";
$received_size = 0;
my $url = $get_url;
print "Fetching $url\n";
$request_time = time;
$last_update = 0;
my $response = $ua->get($url,
':content_cb' => \&callback_t,
':read_size_hint' => 8192,
);
print "\n";
close IN;
print "$infile done\n";
push @ready, $infile;
}else
{ select(undef,undef,undef,.1); } #sleep .1 second
} #end while loop
sub callback_t {
my ($data, $response, $protocol) = @_;
my $total_size = $response->header('Content-Length') || 0;
$received_size += length $data;
# write the $data to a filehandle or whatever should happen
# with it here.
print IN $data;
my $time_now = time;
if($thread_go == 0){last}
if($thread_die == 1){ goto END };
# this to make the status only update once per second.
return unless $time_now > $last_update or $received_size == $total_
+size;
$last_update = $time_now;
print "\rReceived $received_size bytes";
printf " (%i%%)", (100/$total_size)*$received_size if $total_size;
printf " %6.1f/bps", $received_size/(($time_now-$request_time)||1)
if $received_size;
}
END:
}
###################################################################
sub make_init{
use MIME::Base64;
+
my $init_mpg ='
UklGRvYUAABBVkkgTElTVOgRAABoZHJsYXZpaDgAAABAQg8AfJIAAAAAAAAQCQAAAwAAAA
+AAAAAB
AAAAAAAQAMAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAExJU1SQEAAAc3RybHN0cmg4AAAAdm
+lkc0RJ
VlgAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAAAAAQAP////8ARAEAAAAAAMAAkABzdH
+JmKAAA
ACgAAADAAAAAkAAAAAEAGABESVZYAEQBAAAAAAAAAAAAAAAAAAAAAABKVU5LFBAAAAQAAA
+AAAAAA
MDBkYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAEpVTksEAQAAb2RtbGRtbGj4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMSVNUwgIAAG
+1vdmkw
MGRjbAEAAAAAAbABAAABtYkTAAABAAAAASAAxI2IAA0GBBIUYwAAAbJGRm1wZWcwLjQuOG
+I0Njgw
AH8AAAGzABAHAAABthYPGC/bfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfx
+tt/G23
8bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbf
+xtt/G2
38bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bb
+fxtt/G
238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238b
+bfxtt/
G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238bbfxtt/G238
+bbfxtt
/G238bbfxtt/G238bbfxtt/G238bbfxtt/G2378wMGRjIwEAAAAAAbZrgRC+5wX3OC+5wX
+3OC+5w
X3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5w
+X3OC+5
wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5
+wX3OC+
5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+
+5wX3OC
+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC
++5wX3O
C+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OC+5wX3OfwAwMGRjFQAAAA
+AAAbZr
AR//////////////////fwBpZHgxMAAAADAwZGMQAAAABAAAAGwBAAAwMGRjAAAAAHgBAA
+AjAQAA
MDBkYwAAAACkAgAAFQAAAA==';
open(FH,"> init.mpg") or die "$!\n";
print FH decode_base64($init_mpg);
close FH;
}