#!/usr/bin/perl # copyed from http://coderepos.org/share/browser/lang/perl/plagger/lib/Plagger/Plugin/Filter/FetchNicoVideo.pm package FetchNicoVideo; use strict; use warnings; use Carp qw(croak); use Cwd (); use CGI; use Encode; use File::Spec; use HTTP::Request; use LWP::UserAgent; use Time::HiRes qw(sleep); use URI::Escape; our $VERSION = '0.01'; sub new { my $class = shift; my $opt = ref($_[0]) eq "HASH" ? shift : {@_}; eval { require Config::Pit; $opt->{pit} = Config::Pit::pit_get("nicovideo.jp"); }; for my $key (qw/mail password/) { $opt->{$key} ||= $opt->{pit}->{$key} if $opt->{pit}->{$key}; $opt->{_form}->{$key} = $opt->{$key}; croak "conifg '$key' is not set." unless $opt->{$key}; } my $self = bless $opt, $class; $self->_init_dir; $self->_init_ua; $self; } sub _init_dir { my $self = shift; unless ($self->{dir}) { $self->{dir} = Cwd::cwd; return; } if ($self->{dir} =~ /^[a-zA-Z]/ && $self->conf->{dir} !~ /:/) { $self->{dir} = File::Spec->catfile(Cwd::cwd, $self->conf->{dir}); } unless (-e $self->{dir} && -d _) { warn $self->{dir} . " does not exist. Creating" unless $self->{quiet}; mkpath $self->{dir}; } } sub _init_ua { my $self = shift; my $ua = LWP::UserAgent->new(keep_alive => 1); $ua->cookie_jar({}); $ua->post("https://secure.nicovideo.jp/secure/login?site=niconico" => $self->{_form}); $self->{ua} = $ua; $self; } sub download { my ($self, $entry) = @_; my $ua = $self->{ua}; # get video_id my ($video_id) = $entry =~ m!www.nicovideo.jp/watch/(.*)!; croak "invalid entry ($entry)" unless $video_id; my $resentry = $ua->get($entry); my $content = Encode::decode('utf-8', $resentry->content); my $title = ($content =~ m!]+>]+>(.*?)!s)[0]; # get flv url my $res = $ua->get("http://www.nicovideo.jp/api/getflv?v=$video_id"); my $q = CGI->new($res->content); my $flv_url = $q->param('url'); return warn "Not Found FLV URL : $video_id" unless $flv_url; print "Found FLV URL $flv_url" unless $self->{quiet}; #set local path my $filename; if ($self->{id_as_filename}) { $filename = $video_id; } else { $filename = exists($self->{title}) ? $self->{title} : $title; $filename =~ s!/!_!g; utf8::encode($filename); if ($self->{filename_encode}) { Encode::from_to($filename, "utf-8", $self->{filename_encode}); } if ($self->{add_id_to_filename}) { $filename = "$video_id $filename"; $filename =~ s/\s*$//; } } $flv_url =~ m!^http://[^/]+(?:smilevideo|nicovideo)\.jp/smile\?(\w)=(?:[^.]+)\.\d+(?:low)?!; my %video_type_of = ( v => 'flv', m => 'mp4', s => 'swf', ); my $ext = exists( $video_type_of{$1} ) ? $video_type_of{$1} : "flv"; my $path = File::Spec->catfile( $self->{dir}, $filename . ".$ext" ); unless (-e $path) { # access video page $ua->get("http://www.nicovideo.jp/watch/$video_id"); # download flv file my $req = HTTP::Request->new(GET => $flv_url); print "Fetching $video_id (save as '$filename.$ext') FLV File from " . $flv_url . "..." unless $self->{quiet};; $res = $ua->request($req, $path); print "\n" unless $self->{quiet}; warn "Fetch FLV Error: $video_id" if $res->is_error; } else { warn "Exist FLV File: $video_id"; my $sleeping_time = $self->{interval} || 15; warn "sleep $sleeping_time."; sleep($sleeping_time); } } package main; use strict; use warnings; use Getopt::Long; sub main { my %opt = (); GetOptions(\%opt, 'mail=s', 'password=s', 'quiet', 'dir=s', 'filename_encode=s', 'id_as_filename', 'add_id_to_filename', 'title=s', 'interval=i', ); if (exists($opt{title}) and scalar(@ARGV) > 1) { die "you cannot download multiple urls with --title option."; } my $nico = FetchNicoVideo->new(%opt); for my $entry (@ARGV) { $nico->download($entry); } } main; __END__ =head1 NAME fetch-nico-video - command line downloader of NicoVideo =head1 SYNOPSIS fetch-nico-video [options] [urls ...] =head1 DESCRIPTION fetch-nico-video is a command line downloader of NicoVideo. =head1 CONFIG =over 4 =item ~/.pit/default.yaml (on your pit) --- 'nicovideo.jp': mail: 'your mail address' password: 'your password' =item --mail and --password (overrride values of pit) --mail 'your mail address' --password 'your password' =item --dir Directory to store downloaded enclosures. Optional. =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. =item --add_id_to_filename IF set, add video id as prefix of filename. Optional. =item --title If set, override entry title. Optional. =item --interval Interval between each download. Default is 15. =back =head1 SEE ALSO L, L =cut