Skip to content

Commit

Permalink
import NicoVideo downloader with proxy CGI script
Browse files Browse the repository at this point in the history
  • Loading branch information
miyagawa committed Oct 26, 2008
0 parents commit e3ad797
Show file tree
Hide file tree
Showing 14 changed files with 373 additions and 0 deletions.
1 change: 1 addition & 0 deletions .shipit
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
4 changes: 4 additions & 0 deletions Changes
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,4 @@
Revision history for Perl extension WWW::NicoVideo::Download

0.01 Sun Oct 26 14:14:56 2008
- original version
27 changes: 27 additions & 0 deletions MANIFEST
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,27 @@
Changes
inc/Module/Install.pm
inc/Module/Install/AuthorTests.pm
inc/Module/Install/Base.pm
inc/Module/Install/Can.pm
inc/Module/Install/Fetch.pm
inc/Module/Install/Include.pm
inc/Module/Install/Makefile.pm
inc/Module/Install/Metadata.pm
inc/Module/Install/TestBase.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
inc/Spiffy.pm
inc/Test/Base.pm
inc/Test/Base/Filter.pm
inc/Test/Builder.pm
inc/Test/Builder/Module.pm
inc/Test/More.pm
lib/WWW/NicoVideo/Download.pm
Makefile.PL
MANIFEST This list of files
META.yml
README
t/00_compile.t
xt/perlcritic.t
xt/pod.t
xt/podspell.t
13 changes: 13 additions & 0 deletions MANIFEST.SKIP
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,13 @@
\bRCS\b
\bCVS\b
\.svn/
^MANIFEST\.
^Makefile$
~$
\.old$
^blib/
^pm_to_blib
^MakeMaker-\d
\.gz$
\.cvsignore
\.shipit
25 changes: 25 additions & 0 deletions META.yml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,25 @@
---
abstract: 'Download FLV/MP4/SWF files from nicovideo.jp'
author:
- 'Tatsuhiko Miyagawa <miyagawa@cpan.org>'
build_requires:
Test::More: 0
distribution_type: module
generated_by: 'Module::Install version 0.77'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: 1.4
name: WWW-NicoVideo-Download
no_index:
directory:
- inc
- t
requires:
CGI::Simple: 0
LWP::UserAgent: 0
Moose: 0
perl: 5.8.1
resources:
license: http://dev.perl.org/licenses/
version: 0.01
13 changes: 13 additions & 0 deletions Makefile.PL
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,13 @@
use inc::Module::Install;
name 'WWW-NicoVideo-Download';
all_from 'lib/WWW/NicoVideo/Download.pm';

requires 'LWP::UserAgent';
requires 'Moose';
requires 'CGI::Simple';

build_requires 'Test::More';
use_test_base;
auto_include_deps;
author_tests('xt');
WriteAll;
27 changes: 27 additions & 0 deletions README
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,27 @@
This is Perl module WWW::NicoVideo::Download.

INSTALLATION

WWW::NicoVideo::Download installation is straightforward. If your CPAN shell is set up,
you should just be able to do

% cpan WWW::NicoVideo::Download

Download it, unpack it, then build it as per the usual:

% perl Makefile.PL
% make && make test

Then install it:

% make install

DOCUMENTATION

WWW::NicoVideo::Download documentation is available as in POD. So you can do:

% perldoc WWW::NicoVideo::Download

to read the documentation online with your favorite pager.

Tatsuhiko Miyagawa
24 changes: 24 additions & 0 deletions eg/fetch-video.pl
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/perl
use strict;
use WWW::NicoVideo::Download;
use Term::ProgressBar;

my($email, $password, $video_id) = @ARGV;

my($term, $fh);

my $client = WWW::NicoVideo::Download->new( email => $email, password => $password );
$client->download($video_id, \&cb);

sub cb {
my($data, $res, $proto) = @_;

unless ($term && $fh) {
my $ext = (split '/', $res->header('Content-Type'))[-1] || "flv";
open $fh, ">", "$video_id.$ext" or die $!;
$term = Term::ProgressBar->new( $res->header('Content-Length') );
}

$term->update( $term->last_update + length $data );
print $fh $data;
}
47 changes: 47 additions & 0 deletions eg/nph-download-proxy.cgi
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/perl
use strict;
use CGI::Simple;
use WWW::NicoVideo::Download;

# Access as nph-download-proxy.cgi/sm9
my $email = 'YOUR-EMAIL@example.com';
my $password = 'YOUR-PASSWORD';

my $query = CGI::Simple->new;
my $video_id = ($query->path_info =~ m!^/(\w+)!)[0];

my $client = WWW::NicoVideo::Download->new( email => $email, password => $password );
my $url = $client->prepare_download($video_id);

my $req = HTTP::Request->new( GET => $url );
if ($ENV{HTTP_RANGE}) {
$req->header( Range => $ENV{HTTP_RANGE} );
}
my $res = $client->user_agent->request( $req, make_callback($video_id) );

if ($res->is_error) {
print $res->as_string;
}

sub make_callback {
my $video_id = shift;

my $header_printed;
return sub {
my($data, $res, $proto) = @_;

unless ($header_printed) {
print "HTTP/1.0 " . $res->status_line . "\n";

if (my $ctd = $res->header("Content-Disposition")) {
$ctd =~ s/smile\./$video_id./;
$res->header("Content-Disposition" => $ctd);
}

print $res->headers->as_string;
$header_printed++;
}

print $data;
};
}
170 changes: 170 additions & 0 deletions lib/WWW/NicoVideo/Download.pm
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,170 @@
package WWW::NicoVideo::Download;

use strict;
use 5.8.1;
our $VERSION = '0.01';

use Carp;
use LWP::UserAgent;
use CGI::Simple;

use Moose;
has 'email', is => 'rw', isa => 'Str';
has 'password', is => 'rw', isa => 'Str';
has 'user_agent', is => 'rw', isa => 'LWP::UserAgent', default => sub {
LWP::UserAgent->new( cookie_jar => {} );
};

sub download {
my $self = shift;
my($video_id, @args) = @_;

my $url = $self->prepare_download($video_id);
my $res = $self->user_agent->request( HTTP::Request->new( GET => $url ), @args );

croak "Download failed: ", $res->status_line if $res->is_error;
}

sub prepare_download {
my($self, $video_id) = @_;

if ($video_id =~ m!/watch/(\w+)!) {
$video_id = $1;
}

my $ua = $self->user_agent;
my $res = $ua->get("http://www.nicovideo.jp/watch/$video_id");

if ( $self->is_logged_out($res) ) {
$self->login($video_id);
}

$res = $ua->get("http://www.nicovideo.jp/api/getflv?v=$video_id");
if ($res->is_error) {
croak "getflv API error: ", $res->status_line;
}

my $params = CGI::Simple->new($res->content);
my $url = $params->param('url')
or croak "URL not found in getflv response";

# Not sure why, but you need to get the page again
$ua->get("http://www.nicovideo.jp/watch/$video_id");

return $url;
}

sub is_logged_out {
my($self, $res) = @_;
$res->content =~ /id="login_bar"/;
}

sub login {
my($self, $video_id) = @_;

my $res = $self->user_agent->post("https://secure.nicovideo.jp/secure/login?site=niconico", {
next_url => "/watch/$video_id",
mail => $self->email,
password => $self->password,
});

if ($res->is_error) {
croak "Login failed: " . $res->status_line;
} elsif ( $self->is_logged_out($res) ) {
croak "Login failed because of bad email and password combination.";
}

return 1;
}

1;
__END__
=encoding utf-8
=for stopwords nicovideo Nico Douga
=head1 NAME
WWW::NicoVideo::Download - Download FLV/MP4/SWF files from nicovideo.jp
=head1 SYNOPSIS
use WWW::NicoVideo::Download;
my $client = WWW::NicoVideo::Download->new(
email => 'your-email@example.com',
password => 'PASSSWORD',
);
$client->download("smNNNNNN", \&callback);
=head1 DESCRIPTION
WWW::NicoVideo::Download is a module to login, request and download video files from Nico Nico Douga.
=head1 METHODS
=over 4
=item new
$client = WWW::NicoVideo::Download->new(%options);
Creates a new WWW::NicoVideo::Download instance. %options can take the
following parameters and they can also be set and get using accessor
methods.
=item email, password
Sets and gets email and password to login Nico Nico Douga. Required if the User
Agent object doesn't have the valid session or cookie to login to the
site.
=item user_agent
Sets and gets LWP::UserAgent object to use to send HTTP requests to
nicovideo.jp server. If you want to reuse the browser Cookie that has
the signed-in state, you can set the Cookie to the UserAgent object
here.
# use Safari sesssions
use HTTP::Cookies::Safari;
my $cookie_jar = HTTP::Cookies::Safari->new(
file => "$ENV{HOME}/Library/Cookies/Cookies.plist",
);
my $client = WWW::NicoVideo::Download->new;
$client->user_agent->cookie_jar( $cookie_jar );
=item download
$client->download($video_id, $file_path);
Prepares the download by logging in and requesting the FLV API, and
then download the video file. The 2nd parameter is passed to
LWP::UserAgent's request() method, so you can pass either local file
path to be saved, or a callback function.
=item prepare_download
my $url = $client->prepare_download($video_id);
Prepares the download and returns the URL of the actual video. See
I<eg/fetch-video.pl> how to make use of this method.
=back
=head1 AUTHOR
Tatsuhiko Miyagawa E<lt>miyagawa@cpan.orgE<gt>
Original downloader code for Plagger was written by woremacx.
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 SEE ALSO
=cut
4 changes: 4 additions & 0 deletions t/00_compile.t
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,4 @@
use strict;
use Test::More tests => 1;

BEGIN { use_ok 'WWW::NicoVideo::Download' }
5 changes: 5 additions & 0 deletions xt/perlcritic.t
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,5 @@
use strict;
use Test::More;
eval q{ use Test::Perl::Critic };
plan skip_all => "Test::Perl::Critic is not installed." if $@;
all_critic_ok("lib");
4 changes: 4 additions & 0 deletions xt/pod.t
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,4 @@
use Test::More;
eval "use Test::Pod 1.00";
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
all_pod_files_ok();
9 changes: 9 additions & 0 deletions xt/podspell.t
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,9 @@
use Test::More;
eval q{ use Test::Spelling };
plan skip_all => "Test::Spelling is not installed." if $@;
add_stopwords(<DATA>);
set_spell_cmd("aspell -l en list");
all_pod_files_spelling_ok('lib');
__DATA__
Tatsuhiko
Miyagawa

0 comments on commit e3ad797

Please sign in to comment.