YouTube から動画をダウンロードする


スポンサーリンク

アップロードするにあたって、ダウンロードするスクリプトも欲しくなるわけだ。
探してみた。とりあえず、php のソース。
php が読めれば、perl が読める。perl が読めれば、php が読める
ま、最悪 perl から呼び出して使うって手もあるしね。こういうものは見つけたときの保存しておく。
そのためにこのサイトを立ち上げたのだ。なんてなw
 
<?php
// 動画のURL
$url = "http://www.youtube.com/watch?v=NGQrE3fM8w8";
 
// 拡張子のリスト
$extension = array("5" => ".flv", "18" => ".mp4", "22" => ".mp4", "34" => ".flv", "35" => ".flv", "37" => ".mp4", "38" => ".mp4");
 
// HTMLファイルの取得
$html = file_get_contents($url);
 
// HTMLからタイトルを獲得する
preg_match("/<meta name=\"title\" content=\"([^\"]*)\">/s", $html, $matches);
$title = $matches[1];
 
// 動画URLの取得
preg_match("/url_encoded_fmt_stream_map=([^\"]*)/i", $html, $matches);
$dataset = explode("%2C", $matches[1]);
for ($i = 0; $i < count($dataset); $i++) {
    preg_match("/^url%3D(.*)/i", $dataset[$i], $matches);
    if (count($matches) != 0) {
        $flvs = explode("&quality=", urldecode(urldecode($matches[1])));
        preg_match("/&itag=(\d*)/i", $flvs[0], $itags);
 
        $video_url = $flvs[0];
        $itag = $itags[1];
 
        // 動画をDL
        if (isset($extension[$itag])) {
            echo "title : $title\n";
            echo "itag  : $itag\n";
            echo "start  download.\n";
             
            $fp = fopen(mb_convert_encoding($title,"sjis","auto")."_fmt" . $itag . $extension[$itag], "wb");
            $handle = fopen($video_url, "rb");
            while (!feof($handle)) fwrite($fp, fread($handle, 8192));
            echo "finish download.\n\n";
        }
    }
}
?>
 
技術情報として参考になりそうなサイト。
perl-users.jp/articles/advent-calendar/2010/hacker/23

パールも見つけたけど、syntaxhirightがうまく動いてないみたいで、一応コピーしてきたけどうまくはれるかな?
解説は、ごたぶんに漏れず上から目線でわけわかめ。「実に興味深いコードだ」だって、しらねーよ!ってな?ww
要するにユーチューブのcpanがありそうだってことだな。よしよし行けそうだw
almajiro.net/youtube-channel-save
 
use WWW::YouTube::Download::Channel;
my $yt = WWW::YouTube::Download::Channel->new();

$yt->target_directory(‘/youtuve/thiers48′); #OPTIONAL. default is current dir
$yt->apply_regex_filter(’24 horas|24H’); #OPTIONAL apply regex filters by title..
$yt->apply_regex_skip( ‘skip|this|title’ ); #OPTIONAL skip some titles
$yt->newer_than( { #OPTIONAL filter videos by dates
day => 1, month => 12, year => 2000 } );
$yt->leech_channel(‘thiers48′); #REQ
$yt->download_all; #REQ find and download youtube videos
 
こっちの方がわかりやすそうだ。
blog.livedoor.jp/xaicron/archives/50764987.html
#!C:/Perl/bin/perl
# Youtubeから最高画質の動画をダウンロードする
# fmt35とかもいける

use strict;
use warnings;
use utf8;
use Encode;
use LWP::UserAgent;
use File::Basename;
use Web::Scraper;
use URI;
use JSON qw/decode_json/;

# ファイル名のエンコード
my $enc = 'cp932';

# 引数
my $url = shift || die "Usage: $0 youtube_rul";

# スクレイピング
my $uri = URI->new($url);
my $scraper = scraper {
    process '/html/head/script[5]', script => 'html',
    process '/html/body/div/div[3]/h1', title => 'TEXT',
};
my $result = $scraper->scrape($uri);

# JSON取得
my $json;
for my $line (split /\n/, $result->{script}) {
    if ($line =~ /^\s*var\s*swfArgs\s*=\s*({.*});/) {
        $json = HTML::Entities::decode_entities($1);
        last;
    }
}
my $swfArgs = decode_json $json;

# 最高画質のfmt取得
my $fmt;
for my $map (split /,/, $swfArgs->{fmt_map}) {
    next if $map =~ m|^(\d+)/(\d+)| and $2 eq '0'; # 2つ目の数値が0だったら存在しないっぽい?
    $fmt = "&fmt=$1";
    last;
}

# 定義がなかったらfmt=18とする
$fmt = '&fmt=18' unless $fmt;

# ファイルの拡張子
my $suffix = $fmt =~ /(18|22)/ ? '.mp4' : '.flv';

# ダウンロードURL
my $video_url = sprintf "http://www.youtube.com/get_video?video_id=%s&t=%s%s", $swfArgs->{video_id}, $swfArgs->{t}, $fmt;

# 保存するファイル名
my $filename = encode $enc, $result->{title} . $suffix;

# ファイルがあったら終了
die "File exists ($filename)" if -f $filename;

# 進捗表示しつつダウンロード
open my $wfh, '>', $filename or die "$filename: $!";
binmode $wfh;

print "$video_url\n";
print "Downloading -> $filename\n";

my $res = LWP::UserAgent->new->get(
    $video_url,
    ':content_cb' => sub {
        my ( $chunk, $res, $proto ) = @_;
        print $wfh $chunk;
        my $size = tell $wfh;
        if (my $total = $res->header('Content-Length')) {
            printf "%d/%d (%f%%)\r", $size, $total, $size/$total * 100;
        }
        else {
            printf "%d/Unknown bytes\r", $size;
        }
    },
);
close $wfh;

# 後処理
print "\n", $res->status_line, "\n";
unlink $filename unless $res->is_success;

exit 1;

スポンサーリンク