sábado, 17 de septiembre de 2011

YouTube Downloader: Descarga Videos de YouTube

Yap, por fin salió!

Este script sirve para descargar videos de YouTube por CLI ;)

Lo único que tienen que hacer es ejecutar el script y pasarle como argumento el ID del video, luego el script preguntará el formato y resolución y... listo!

Enjoy!

#!/usr/bin/perl
use strict;
use HTTP::Lite;
use Data::Dumper;

#####################################################
#
# Desarrollado por: Zort
# Fecha: 16 de Septiembre de 2011
#
# Descripcion:
#   Este script descarga un video de YouTube especificado por
# el ID, el cual es entregado como parametro en la ejecucion.
#   A su vez, es posible elegir el formato y la resolucion
# del video segun la disponibilidad de YouTube de entregar el
# video con dichas caracteristicas.
#
# Anexo:
#   Se omitieron todos los acentos en el codigo, para que no se
# vean caracteres erroneos en el caso de que el equipo donde
# se corra este codigo permita ver solo caracteres gringos.
#   Se ha detectado que en ciertas ocasiones no se descarga
# el video. En estos casos se debe intentar nuevamente.
#
#####################################################

my $debug = 0;
my $video_id = $ARGV[0];

die "Usage: $0 video_id\n\n" if ($video_id eq '');

my $http = HTTP::Lite->new;
$http->http11_mode(1);

my $req = $http->request("http://www.youtube.com/get_video_info?video_id=$video_id&eurl=http%3A%2F%2Flocalhost%2F&hl=en_US")
    or die "Unable to get document: $!";

&showResponse($http) if ($debug);

if ($http->status() != 200) {
    print "The return code is not valid!\n";
    exit;
}

my $seconds        = 0;
my $fmt_stream_map = '';
my $fmt_list       = '';
my $title          = '';
my $token          = '';
my $formats        = ();

my @infos = split(/&/, $http->body());
foreach my $info (@infos) {

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

    $seconds        = $value            if ($name eq 'length_seconds');
    $fmt_stream_map = urlDecode($value) if ($name eq 'url_encoded_fmt_stream_map');
    $fmt_list       = urlDecode($value) if ($name eq 'fmt_list');
    $title          = urlDecode($value) if ($name eq 'title');
    $token          = $value            if ($name eq 'token');
}

my @formats_list = split(/,/, $fmt_list);
foreach my $format_list (@formats_list) {

    $format_list =~ /^([^\/]+)\/([^\/]+)\//;
    $formats->{$1}->{'resolution'} = $2;
}

my @formats_map = split(/,/, $fmt_stream_map);
foreach my $format_map (@formats_map) {

    my $url           = '';
    my $quality       = '';
    my $fallback_host = '';
    my $type          = '';
    my $itag          = '';

    my @variables = split(/&/, $format_map);
    foreach my $variable (@variables) {

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

        $url           = urlDecode($value) if ($name eq 'url');
        $quality       = urlDecode($value) if ($name eq 'quality');
        $fallback_host = urlDecode($value) if ($name eq 'fallback_host');
        $type          = urlDecode($value) if ($name eq 'type');
        $itag          = $value            if ($name eq 'itag');
    }

    $formats->{$itag}->{'url'}           = $url;
    $formats->{$itag}->{'quality'}       = $quality;
    $formats->{$itag}->{'fallback_host'} = $fallback_host;
    $formats->{$itag}->{'type'}          = $type;
}

print "Titulo: $title\n";
print "Formatos:\n";
foreach my $format (sort { $formats->{$a}->{'type'} cmp $formats->{$b}->{'type'} } keys %{$formats}) {
    print " - (" . sprintf("%2d", $format) . ") " . $formats->{$format}->{'type'} . " (" . $formats->{$format}->{'quality'} . ") [" . $formats->{$format}->{'resolution'} . "]\n";
}
print "Opcion: ";
my $option = <STDIN>;
chomp($option);
print "Descargando numero $option...\n";
$http->reset();
$req = $http->request($formats->{$option}->{'url'});

my $output = $title;
$output .= '.mp4' if ($formats->{$option}->{'type'} =~ /video\/mp4/);
$output .= '.flv' if ($formats->{$option}->{'type'} =~ /video\/x-flv/);
$output .= '.webm' if ($formats->{$option}->{'type'} =~ /video\/webm/);

open(FH, '>', $output);
binmode(FH);
print FH $http->body();
close(FH);
print "Done!\n";
print "Archivo: '$output'\n";

   


#################
##  FUNCTIONS  ##
#################

sub showResponse() {

    my $http = shift;

    my $status     = $http->status();
    my $status_msg = $http->status_message();
    my @headers    = $http->headers_array();

    $status_msg =~ s/[\n\r]//g;

    print "Return Code:\n";
    print "    $status ($status_msg)\n";
    print "Headers:\n";
    foreach my $header (@headers) {
        print "    $header\n";
    }
    print "---------------------------\n";

    return 0;
}

sub urlDecode() {

    $_ = shift;

    s/\+/ /g;
    s/\%([0-9A-F]{2})/@{[chr hex $1]}/g;

    return $_;
}

No hay comentarios: