Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

YouTube Video Downloader

by zentara (Archbishop)
on Aug 30, 2006 at 20:10 UTC ( #570467=snippet: print w/replies, xml ) Need Help??
Description: Shamelessly converted to perl from the python script youtube.dl

It downloads the front page, extracts the necessary strings, then gets the flash video file ( .flv ) which is then opened in mplayer. The large video download has a progress callback.

#!/usr/bin/perl
use warnings;
use LWP::Simple;
use LWP::UserAgent;

# shamelessly reversed engineered from a python script :-) 

print "startring first page retrieval\n";
my $urlin  = shift || "http://youtube.com/watch?v=EkTpUxh8Vxc";
my $content = get( $urlin  ) or die "$!\n"; 
print "done first page retrieval\n";
#print $content;

# 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";  
my $infile = $1.'.flv';  #add a .flv extension

#http://www.youtube.com/get_video?video_id=p_YMigZmUuk&t=OEgsToPDskLRl
+9-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"; 

my $ua = LWP::UserAgent->new();
my $received_size = 0;
my $url = $get_url;
print "Fetching $url\n";
my $request_time = time;
my $last_update = 0;
my $response = $ua->get($url,
                        ':content_cb'     => \&callback,
                        ':read_size_hint' => 8192,
                       );
print "\n";
close IN;

#play the flv file with mplayer
system( "mplayer $infile" );

#############################################

sub callback {
  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;

  # this to make the status only update once per second.
  return unless $time_now > $last_update or $received_size == $total_s
+ize;
  $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__

Replies are listed 'Best First'.
Re: YouTube Video Downloader
by BigJoe (Curate) on Aug 31, 2006 at 12:51 UTC
    After you download it, you should convert it to mpeg. I have a script somewhere that does this. I think it uses mencoder. Then you can use pretty much any player.


    --BigJoe

    Learn patience, you must.
    Young PerlMonk, craves Not these things.
    Use the source Luke.

      OS X people may be interested in ffmpegX (shareware) which is a drag-n-drop app that sits on top of things like mencoder and can convert between several different video file formats. Of course VLC on OS X seems to be able to open FLV files fine, so that might be a possibility as well (system( "open -a /Applications/VLC.app $infile" );).

      And I had to ++ the OP just for the choice of default URLs it pulls down. :)

      Please post your flv to mpg converter, sounds like a good idea.

      I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      is anyone using this script on windows? I am trying to run it with camel pack on win XP. download is fine , size also looks fine but the .flv would not play in VLC player.
        oops forgot to binmode the file on windows !!
Re: YouTube Video Downloader
by wazoox (Prior) on Sep 03, 2007 at 19:53 UTC
    Youtube changed its page layout recently, so none of the common tools (this script, but also clive and the Firefox VideoDownloader extension) works anymore. So I quickly modified this script to make it work again. Here it is :
    #!/usr/bin/perl use strict; use warnings; use LWP::Simple; use LWP::UserAgent; # shamelessly reversed engineered from a python script :-) print "starting first page retrieval\n"; my $urlin = shift || "http://youtube.com/watch?v=NeiLBET8Cdk"; my $content = get( $urlin ) or die "argh : $!\n"; print "done first page retrieval : $urlin\n"; # print "$content" ; # 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=([^&]+)&/ ; $content =~ /<title>(.*)<\/title>/ ; my $infile = $1.'.flv' ; $content =~ /watch_fullscreen\?video_id=([^&]+)&.*t=([^&]+)&/ ; print $1, "\n" , $2, "\n"; #http://www.youtube.com/get_video?video_id=p_YMigZmUuk&t=OEgsToPDskLRl +9-iKyfQVcNT8xes2OIT my $get_url = 'http://www.youtube.com/get_video?video_id='.$1.'&t='.$2 +; print "gettin video file : $infile\n"; # don't buffer the prints to make the status update $| = 1; open(IN,"> $infile") or die "$_\n"; my $ua = LWP::UserAgent->new(); my $received_size = 0; my $url = $get_url; print "Fetching $url\n"; my $request_time = time; my $last_update = 0; my $response = $ua->get($url, ':content_cb' => \&callback, ':read_size_hint' => 8192, ); print "\n"; close IN; #play the flv file with mplayer # system( "mplayer $infile" ); ############################################# sub callback { 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; # this to make the status only update once per second. return unless $time_now > $last_update or $received_size == $total_s +ize; $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__
    Enjoy!
      Thanks for pointing that out, it worked here. I did notice that YouTube started changing it's downloads a few months ago. At the time, it looked to me like they were trying to work out a system of regional servers to improve efficiency, and there was some extra codes in there. I figured that ultimately I would need to switch to WWW:Mechanize, and decided it wasn't worth the effort..... since the novelty of YouTube has worn off for me, and they might change it all again at some future time. :-)

      I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      Well the times they keep a changin' ...
      #!/usr/bin/perl use strict; use warnings; use LWP::Simple; use LWP::UserAgent; # shamelessly reversed engineered from a python script :-) print "starting first page retrieval\n"; my $urlin = shift || "http://youtube.com/watch?v=vCsQLQ00hvs"; my $content = get( $urlin ) or die "argh : $!\n"; print "done first page retrieval : $urlin\n"; # print "$content" ; # 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=([^&]+)&/ ; my $infile = ($content =~ m{<title>([^<]+)</title>})[0] . '.flv'; my ($video_id) = ($content =~ /watch_fullscreen\?(?:.*?)video_id=([^&] ++)/); my ($t_id) = ($content =~ /watch_fullscreen\?(?:.*?)t=([^&]+)/); my $get_url = "http://www.youtube.com/get_video?video_id=$video_id&t=$ +t_id"; print "gettin video file : $infile\n"; # don't buffer the prints to make the status update $| = 1; open(IN,"> $infile") or die "$_\n"; my $ua = LWP::UserAgent->new(); my $received_size = 0; my $url = $get_url; print "Fetching $url\n"; my $request_time = time; my $last_update = 0; my $response = $ua->get($url, ':content_cb' => \&callback, ':read_size_hint' => 8192, ); print "\n"; close IN; #play the flv file with mplayer # system( "mplayer $infile" ); ############################################# sub callback { 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; # this to make the status only update once per second. return unless $time_now > $last_update or $received_size == $total_s +ize; $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__
      Works like a charm again! :)
        thanks for the update !
      missing binmode again
Re: YouTube Video Downloader
by zentara (Archbishop) on Aug 31, 2006 at 18:54 UTC
    After fiddling a bit, here is a shell script using mencoder, that takes an .flv file and converts it to avi, (with mpg compression)
    #/bin/sh # output plays with ffplay or latest mplayer-1.0pre8 # takes an .flv file as arg1 and produces a basename.avi mencoder $1 -vc ffflv -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=1000:v +hq -ofps 24 -oac mp3lame -lameopts cbr:br=96 -o `basename $1 .flv`.av +i

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: YouTube Video Downloader
by BigJoe (Curate) on Sep 01, 2006 at 03:28 UTC
    I reposted your code because I needed to pass on the file name to the ffmpeg program. BTW this require ffmpeg. I pulled this from a Ubuntu blog (http://www.jadmadi.net/2006/06/22/ubuntu-howto-converting-flv-to-mpg/)

    I had just setup a shell script for this and I would just run it on all the files in the directory but this seems a little easier.
    #!/usr/bin/perl use warnings; use LWP::Simple; use LWP::UserAgent; # shamelessly reversed engineered from a python script :-) print "startring first page retrieval\n"; my $urlin = shift || "http://youtube.com/watch?v=EkTpUxh8Vxc"; my $content = get( $urlin ) or die "$!\n"; print "done first page retrieval\n"; #print $content; # 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"; my $infile = $1.'.flv'; #add a .flv extension my $filename = $1; #http://www.youtube.com/get_video?video_id=p_YMigZmUuk&t=OEgsToPDskLRl +9-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"; my $ua = LWP::UserAgent->new(); my $received_size = 0; my $url = $get_url; print "Fetching $url\n"; my $request_time = time; my $last_update = 0; my $response = $ua->get($url, ':content_cb' => \&callback, ':read_size_hint' => 8192, ); print "\n"; close IN; #play the flv file with mplayer #system( "mplayer $infile" ); my $return_val = `ffmpeg -i $filename.flv -ab 56 -ar 22050 -b 500 -s +320x240 $filename.mpg`; ############################################# sub callback { 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; # this to make the status only update once per second. return unless $time_now > $last_update or $received_size == $total_s +ize; $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__


    --BigJoe

    Learn patience, you must.
    Young PerlMonk, craves Not these things.
    Use the source Luke.
Re: YouTube Video Downloader
by zentara (Archbishop) on Sep 01, 2006 at 15:14 UTC
    I just modified Perl/Tk front-end to mplayer to use .flv files in it's playlist. So it would not take much work at all, to setup this downloader script, to download all the video links on a YouTube page, then "quickly browse thru them at your leisure". I will probably post a version later.

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: YouTube Video Downloader
by jZed (Prior) on May 06, 2007 at 17:22 UTC
    A thing that could be combined with this script that I find very useful is "mplayer -dumpaudio $file" which creates an .mp3 file - extracts the audio portion of the .flv for those music videos where you just want the music.
      Hi, that sounds good, mplayer is so powerful. I have noticed that You-Tube is getting more sophisticated in setting up their links, to different servers (maybe due to heavy loads from popularity?). It seems to be getting harder to screen scrape their pages to get reliable links. Maybe I'm just too lazy to try harder. :-)

      I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: YouTube Video Downloader
by Anonymous Monk on May 04, 2008 at 13:28 UTC
    is code changed. and very good. My Code.
    #!/usr/bin/perl use strict; use warnings; use LWP::Simple; use LWP::UserAgent; use CGI qw(:standard); print "Content-type:text/html\n\n"; my $query = new CGI; print qq~ <html> <head> <style> div{ position:absolute; } </style> </head> <body> <form name="aa" action="" method="get"> <INPUT TYPE="hidden" name="islem" value="1"> <textarea name="url" cols="25" rows="6" OnFocus="this.value=''"> Lütfen Youtube Linkini buraya yapıştırınız. </textarea> <INPUT TYPE="submit" name="submit" value="İndir"> </form> ~; my $myurl = $query -> param('url'); my $islem = $query -> param('islem'); if ($islem eq "1") { # shamelessly reversed engineered from a python script :-) #print "starting first page retrieval\n"; my $urlin = shift || $myurl; ###"http://www.youtube.com/watch?v=0Q3Uv +6_jXzg"; my $content = get( $urlin ) or die "argh : $!\n"; #print "done first page retrieval : $urlin\n"; # print "$content" ; # 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=([^&]+)&/ ; my $infile = ($content =~ m{<title>([^<]+)</title>})[0] . '.flv'; my ($video_id) = ($content =~ /watch_fullscreen\?(?:.*?)video_id=([^&] +++)/); my ($t_id) = ($content =~ /watch_fullscreen\?(?:.*?)t=([^&]+)/); $infile =~ s/YouTube/Seyret/isg; $infile =~ s/[\*]//isg; $infile = normalize_filename($infile,'-', 40); my $kaydet="flv/".$infile; my $get_url = "http://www.youtube.com/get_video?video_id=$video_id&t=$ +t_id"; #print "gettin video file : $infile\n"; print qq~ <B>Dosya Adı :</B> $infile<br> <B>Tamamlama Yüzdesi :</B> <div id=yuzde></div><br> <B>Hız :</B> <div id=hiz></div><br> <B>Alınan :</B> <div id=alma></div><br> ~; # don't buffer the prints to make the status update $| = 1; open(IN,"> $kaydet") or die "$_\n"; my $ua = LWP::UserAgent->new(); my $received_size = 0; my $url = $get_url; #print "Fetching $url\n"; my $request_time = time; my $last_update = 0; my $response = $ua->get($url, ':content_cb' => \&callback, ':read_size_hint' => 8192, ); print "\n"; close IN; print "\nBitti</body></html>"; #play the flv file with mplayer # system( "mplayer $infile" ); ############################################# sub callback { 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; # this to make the status only update once per second. return unless $time_now > $last_update or $received_size == $total_s +ize; $last_update = $time_now; #print "\rReceived $received_size bytes\n\n"; #printf " (%i%%)", (100/$total_size)*$received_size if $total_size; printf "<script>document.all.yuzde.innerHTML='(%i%%)';</script>",(100/ +$total_size)*$received_size if $total_size; printf "<script>document.all.hiz.innerHTML='%6.1f - KB';</script>", ($ +received_size*8)/1024/(($time_now-$request_time)||1) if $received_si +ze; printf "<script>document.all.alma.innerHTML='%i-KB / %i KB';</script>" +, ($received_size/1024),($total_size)/1024 if $total_size; } sub random_string{ my $length_of_randomstring = shift; my @chars=('a'..'z','A'..'Z','0'..'9'); my $random_string; for(my $i = 0; $i < $length_of_randomstring; $i++){ $random_string + .= $chars[int(rand(58))]; } return $random_string; } sub normalize_filename{ my $file_name = shift; my $delimiter = shift; my $max_file_length = shift; if(length($file_name) > $max_file_length){ $file_name = substr($fi +le_name, length($file_name) - $max_file_length); } $file_name =~ s/[^a-zA-Z0-9\_\.\-]/$delimiter/g; return $file_name; } }
Re: YouTube Video Downloader
by Anonymous Monk on May 06, 2010 at 05:44 UTC
    Try this http://pastebin.com/tWSAz8sQ
      Thanks for the link :)
Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: snippet [id://570467]
help
Chatterbox?
and John Coltrane plays...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2018-04-24 17:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?