ニコニコ動画ダウンローダ with Irvine
Irvine を使ってニコニコ動画の flv をダウンロードする Perl スクリプト。こんな感じに使う。
perl NicoVideoDownloader.pm -c cookies.txt <ニコニコ動画のURL>
Cookie は Firefox なんかの Mozilla 系の Cookie を持って来る(プロファイルフォルダ以下の cookies.tx を使う)。
ぶっちゃけ、これのパクリ + α です。
本当は Python でやろうと思ったんだけど、Cookie を使った認証でうまくいかなかったので、Perl でゴリゴリ。
package NicoVideoDownloader; use base qw(Class::Accessor); __PACKAGE__->mk_accessors(qw(ua irvine)); use strict; use warnings; use utf8; use Encode; use Getopt::Long; use Win32::OLE; use LWP::UserAgent; use HTTP::Cookies::Mozilla; use HTML::HeadParser; use URI::Escape; sub new { my $class = shift; my $irvine = Win32::OLE->GetActiveObject('Irvine.Api') || Win32::OLE->new('Irvine.Api'); my $ua = LWP::UserAgent->new; my $self = { irvine => $irvine, cookie_file => 'cookies.txt', ua => $ua, }; return bless $self, $class; }; sub register_download { my ($self, $parent, $folder, $url) = @_; my $response = $self->ua->request( HTTP::Request->new('GET', $url)); my $headers = $response->headers; my $content = Encode::decode('utf8', $response->content); my $parser = HTML::HeadParser->new($headers); $parser->parse($content); my $title = $headers->title; $title =~ s/[^\|]+ \| //; my $flv_id; if ($url =~ m{watch/(.*)$}) { $flv_id = $1; } else { die; } my $getflv_url = "http://www.nicovideo.jp/getflv?v=$flv_id"; my $query_string = $self->ua->simple_request( HTTP::Request->new('GET', $getflv_url))->content; my %params = map { map { uri_unescape($_) } split /=/, $_, 2 } split /\&/, $query_string; ### %params my $download_url = $params{url}; my $filename = sprintf '%s_%s.flv', $title, $flv_id; my $item = join("\t", ($download_url, $folder, $filename)); $self->irvine->AddQueueItem($parent, Encode::encode('cp932', $item)); } sub main { my $cookie_file = 'cookies.txt'; my $parent = '/Default'; my $folder = ''; my $result = GetOptions( 'cookie=s' => \$cookie_file, 'parent=s' => \$parent, 'folder=s' => \$folder); if ($parent !~ m{\A / }x) { $parent = '/' . $parent; } my $cj = HTTP::Cookies::Mozilla->new; $cj->load($cookie_file) or die; my $downloader = NicoVideoDownloader->new; $downloader->ua->cookie_jar($cj); my @urls = @ARGV; for my $url (@urls) { $downloader->register_download($parent, $folder, $url); } } if ($0 eq __FILE__) { binmode STDOUT, ':encoding(cp932)'; main; } 1;
あと、wxPerl を使った適当なフロントエンドとか。URL をクリップボードから読み取り、ダイアログでフォルダ名を入力。
#!/usr/bin/env perl use strict; use warnings; use Encode; use Wx; use LWP::UserAgent; use HTTP::Cookies::Mozilla; use Win32::Clipboard; use Win32::OLE; use NicoVideoDownloader; binmode STDOUT, ':encoding(cp932)'; my $clip = Win32::Clipboard(); my $parent = '/Default'; my $cookie = 'cookies.txt'; my $cookie_jar = HTTP::Cookies::Mozilla->new; $cookie_jar->load($cookie) or die; my $folder = Wx::GetTextFromUser('folder name', 'folder name'); my $downloader = NicoVideoDownloader->new; $downloader->ua->cookie_jar($cookie_jar); my $text = $clip->Get(); my @urls = split /\r?\n/, $text; for my $url (@urls) { return if $url =~ /\A \s* \Z/x; $downloader->register_download($parent, $folder, $url); }