line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Rarbg::torrentapi; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
121023
|
use strict; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
31
|
|
4
|
1
|
|
|
1
|
|
21
|
use 5.008_005; |
|
1
|
|
|
|
|
3
|
|
5
|
|
|
|
|
|
|
our $VERSION = 'v0.1.10'; |
6
|
1
|
|
|
1
|
|
7
|
use LWP::UserAgent; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
7
|
1
|
|
|
1
|
|
578
|
use JSON; |
|
1
|
|
|
|
|
8662
|
|
|
1
|
|
|
|
|
5
|
|
8
|
1
|
|
|
1
|
|
139
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
84
|
|
9
|
1
|
|
|
1
|
|
351
|
use Rarbg::torrentapi::Res; |
|
1
|
|
|
|
|
17
|
|
|
1
|
|
|
|
|
69
|
|
10
|
1
|
|
|
1
|
|
614
|
use Rarbg::torrentapi::Error; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
38
|
|
11
|
1
|
|
|
1
|
|
7
|
use Moose; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $BASEURL = 'https://torrentapi.org/pubapi_v2.php?'; |
14
|
|
|
|
|
|
|
our $REQUEST_LIMIT = 2; # The api has a 1req/2s limit. |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has [qw(search_string search_imdb search_themoviedb search_tvdb category)] => ( |
17
|
|
|
|
|
|
|
is => 'rw', |
18
|
|
|
|
|
|
|
isa => 'Str' |
19
|
|
|
|
|
|
|
); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has limit => ( |
22
|
|
|
|
|
|
|
is => 'rw', |
23
|
|
|
|
|
|
|
isa => 'Int', |
24
|
|
|
|
|
|
|
default => 25 |
25
|
|
|
|
|
|
|
); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
has sort => ( |
28
|
|
|
|
|
|
|
is => 'rw', |
29
|
|
|
|
|
|
|
isa => 'Str', |
30
|
|
|
|
|
|
|
default => 'last' |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
has [qw(min_seeders min_leechers)] => ( |
34
|
|
|
|
|
|
|
is => 'rw', |
35
|
|
|
|
|
|
|
isa => 'Int' |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has ranked => ( |
39
|
|
|
|
|
|
|
is => 'rw', |
40
|
|
|
|
|
|
|
isa => 'Int', |
41
|
|
|
|
|
|
|
default => 0 |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
has mode => ( |
45
|
|
|
|
|
|
|
is => 'rw', |
46
|
|
|
|
|
|
|
isa => 'Str', |
47
|
|
|
|
|
|
|
default => 'list' |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
has app_id => ( |
51
|
|
|
|
|
|
|
is => 'rw', |
52
|
|
|
|
|
|
|
isa => 'Str', |
53
|
|
|
|
|
|
|
default => 'p5-Rarbg-torrentapi' |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
has _format => ( |
57
|
|
|
|
|
|
|
is => 'ro', |
58
|
|
|
|
|
|
|
isa => 'Str', |
59
|
|
|
|
|
|
|
default => 'json_extended' |
60
|
|
|
|
|
|
|
); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
has _ua => ( |
63
|
|
|
|
|
|
|
is => 'ro', |
64
|
|
|
|
|
|
|
default => sub { |
65
|
|
|
|
|
|
|
LWP::UserAgent->new( agent => 'curl/7.44.0' ); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
has _token => ( |
70
|
|
|
|
|
|
|
is => 'rw', |
71
|
|
|
|
|
|
|
isa => 'Str', |
72
|
|
|
|
|
|
|
default => sub { |
73
|
|
|
|
|
|
|
my $self = shift; |
74
|
|
|
|
|
|
|
$self->_renew_token(); |
75
|
|
|
|
|
|
|
}, |
76
|
|
|
|
|
|
|
required => 1, |
77
|
|
|
|
|
|
|
lazy => 1 |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
has _token_time => ( |
81
|
|
|
|
|
|
|
is => 'rw', |
82
|
|
|
|
|
|
|
isa => 'Int', |
83
|
|
|
|
|
|
|
default => -1, |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
has _last_request => ( |
87
|
|
|
|
|
|
|
is => 'rw', |
88
|
|
|
|
|
|
|
isa => 'Int', |
89
|
|
|
|
|
|
|
default => -1 |
90
|
|
|
|
|
|
|
); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub _renew_token { |
93
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
94
|
1
|
|
|
|
|
30
|
$self->_last_request(time); |
95
|
1
|
|
|
|
|
40
|
my $url = $BASEURL . "get_token=get_token&app_id=" . $self->app_id; |
96
|
1
|
|
|
|
|
25
|
my $res_json = $self->_ua->get($url); |
97
|
1
|
50
|
|
|
|
11175
|
if ( $res_json->is_success ) { |
98
|
1
|
|
|
|
|
44
|
$self->_token_time(time); |
99
|
1
|
|
|
|
|
6
|
my $res = decode_json( $res_json->decoded_content ); |
100
|
1
|
|
|
|
|
189
|
return $res->{token}; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
else { |
103
|
0
|
|
|
|
|
0
|
confess "Cannot get token " . $res_json->status_line; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub _token_valid { |
108
|
3
|
|
|
3
|
|
14
|
my $self = shift; |
109
|
3
|
|
|
|
|
236
|
( time - $self->_token_time ) < 890; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub _make_request { |
113
|
2
|
|
|
2
|
|
3
|
my $self = shift; |
114
|
2
|
50
|
33
|
|
|
48
|
sleep $REQUEST_LIMIT if $self->_last_request != -1 && time - $self->_last_request < $REQUEST_LIMIT; |
115
|
2
|
50
|
|
|
|
66
|
unless ( $self->_token_valid ) { |
116
|
0
|
|
|
|
|
0
|
$self->_token( $self->_renew_token ); |
117
|
0
|
|
|
|
|
0
|
sleep $REQUEST_LIMIT; |
118
|
|
|
|
|
|
|
} |
119
|
2
|
|
|
|
|
57
|
$self->_last_request(time); |
120
|
2
|
|
|
|
|
7
|
my $url = $BASEURL; |
121
|
2
|
|
|
|
|
26
|
foreach my $attribute ( $self->meta->get_attribute_list ) { |
122
|
34
|
100
|
|
|
|
313
|
next if $attribute =~ /^_/; |
123
|
24
|
100
|
|
|
|
607
|
if ( $self->$attribute ) { |
124
|
9
|
|
|
|
|
221
|
$url .= "$attribute=" . $self->$attribute . "&"; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
2
|
|
|
|
|
61
|
$url .= "format=" . $self->_format . "&"; |
128
|
2
|
|
|
|
|
64
|
$url .= "ranked=" . $self->ranked . "&"; |
129
|
2
|
|
|
|
|
47
|
$url .= "token=" . $self->_token; |
130
|
2
|
|
|
|
|
49
|
my $res_json = $self->_ua->get($url); |
131
|
2
|
50
|
|
|
|
2945
|
if ( $res_json->is_success ) { |
132
|
2
|
|
|
|
|
29
|
my $tresults = decode_json( $res_json->decoded_content ); |
133
|
2
|
|
|
|
|
247
|
my @res; |
134
|
2
|
100
|
100
|
|
|
10
|
if ( $tresults->{torrent_results} |
135
|
1
|
|
|
|
|
5
|
&& scalar( @{ $tresults->{torrent_results} } ) ) |
136
|
|
|
|
|
|
|
{ |
137
|
1
|
|
|
|
|
3
|
foreach my $t ( @{ $tresults->{torrent_results} } ) { |
|
1
|
|
|
|
|
3
|
|
138
|
2
|
|
|
|
|
73
|
my $t_obj = Rarbg::torrentapi::Res->new($t); |
139
|
2
|
|
|
|
|
4
|
push @res, $t_obj; |
140
|
|
|
|
|
|
|
} |
141
|
1
|
|
|
|
|
9
|
return \@res; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
else { |
144
|
1
|
|
|
|
|
40
|
return Rarbg::torrentapi::Error->new($tresults); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
else { |
148
|
0
|
|
|
|
|
0
|
confess "Cannot execute Call " . $res_json->status_line; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
foreach my $method (qw/list search/) { |
153
|
|
|
|
|
|
|
__PACKAGE__->meta->add_method( |
154
|
|
|
|
|
|
|
$method, |
155
|
|
|
|
|
|
|
sub { |
156
|
2
|
|
|
2
|
|
483
|
my $self = shift; |
|
|
|
|
2
|
|
|
|
157
|
2
|
|
|
|
|
4
|
my $args = shift; |
158
|
2
|
|
|
|
|
4
|
foreach my $key ( keys %{$args} ) { |
|
2
|
|
|
|
|
7
|
|
159
|
1
|
|
|
|
|
32
|
$self->$key( $args->{$key} ); |
160
|
|
|
|
|
|
|
} |
161
|
2
|
|
|
|
|
56
|
$self->mode("$method"); |
162
|
2
|
|
|
|
|
6
|
return $self->_make_request; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
1
|
|
|
1
|
|
6736
|
no Moose; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
168
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
169
|
|
|
|
|
|
|
1; |
170
|
|
|
|
|
|
|
__END__ |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=encoding utf-8 |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 NAME |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Rarbg::torrentapi - Wrapper around Rarbg torrentapi (L<https://torrentapi.org/apidocs_v2.txt>) |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head1 SYNOPSIS |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
use Rarbg::torrentapi; |
181
|
|
|
|
|
|
|
my $tapi = Rarbg::torrentapi->new(); |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# list lastest torrents |
184
|
|
|
|
|
|
|
my $last_added = $tapi->list(); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# list torrents sorted by seeders |
187
|
|
|
|
|
|
|
my $last_added = $tapi->list({ |
188
|
|
|
|
|
|
|
sort => 'seeders', |
189
|
|
|
|
|
|
|
limit => 50, |
190
|
|
|
|
|
|
|
category => 'tv' |
191
|
|
|
|
|
|
|
}); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# search by string |
194
|
|
|
|
|
|
|
# You can use all attributes also |
195
|
|
|
|
|
|
|
my $search = $tapi->search({ |
196
|
|
|
|
|
|
|
search_string => 'the beatles', |
197
|
|
|
|
|
|
|
category => '23;24;25;26', |
198
|
|
|
|
|
|
|
min_seeders => 20 |
199
|
|
|
|
|
|
|
}); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# search by imdb id |
202
|
|
|
|
|
|
|
my $search = $tapi->search({ |
203
|
|
|
|
|
|
|
search_imdb => 'tt123456' |
204
|
|
|
|
|
|
|
}); |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# search by themoviedb id |
207
|
|
|
|
|
|
|
my $search = $tapi->search({ |
208
|
|
|
|
|
|
|
search_themoviedb => '123456' |
209
|
|
|
|
|
|
|
}); |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# search by tvdb id |
212
|
|
|
|
|
|
|
my $search = $tapi->search({ |
213
|
|
|
|
|
|
|
search_tvdb => '123456' |
214
|
|
|
|
|
|
|
}); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 DESCRIPTION |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Rarbg::torrentapi is a simple wrapper around Rarbg's torrentapi. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Those attributes can be used on all public methods. In fact you can use them also when creating the object. Some of them make more sense at creation time, some others when calling the method. It's your call. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
The only difference is that you should pass them as an anonymous hash if you pass them to a method. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
You can find more info about their values at L<https://torrentapi.org/apidocs_v2.txt> |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 search_string |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head2 search_imdb |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
This is the Imdb id (http://imdb.com) in the form 'tt123456' |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 search_themoviedb |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head2 search_tvdb |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head2 category |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Category can be quite confusing. |
242
|
|
|
|
|
|
|
It accepts 'tv' and 'movies'. But, for the rest of categories only accepts its id numbers (or a semi-colon separated list of them). |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=over 4 |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item * XXX (18+) => 4 |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item * Movies/XVID => 14 |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item * Movies/XVID/720 => 48 |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=item * Movies/x264 => 17 |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item * Movies/x264/1080 => 44 |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=item * Movies/x264/720 => 45 |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=item * Movies/x264/3D => 47 |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=item * Movies/x264/4k => 50 |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=item * Movies/x265/4k => 51 |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item * Movies/x264/4k/HDR => 52 |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=item * Movies/Full BD => 42 |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=item * Movies/BD Remux => 46 |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=item * TV Episodes => 18 |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=item * TV HD Episodes => 41 |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=item * TV UHD Episodes => 49 |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=item * Movies/MP3 => 23 |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item * Movies/FLAC => 25 |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item * Games/PC ISO => 27 |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item * Games/PC RIP => 28 |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=item * Games/PS3 => 40 |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item * Games/XBOX-360 => 32 |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=item * Software/PC ISO => 33 |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=item * Games/PS4 => 53 |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=back |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head2 limit |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
It can be 25, 50 or 100. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head2 sort |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
It can be seeders, leechers or last |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=head2 min_seeders |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head2 min_leechers |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head2 ranked |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
This marks if you want to get all indexed torrents or just the ones from rarbg team. |
309
|
|
|
|
|
|
|
Defaults to all (0). |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=head1 METHODS |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head2 new |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Just a simple constructor. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=head2 search |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
Makes a call to the API in 'search' mode. It returns either a Rarbg::torrentapi::Error or an array of L<Rarbg::torrentapi::Res>. |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=head2 list |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Makes a call to the API in 'list' mode. It returns either a Rarbg::torrentapi::Error or an array of L<Rarbg::torrentapi::Res>. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=head1 AUTHORS |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
Paco Esteban E<lt>paco@onna.beE<gt> |
328
|
|
|
|
|
|
|
Baptiste C. L<https://github.com/baptistecdr> |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=head1 COPYRIGHT |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
Copyright 2015- Paco Esteban |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head1 LICENSE |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
337
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |