Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

import NicoVideo downloader with proxy CGI script

  • Loading branch information...
commit e3ad7976d28c0603aed7d553ab9c690e9ee3e5e5 0 parents
@miyagawa authored
1  .shipit
@@ -0,0 +1 @@
+steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
4 Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension WWW::NicoVideo::Download
+
+0.01 Sun Oct 26 14:14:56 2008
+ - original version
27 MANIFEST
@@ -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 MANIFEST.SKIP
@@ -0,0 +1,13 @@
+\bRCS\b
+\bCVS\b
+\.svn/
+^MANIFEST\.
+^Makefile$
+~$
+\.old$
+^blib/
+^pm_to_blib
+^MakeMaker-\d
+\.gz$
+\.cvsignore
+\.shipit
25 META.yml
@@ -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 Makefile.PL
@@ -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 README
@@ -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 eg/fetch-video.pl
@@ -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 eg/nph-download-proxy.cgi
@@ -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 lib/WWW/NicoVideo/Download.pm
@@ -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 t/00_compile.t
@@ -0,0 +1,4 @@
+use strict;
+use Test::More tests => 1;
+
+BEGIN { use_ok 'WWW::NicoVideo::Download' }
5 xt/perlcritic.t
@@ -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 xt/pod.t
@@ -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 xt/podspell.t
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.