非公式なニコニコ動画のAPIの制限を加味して、linkがニコニコ動画のビデオページ(http://www.nicovideo.jp/watch/sm000000形式)のエントリーだった場合に、動画のFLVとコメントのXMLをダウンロードできるPlaggerのPluginを作った。 制限のあるニコニコ動画向けに、Filter::FindEnclosuresとFilter::FechEnclosureをあわせたようなもの。 外部クッキーを使ってユーザー名とパスワードを書かなくてよくすることもできるが、とりあえず、必須にした。あとコメント数をオプションで設定するようにしたい。今は500件。 詳しい使い方は→ゆーすけべー日記: Plaggerでニコニコ動画のFLVとコメントを一括ダウンロード!。
package Plagger::Plugin::Filter::FetchNicoVideo;
use strict;
use base qw( Plagger::Plugin );
our $VERSION = 0.01;
use URI::Escape;
use File::Spec;
use HTTP::Request;
use Plagger::Enclosure;
use Plagger::UserAgent;
sub register {
my($self, $context) = @_;
$context->register_hook(
$self,
'update.entry.fixup' => \&filter,
);
my $ua = Plagger::UserAgent->new;
$ua->cookie_jar( $self->cookie_jar );
$self->{ua} = $ua;
$self->login();
}
sub init{
my $self = shift;
$self->SUPER::init(@_);
defined $self->conf->{mail} or Plagger->context->error("conifg 'mail' is not set.");
defined $self->conf->{password} or Plagger->context->error("config 'password' is not set.");
defined $self->conf->{dir} or Plagger->context->error("config 'dir' is not set.");
if ($self->conf->{dir} =~ /^[a-zA-Z]/ && $self->conf->{dir} !~ /:/) {
$self->conf->{dir} = File::Spec->catfile( Cwd::cwd, $self->conf->{dir} );
}
unless (-e $self->conf->{dir} && -d _) {
Plagger->context->log(warn => $self->conf->{dir} . " does not exist. Creating");
mkpath $self->conf->{dir};
}
}
sub filter {
my($self, $context, $args) = @_;
my $ua = $self->{ua};
my $entry = $args->{entry};
#get video_id
my $video_id;
$_ = $entry->link;
return unless (m!www.nicovideo.jp/watch/(.*)!);
$video_id = $1;
#get flv url
my %prop = $self->find_property($video_id);
my $flv_url = $prop{url};
unless($flv_url){
$context->log(warn => "Not Found FLV URL $prop{error}: $video_id");
return;
}
$context->log(info => "Found FLV URL $flv_url");
my $enclosure = Plagger::Enclosure->new;
$enclosure->url( URI->new($flv_url) );
$enclosure->media_type( "video/x-flv" );
#set local path
my $filename = $self->conf->{id_as_filename} ? $video_id : $entry->title;
utf8::encode($filename);
if($self->conf->{filename_encode}){
Encode::from_to($filename, "utf-8", $self->conf->{filename_encode});
}
my $path = File::Spec->catfile($self->conf->{dir}, $filename . ".flv");
#access video page
$ua->get( "http://www.nicovideo.jp/watch/$video_id" );
#download flv file
my $req = HTTP::Request->new(GET => $enclosure->url);
$context->log(info => "Fetching $video_id FLV File ... " );
my $res = $ua->request($req, $path);
$context->log(warn => "Fetch FLV Error: $video_id" ) if $res->is_error;
#download xml file
if($self->conf->{download_comment}){
$path = File::Spec->catfile($self->conf->{dir}, $filename . ".xml");
my $post_data = qq!<thread res_from="-500" version="20061206" thread="$prop{thread_id}" />"!;
my $header = HTTP::Headers->new;
$header->header('Content-Type' => 'text/xml');
my $req = HTTP::Request->new('POST', $prop{ms}, $header, $post_data );
$context->log(info => "Fetching $video_id XML File ... " );
$res = $ua->request($req, $path);
$context->log(warn => "Fetch XML Error: $video_id" ) if $res->is_error;
}
$enclosure->filename($filename);
$enclosure->local_path($path); # set to be used in later plugins
if ($res->header('Content-Length')) {
$enclosure->length( $res->header('Content-Length') );
}
$entry->add_enclosure($enclosure);
}
sub login {
my $self = shift;
my $res = $self->{ua}->post( "http://www.nicovideo.jp/login",
[
mail => $self->conf->{mail},
password => $self->conf->{password},
]);
return $res->content;
}
sub find_property {
my($self, $video_id) = @_;
my $res = $self->{ua}->get( "http://www.nicovideo.jp/api/getflv?v=$video_id");
return if $res->is_error;
my $content = URI::Escape::uri_unescape($res->content);
my %data;
my @temp = split("&",$content);
foreach my $prop (@temp){
if($prop =~ /(.*?)=(.*)/){
$data{$1} = $2;
}
}
return %data;
}
1;
__END__
=head1 NAME
Plagger::Plugin::Filter::FetchNicoVideo - Fetch flv file from NicoVideo link
=head1 SYNOPSIS
- module: Filter::FetchNicoVideo
config:
mail: your@mailadddres
password: yourpassword
dir: /path/to/files
download_xml: 1 #optional default is 0
filename_encode: euc-jp #optional default is utf-8
=head1 DESCRIPTION
This plugin downloads flv file for each entry which has NicoVideo link.
=head1 CONFIG
=over 4
=item mail password
Your NicoVideo login mail address and password.
=item dir
Directory to store downloaded enclosures. Required.
=item download_xml
IF set, download comment xml file. Optional. Default is off.
=item filename_encode
File name encode. Example: euc-jp / shift-jis. Optional. Default is utf-8.
=item id_as_filename
IF set, set video id as flv file. Default file name is entry title. Optional.
=back
=head1 AUTHOR
Yusuke Wada
=head1 SEE ALSO
L<Plagger>, L<http://www.nicovideo.jp/>
=cut


コメント (1)
先日のログイン方法変更によりログイン先が変わったようです。
とりあえず下記変更でログインはいけました。(ニコRSSの挙動も多少変わってる気もしますが未検証です)
変更前
my $res = $self->{ua}->post( "http://www.nicovideo.jp/login",
変更後
my $res = $self->{ua}->post( "https://secure.nicovideo.jp/secure/login?site=niconico",
ご報告までに。
投稿者: Naoto | 2007年08月26日 20:45
日時: 2007年08月26日 20:45