line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# -*- mode: perl; coding: utf-8 -*-
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package WWW::NicoVideo;
|
4
|
1
|
|
|
1
|
|
25717
|
use utf8;
|
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
5
|
|
5
|
1
|
|
|
1
|
|
33
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
35
|
|
6
|
1
|
|
|
1
|
|
6
|
use warnings;
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
38
|
|
7
|
1
|
|
|
1
|
|
5
|
use base qw[Class::Accessor];
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1254
|
|
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
3268
|
use Encode;
|
|
1
|
|
|
|
|
14739
|
|
|
1
|
|
|
|
|
95
|
|
10
|
1
|
|
|
1
|
|
9
|
use Carp;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
71
|
|
11
|
1
|
|
|
1
|
|
1095
|
use LWP::UserAgent;
|
|
1
|
|
|
|
|
71455
|
|
|
1
|
|
|
|
|
52
|
|
12
|
1
|
|
|
1
|
|
1054
|
use HTTP::Cookies;
|
|
1
|
|
|
|
|
9336
|
|
|
1
|
|
|
|
|
33
|
|
13
|
1
|
|
|
1
|
|
8
|
use URI;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
14
|
1
|
|
|
1
|
|
965
|
use URI::QueryParam;
|
|
1
|
|
|
|
|
968
|
|
|
1
|
|
|
|
|
29
|
|
15
|
1
|
|
|
1
|
|
668
|
use WWW::NicoVideo::Entry;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
8
|
|
16
|
1
|
|
|
1
|
|
539
|
use WWW::NicoVideo::Scraper;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6
|
|
17
|
1
|
|
|
1
|
|
6
|
use WWW::NicoVideo::URL;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1217
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors(qw[agent retry retryInterval mail passwd]);
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our $VERSION = "0.03";
|
22
|
|
|
|
|
|
|
our $AGENT_NAME = "@{[__PACKAGE__]}/$VERSION)";
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub new
|
25
|
|
|
|
|
|
|
{
|
26
|
0
|
|
|
0
|
1
|
|
my $pkg = shift;
|
27
|
0
|
|
|
|
|
|
my %opts = @_;
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $ua = $opts{agent} || new LWP::UserAgent(agent => $AGENT_NAME,
|
30
|
|
|
|
|
|
|
timeout => 30,
|
31
|
0
|
|
0
|
|
|
|
%{$opts{agentOpts}});
|
32
|
|
|
|
|
|
|
$ua->cookie_jar($opts{cookies} ||
|
33
|
0
|
|
0
|
|
|
|
new HTTP::Cookies(%{$opts{cookiesOpts}}));
|
34
|
|
|
|
|
|
|
|
35
|
0
|
|
0
|
|
|
|
bless {agent => $ua,
|
|
|
|
0
|
|
|
|
|
36
|
|
|
|
|
|
|
retry => $opts{retry} || 5,
|
37
|
|
|
|
|
|
|
retryInterval => $opts{retryInterval} || 30,
|
38
|
|
|
|
|
|
|
mail => $opts{mail},
|
39
|
|
|
|
|
|
|
passwd => $opts{passwd}}, $pkg;
|
40
|
|
|
|
|
|
|
}
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub login
|
43
|
|
|
|
|
|
|
{
|
44
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
45
|
0
|
|
|
|
|
|
my $ua = $self->{agent};
|
46
|
0
|
|
|
|
|
|
my $cj = $ua->cookie_jar;
|
47
|
0
|
|
|
|
|
|
my $has_cookie = 0;
|
48
|
|
|
|
|
|
|
|
49
|
0
|
0
|
0
|
|
|
|
if(not defined $self->{mail} or
|
50
|
|
|
|
|
|
|
not defined $self->{passwd}) {
|
51
|
0
|
|
|
|
|
|
confess "mail and passwd required";
|
52
|
|
|
|
|
|
|
}
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
$cj->scan(sub {
|
55
|
0
|
|
|
0
|
|
|
my($key, $val, $domain, $expires) = @_[1, 2, 4, 8];
|
56
|
0
|
0
|
0
|
|
|
|
if($domain eq ".nicovideo.jp" and
|
57
|
|
|
|
|
|
|
time + 60 < $expires) {
|
58
|
0
|
|
|
|
|
|
$has_cookie = 1;
|
59
|
|
|
|
|
|
|
}
|
60
|
0
|
|
|
|
|
|
});
|
61
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
|
my $login_ok = 0;
|
63
|
0
|
0
|
|
|
|
|
if($has_cookie) {
|
64
|
0
|
|
|
|
|
|
my $res = $ua->get(nicoURL("top"));
|
65
|
0
|
0
|
0
|
|
|
|
if($res->is_success and
|
66
|
|
|
|
|
|
|
not $res->as_string =~ / |
67
|
0
|
|
|
|
|
|
$login_ok = 1;
|
68
|
|
|
|
|
|
|
}
|
69
|
|
|
|
|
|
|
}
|
70
|
|
|
|
|
|
|
|
71
|
0
|
0
|
|
|
|
|
if($login_ok) {
|
72
|
0
|
|
|
|
|
|
$self->{loginOk} = 1;
|
73
|
0
|
|
|
|
|
|
return 1;
|
74
|
|
|
|
|
|
|
} else {
|
75
|
0
|
|
|
|
|
|
my $res = $ua->post(nicoURL("login"),
|
76
|
|
|
|
|
|
|
{mail => $self->{mail},
|
77
|
|
|
|
|
|
|
password => $self->{passwd}});
|
78
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
|
if($res->is_redirect) {
|
80
|
0
|
|
|
|
|
|
$self->{loginOk} = 1;
|
81
|
0
|
|
|
|
|
|
return 1;
|
82
|
|
|
|
|
|
|
} else {
|
83
|
0
|
|
|
|
|
|
return 0;
|
84
|
|
|
|
|
|
|
}
|
85
|
|
|
|
|
|
|
}
|
86
|
|
|
|
|
|
|
}
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub getEntriesByTagNames
|
89
|
|
|
|
|
|
|
{
|
90
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
91
|
0
|
|
|
|
|
|
$self->getEntries("tag", @_);
|
92
|
|
|
|
|
|
|
}
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
*getEntriesByTagName = \&getEntriesByTagNames;
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub getEntriesByKeywords
|
97
|
|
|
|
|
|
|
{
|
98
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
99
|
0
|
|
|
|
|
|
$self->getEntries("search", @_);
|
100
|
|
|
|
|
|
|
}
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
*getEntriesByKeyword = \&getEntriesByKeywords;
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub getEntries
|
105
|
|
|
|
|
|
|
{
|
106
|
0
|
|
|
0
|
0
|
|
my $self = shift;
|
107
|
0
|
|
|
|
|
|
my $type = shift;
|
108
|
0
|
|
|
|
|
|
my %opts = @_;
|
109
|
0
|
0
|
|
|
|
|
my @keys = (@{$opts{keys} || []},
|
|
0
|
0
|
|
|
|
|
|
110
|
|
|
|
|
|
|
(defined $opts{key}? $opts{key}: ()));
|
111
|
0
|
|
|
|
|
|
my $page = $opts{page};
|
112
|
0
|
|
|
|
|
|
my $sort = $opts{sort};
|
113
|
0
|
|
|
|
|
|
my $order = $opts{order};
|
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
my $ua = $self->{agent};
|
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
|
if(!$self->{loginOk}) {
|
118
|
0
|
0
|
|
|
|
|
return wantarray? (): undef;
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
my $url = new URI(nicoURL($type, @keys));
|
122
|
0
|
0
|
|
|
|
|
$url->query_param_append(sort => $sort) if(defined $sort);
|
123
|
0
|
0
|
|
|
|
|
$url->query_param_append(order => $order) if(defined $order);
|
124
|
0
|
0
|
|
|
|
|
$url->query_param_append(page => $page) if(defined $page);
|
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
my $count = 0;
|
127
|
0
|
|
|
|
|
|
my $res;
|
128
|
|
|
|
|
|
|
my $html;
|
129
|
|
|
|
|
|
|
|
130
|
0
|
|
0
|
|
|
|
do {
|
|
|
|
0
|
|
|
|
|
131
|
0
|
0
|
|
|
|
|
if($count) {
|
132
|
|
|
|
|
|
|
# busy
|
133
|
0
|
|
0
|
|
|
|
sleep($self->{retryInterval} || 30);
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
$res = $ua->get($url);
|
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
|
if($res->is_success) {
|
|
|
0
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
$html = decode_utf8($res->content);
|
140
|
|
|
|
|
|
|
} elsif($opts{verbose}) {
|
141
|
0
|
|
|
|
|
|
carp "Could not get $url (status: ", $res->status_line, ")";
|
142
|
|
|
|
|
|
|
}
|
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
$count++;
|
145
|
|
|
|
|
|
|
} while(not $res->is_success and
|
146
|
|
|
|
|
|
|
$count < $self->{retry} and
|
147
|
|
|
|
|
|
|
$html =~ m{^ 【ご注意】 }m # access blocking
|
148
|
|
|
|
|
|
|
);
|
149
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
my $scraper = scraper_entries();
|
151
|
0
|
0
|
|
|
|
|
my @res = (map { WWW::NicoVideo::Entry->new($_) }
|
|
0
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
@{$scraper->scrape($html)->{entries} || []});
|
153
|
0
|
0
|
|
|
|
|
wantarray? @res: \@res;
|
154
|
|
|
|
|
|
|
}
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
"Ritsuko";
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=encoding utf-8
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 NAME
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
WWW::NicoVideo - Perl interface to Nico Nico Video service
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
use utf8;
|
167
|
|
|
|
|
|
|
use WWW::NicoVideo;
|
168
|
|
|
|
|
|
|
binmode STDOUT, ":encoding(euc-jp)";
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
my $nv = new WWW::NicoVideo(mail => 'ritsuko@ritsuko.org',
|
171
|
|
|
|
|
|
|
passwd => "ritchan-wa-kawaiidesuyo");
|
172
|
|
|
|
|
|
|
$nv->login or die "Login failed";
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
my @entries = $nv->getEntriesByTagNames("律子ソロ") or die "get failed";
|
175
|
|
|
|
|
|
|
foreach my $e (@entries) {
|
176
|
|
|
|
|
|
|
print $e->title, "\n";
|
177
|
|
|
|
|
|
|
}
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
This module allows you to get information from
|
182
|
|
|
|
|
|
|
Nico Nico Video service (L)
|
183
|
|
|
|
|
|
|
and also allows you to search from it.
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head1 METHODS
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=over 4
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=item $nv = new WWW::NicoVideo(%OPTS)
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Constructs a new WWW::NicoVideo object and returns it.
|
192
|
|
|
|
|
|
|
Key/value pair options may be provided to set the default value.
|
193
|
|
|
|
|
|
|
Following options are accepted:
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=over 4
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=item agent / cookies
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
LWP::UserAgent / HTTP::Cookies object.
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item retry / retryInterval
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Retry count / retry interval in second.
|
204
|
|
|
|
|
|
|
As Nico Nico Video rejects mass access,
|
205
|
|
|
|
|
|
|
you have to give appropriate interval between accesses.
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item mail / passwd
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Mail address / password to access Nico Nico Video.
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=back
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
All options except "cookies" can be accessed via accessor methods.
|
214
|
|
|
|
|
|
|
(e.g. $nv->agent)
|
215
|
|
|
|
|
|
|
You may access cookies via "agent".
|
216
|
|
|
|
|
|
|
(e.g. $nv->agent->cookie_jar)
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=item $nv->login
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Login to Nico Nico Video. You have to call this method before
|
221
|
|
|
|
|
|
|
calling getEntries* methods;
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item $nv->getEntriesByTagNames(%OPTS) / $nv->getEntriesByKeywords(%OPTS)
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Returns entry list for given tag name(s) / keyword(s).
|
226
|
|
|
|
|
|
|
In scalar context, this method returns a reference to array of
|
227
|
|
|
|
|
|
|
WWW::NicoVideo::Entry or undef on errors.
|
228
|
|
|
|
|
|
|
In list context, this method returns list of WWW::NicoVideo::Entry
|
229
|
|
|
|
|
|
|
or null list on errors.
|
230
|
|
|
|
|
|
|
Following options are accepted:
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=over 4
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item key / keys
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Tagname(s) or keyword(s).
|
237
|
|
|
|
|
|
|
"key" takes a scalar value, "keys" takes a reference to array.
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=item page
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Page number.
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=item sort
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Sort type. "f" for post date, "v" for number of views,
|
246
|
|
|
|
|
|
|
"r" for number of comments, undef for last comment date.
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item order
|
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Sort order. "a" for ASC, "d" or undef for DESC.
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=back
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=back
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head1 SEE ALSO
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
L, L, L
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head1 AUTHOR
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
HIRATA Yasuyuki, Eyasu@REMOVE-THIS-PART.asuka.netE
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
267
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.8 or,
|
268
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available.
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head1 SUBVERSION REPOSITORY
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
The latest version of this module is available
|
273
|
|
|
|
|
|
|
from our Subversion repository at:
|
274
|
|
|
|
|
|
|
L
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=cut
|