File Coverage

blib/lib/Rarbg/torrentapi.pm
Criterion Covered Total %
statement 67 71 94.3
branch 10 14 71.4
condition 3 6 50.0
subroutine 14 14 100.0
pod n/a
total 94 105 89.5


line stmt bran cond sub pod time code
1             package Rarbg::torrentapi;
2              
3 1     1   134744 use strict;
  1         7  
  1         26  
4 1     1   19 use 5.008_005;
  1         3  
5             our $VERSION = 'v0.1.9';
6 1     1   6 use LWP::UserAgent;
  1         3  
  1         19  
7 1     1   714 use JSON;
  1         9755  
  1         6  
8 1     1   141 use Carp;
  1         3  
  1         53  
9 1     1   370 use Rarbg::torrentapi::Res;
  1         19  
  1         46  
10 1     1   623 use Rarbg::torrentapi::Error;
  1         2  
  1         40  
11 1     1   7 use Moose;
  1         2  
  1         4  
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   3 my $self = shift;
94 1         39 $self->_last_request(time);
95 1         37 my $url = $BASEURL . "get_token=get_token&app_id=" . $self->app_id;
96 1         26 my $res_json = $self->_ua->get($url);
97 1 50       11908 if ( $res_json->is_success ) {
98 1         49 $self->_token_time(time);
99 1         7 my $res = decode_json( $res_json->decoded_content );
100 1         243 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   25 my $self = shift;
109 3         232 ( time - $self->_token_time ) < 890;
110             }
111              
112             sub _make_request {
113 2     2   5 my $self = shift;
114 2 50 33     76 sleep $REQUEST_LIMIT if $self->_last_request != -1 && time - $self->_last_request < $REQUEST_LIMIT;
115 2 50       57 unless ( $self->_token_valid ) {
116 0         0 $self->_token( $self->_renew_token );
117 0         0 sleep $REQUEST_LIMIT;
118             }
119 2         77 $self->_last_request(time);
120 2         6 my $url = $BASEURL;
121 2         23 foreach my $attribute ( $self->meta->get_attribute_list ) {
122 34 100       336 next if $attribute =~ /^_/;
123 24 100       737 if ( $self->$attribute ) {
124 9         253 $url .= "$attribute=" . $self->$attribute . "&";
125             }
126             }
127 2         58 $url .= "format=" . $self->_format . "&";
128 2         52 $url .= "ranked=" . $self->ranked . "&";
129 2         54 $url .= "token=" . $self->_token;
130 2         51 my $res_json = $self->_ua->get($url);
131 2 50       3172 if ( $res_json->is_success ) {
132 2         34 my $tresults = decode_json( $res_json->decoded_content );
133 2         327 my @res;
134 2 100 66     14 if ( $tresults->{torrent_results}
135 1         6 && scalar( @{ $tresults->{torrent_results} } ) > 1 )
136             {
137 1         3 foreach my $t ( @{ $tresults->{torrent_results} } ) {
  1         3  
138 2         78 my $t_obj = Rarbg::torrentapi::Res->new($t);
139 2         6 push @res, $t_obj;
140             }
141 1         10 return \@res;
142             }
143             else {
144 1         47 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   615 my $self = shift;
        2      
157 2         6 my $args = shift;
158 2         4 foreach my $key ( keys %{$args} ) {
  2         10  
159 1         41 $self->$key( $args->{$key} );
160             }
161 2         69 $self->mode("$method");
162 2         8 return $self->_make_request;
163             }
164             );
165             }
166              
167 1     1   7272 no Moose;
  1         2  
  1         5  
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