#!/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