| 1 | package Plagger::Plugin::Filter::FetchNicoVideo; |
|---|
| 2 | use strict; |
|---|
| 3 | use base qw( Plagger::Plugin ); |
|---|
| 4 | |
|---|
| 5 | our $VERSION = 0.02; |
|---|
| 6 | |
|---|
| 7 | use URI::Escape; |
|---|
| 8 | use File::Path qw(mkpath); |
|---|
| 9 | use File::Spec; |
|---|
| 10 | use HTTP::Request; |
|---|
| 11 | use Time::HiRes qw(sleep); |
|---|
| 12 | use Plagger::Enclosure; |
|---|
| 13 | use Plagger::UserAgent; |
|---|
| 14 | use CGI; |
|---|
| 15 | |
|---|
| 16 | sub register { |
|---|
| 17 | my ( $self, $context ) = @_; |
|---|
| 18 | $context->register_hook( $self, 'update.entry.fixup' => \&filter, ); |
|---|
| 19 | my $ua = Plagger::UserAgent->new( keep_alive => 1 ); |
|---|
| 20 | $ua->cookie_jar( {} ); |
|---|
| 21 | $ua->post( "https://secure.nicovideo.jp/secure/login?site=niconico" => $self->conf ); |
|---|
| 22 | $self->{ua} = $ua; |
|---|
| 23 | } |
|---|
| 24 | |
|---|
| 25 | sub init { |
|---|
| 26 | my $self = shift; |
|---|
| 27 | $self->SUPER::init(@_); |
|---|
| 28 | |
|---|
| 29 | defined $self->conf->{mail} |
|---|
| 30 | or Plagger->context->error("conifg 'mail' is not set."); |
|---|
| 31 | defined $self->conf->{password} |
|---|
| 32 | or Plagger->context->error("config 'password' is not set."); |
|---|
| 33 | defined $self->conf->{dir} |
|---|
| 34 | or Plagger->context->error("config 'dir' is not set."); |
|---|
| 35 | |
|---|
| 36 | if ( $self->conf->{dir} =~ /^[a-zA-Z]/ && $self->conf->{dir} !~ /:/ ) { |
|---|
| 37 | $self->conf->{dir} = |
|---|
| 38 | File::Spec->catfile( Cwd::cwd, $self->conf->{dir} ); |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | unless ( -e $self->conf->{dir} && -d _ ) { |
|---|
| 42 | Plagger->context->log( |
|---|
| 43 | warn => $self->conf->{dir} . " does not exist. Creating" ); |
|---|
| 44 | mkpath $self->conf->{dir}; |
|---|
| 45 | } |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | sub filter { |
|---|
| 49 | my ( $self, $context, $args ) = @_; |
|---|
| 50 | my $ua = $self->{ua}; |
|---|
| 51 | my $entry = $args->{entry}; |
|---|
| 52 | |
|---|
| 53 | #get video_id |
|---|
| 54 | my ($video_id) = $entry->link =~ m!www.nicovideo.jp/watch/(.*)!; |
|---|
| 55 | |
|---|
| 56 | #get flv url |
|---|
| 57 | my $res = $ua->get("http://www.nicovideo.jp/api/getflv?v=$video_id"); |
|---|
| 58 | my $q = CGI->new( $res->content ); |
|---|
| 59 | my $flv_url = $q->param('url'); |
|---|
| 60 | |
|---|
| 61 | unless ($flv_url) { |
|---|
| 62 | $context->log( warn => "Not Found FLV URL : $video_id" ); |
|---|
| 63 | return; |
|---|
| 64 | } |
|---|
| 65 | $context->log( info => "Found FLV URL $flv_url" ); |
|---|
| 66 | |
|---|
| 67 | my $enclosure = Plagger::Enclosure->new; |
|---|
| 68 | $enclosure->url( URI->new($flv_url) ); |
|---|
| 69 | $enclosure->media_type("video/x-flv"); |
|---|
| 70 | |
|---|
| 71 | #set local path |
|---|
| 72 | my $filename = $self->conf->{id_as_filename} ? $video_id : $entry->title; |
|---|
| 73 | utf8::encode($filename); |
|---|
| 74 | if ( $self->conf->{filename_encode} ) { |
|---|
| 75 | Encode::from_to( $filename, "utf-8", $self->conf->{filename_encode} ); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | $enclosure->url =~ m!^http://[^/]+(?:smilevideo|nicovideo)\.jp/smile\?(\w)=(?:[^.]+)\.\d+(?:low)?!; |
|---|
| 79 | my %video_type_of = ( |
|---|
| 80 | v => 'flv', |
|---|
| 81 | m => 'mp4', |
|---|
| 82 | s => 'swf', |
|---|
| 83 | ); |
|---|
| 84 | my $ext = exists( $video_type_of{$1} ) ? $video_type_of{$1} : "flv"; |
|---|
| 85 | |
|---|
| 86 | my $path = File::Spec->catfile( $self->conf->{dir}, $filename . ".$ext" ); |
|---|
| 87 | |
|---|
| 88 | unless ( -e $path ) { |
|---|
| 89 | #access video page |
|---|
| 90 | $ua->get("http://www.nicovideo.jp/watch/$video_id"); |
|---|
| 91 | |
|---|
| 92 | #download flv file |
|---|
| 93 | my $req = HTTP::Request->new(GET => $enclosure->url); |
|---|
| 94 | $context->log(info => "Fetching $video_id FLV File from " . $enclosure->url . "..." ); |
|---|
| 95 | my $res = $ua->request($req, $path); |
|---|
| 96 | $context->log(warn => "Fetch FLV Error: $video_id" ) if $res->is_error; |
|---|
| 97 | }else{ |
|---|
| 98 | $context->log(info => "Exist FLV File: $video_id"); |
|---|
| 99 | my $sleeping_time = $self->conf->{interval} || 15; |
|---|
| 100 | $context->log(info => "sleep $sleeping_time."); |
|---|
| 101 | sleep( $sleeping_time ); |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | #download xml file |
|---|
| 105 | if ( $self->conf->{download_comment} ) { |
|---|
| 106 | $path = File::Spec->catfile( $self->conf->{dir}, $filename . ".xml" ); |
|---|
| 107 | unless ( -e $path ) { |
|---|
| 108 | my $thread_id = $q->param('thread_id'); |
|---|
| 109 | my $post_data = |
|---|
| 110 | qq!<thread res_from="-500" version="20061206" thread="$thread_id" />"!; |
|---|
| 111 | my $header = HTTP::Headers->new; |
|---|
| 112 | $header->header( 'Content-Type' => 'text/xml' ); |
|---|
| 113 | my $req = HTTP::Request->new( 'POST', $q->param('ms'), $header, $post_data ); |
|---|
| 114 | $context->log( info => "Fetching $video_id XML File ... " ); |
|---|
| 115 | $res = $ua->request( $req, $path ); |
|---|
| 116 | $context->log( warn => "Fetch XML Error: $video_id" ) if $res->is_error; |
|---|
| 117 | } |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | $enclosure->filename($filename); |
|---|
| 121 | $enclosure->local_path($path); # set to be used in later plugins |
|---|
| 122 | if ($res->header('Content-Length') ) { |
|---|
| 123 | $enclosure->length( $res->header('Content-Length') ); |
|---|
| 124 | } |
|---|
| 125 | $enclosure->type( Plagger::Util::mime_type_of($path) ); |
|---|
| 126 | $entry->add_enclosure($enclosure); |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | 1; |
|---|
| 130 | |
|---|
| 131 | __END__ |
|---|
| 132 | |
|---|
| 133 | =head1 NAME |
|---|
| 134 | |
|---|
| 135 | Plagger::Plugin::Filter::FetchNicoVideo - Fetch flv file from NicoVideo link |
|---|
| 136 | |
|---|
| 137 | =head1 SYNOPSIS |
|---|
| 138 | |
|---|
| 139 | - module: Filter::FetchNicoVideo |
|---|
| 140 | config: |
|---|
| 141 | mail: your@mailadddres |
|---|
| 142 | password: yourpassword |
|---|
| 143 | dir: /path/to/files |
|---|
| 144 | download_xml: 1 #optional default is 0 |
|---|
| 145 | filename_encode: euc-jp #optional default is utf-8 |
|---|
| 146 | interval: 60 #optional default is 15 |
|---|
| 147 | |
|---|
| 148 | =head1 DESCRIPTION |
|---|
| 149 | |
|---|
| 150 | This plugin downloads flv file for each entry which has NicoVideo link. |
|---|
| 151 | |
|---|
| 152 | =head1 CONFIG |
|---|
| 153 | |
|---|
| 154 | =over 4 |
|---|
| 155 | |
|---|
| 156 | =item mail password |
|---|
| 157 | |
|---|
| 158 | Your NicoVideo login mail address and password. |
|---|
| 159 | |
|---|
| 160 | =item dir |
|---|
| 161 | |
|---|
| 162 | Directory to store downloaded enclosures. Required. |
|---|
| 163 | |
|---|
| 164 | =item download_xml |
|---|
| 165 | |
|---|
| 166 | IF set, download comment xml file. Optional. Default is off. |
|---|
| 167 | |
|---|
| 168 | =item filename_encode |
|---|
| 169 | |
|---|
| 170 | File name encode. Example: euc-jp / shift_jis. Optional. Default is utf-8. |
|---|
| 171 | |
|---|
| 172 | =item id_as_filename |
|---|
| 173 | |
|---|
| 174 | IF set, set video id as flv file. Default file name is entry title. Optional. |
|---|
| 175 | |
|---|
| 176 | =back |
|---|
| 177 | |
|---|
| 178 | =head1 AUTHOR |
|---|
| 179 | |
|---|
| 180 | Yusuke Wada |
|---|
| 181 | |
|---|
| 182 | =head1 SEE ALSO |
|---|
| 183 | |
|---|
| 184 | L<Plagger>, L<http://www.nicovideo.jp/> |
|---|
| 185 | |
|---|
| 186 | =cut |
|---|
| 187 | |
|---|