Rarbg-torrentapi

Perl Module to interact with https://torrentapi.org
git clone https://git.onna.be/Rarbg-torrentapi.git
Log | Files | Refs | README | LICENSE

commit d9198e3bd17bc5de8e421b30698b0546d02f712b
parent e74413ad245357879ebf88f1c2d6316bf52e2308
Author: Paco Esteban <paco@onna.be>
Date:   Tue,  8 Sep 2015 13:15:13 +0200

first working version

Diffstat:
cpanfile | 3+++
lib/Rarbg/torrentapi.pm | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
lib/Rarbg/torrentapi/Error.pm | 48++++++++++++++++++++++++++++++++++++++++++++++++
lib/Rarbg/torrentapi/Res.pm | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
t/basic.t | 17+++++++++++++++--
t/error.t | 24++++++++++++++++++++++++
t/res.t | 49+++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 403 insertions(+), 11 deletions(-)

diff --git a/cpanfile b/cpanfile @@ -1,7 +1,10 @@ requires 'perl', '5.008005'; requires 'Moose', '0'; +requires 'JSON', '0'; +requires 'LWP::UserAgent', '0'; on test => sub { requires 'Test::More', '0.96'; + requires 'JSON', '0'; }; diff --git a/lib/Rarbg/torrentapi.pm b/lib/Rarbg/torrentapi.pm @@ -3,14 +3,144 @@ package Rarbg::torrentapi; use strict; use 5.008_005; our $VERSION = '0.01'; +use LWP::UserAgent; +use JSON; +use Carp; +use Rarbg::torrentapi::Res; +use Rarbg::torrentapi::Error; use Moose; -sub search { - #body ... +our $BASEURL = 'https://torrentapi.org/pubapi_v2.php?'; + +has [qw(search_string search_imdb search_tvrage search_tvdb category)] => ( + is => 'rw', + isa => 'Str' +); + +has limit => ( + is => 'rw', + isa => 'Int', + default => 25 +); + +has sort => ( + is => 'rw', + isa => 'Str', + default => 'last' +); + +has [qw(min_seeders min_leechers)] => ( + is => 'rw', + isa => 'Int' +); + +has ranked => ( + is => 'rw', + isa => 'Int', + default => 0 +); + +has _mode => ( + is => 'rw', + isa => 'Str', + default => 'list' +); + +has _format => ( + is => 'ro', + isa => 'Str', + default => 'json_extended' +); + +has _ua => ( + is => 'ro', + default => sub { + LWP::UserAgent->new( agent => 'curl/7.44.0' ); + } +); + +has _token => ( + is => 'rw', + isa => 'Str', + default => sub { + my $self = shift; + $self->_renew_token(); + }, + required => 1, + lazy => 1 +); + +has _token_time => ( + is => 'rw', + isa => 'Int', + default => 1, +); + +sub _renew_token { + my $self = shift; + my $res_json = $self->_ua->get( $BASEURL . "get_token=get_token" ); + if ( $res_json->is_success ) { + $self->_token_time(time); + my $res = decode_json( $res_json->decoded_content ); + return $res->{token}; + } + else { + confess "Cannot get token " . $res_json->status_line; + } } -sub list { - #body ... +sub _token_valid { + my $self = shift; + ( time - $self->_token_time ) < 890; +} + +sub _make_request { + my $self = shift; + $self->_renew_token unless $self->_token_valid; + my $url = $BASEURL; + foreach my $attribute ( $self->meta->get_attribute_list ) { + next if $attribute =~ /^_/; + if ( $self->$attribute ) { + $url .= "$attribute=" . $self->$attribute . "&"; + } + } + $url .= "format=" . $self->_format . "&"; + $url .= "token=" . $self->_token; + my $res_json = $self->_ua->get($url); + if ( $res_json->is_success ) { + my $tresults = decode_json( $res_json->decoded_content ); + my @res; + if ( $tresults->{torrent_results} + && scalar( @{ $tresults->{torrent_results} } ) > 1 ) + { + foreach my $t ( @{ $tresults->{torrent_results} } ) { + my $t_obj = Rarbg::torrentapi::Res->new($t); + push @res, $t_obj; + } + return \@res; + } + else { + return Rarbg::torrentapi::Error->new($tresults); + } + } + else { + confess "Cannot execute Call " . $res_json->status_line; + } +} + +foreach my $method (qw/list search/) { + __PACKAGE__->meta->add_method( + $method, + sub { + my $self = shift; + my $args = shift; + foreach my $key ( keys %{$args} ) { + $self->$key( $args->{$key} ); + } + $self->_mode("$method"); + return $self->_make_request; + } + ); } no Moose; @@ -27,16 +157,86 @@ Rarbg::torrentapi - Wrapper around Rarbg torrentapi (https://torrentapi.org/apid =head1 SYNOPSIS use Rarbg::torrentapi; + my $tapi = Rarbg::torrentapi->new(); + + # list lastest torrents + my $last_added = $tapi->list(); + + # list torrents sorted by seeders + my $last_added = $tapi->list({ + sort => 'seeders', + limit => 50, + category => 'tv' + }); + + # search by string + # You can use all the attributes of list also + my $search = $tapi->search({ + search_string => 'the beatles', + category => '23;24;25;26', + min_seeders => 20 + }); + + # search by imdb id + my $search = $tapi->search({ + search_imdb => 'tt123456' + }); + + # search by tvrage id + my $search = $tapi->search({ + search_tvrage => '123456' + }); + + # search by tvdb id + my $search = $tapi->search({ + search_tvdb => '123456' + }); + =head1 DESCRIPTION -Rarbg::torrentapi is a simple wrapper around Rarbg's torrentapi (JSON format) +Rarbg::torrentapi is a simple wrapper around Rarbg's torrentapi. =head1 ATTRIBUTES -=head2 token +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. + +The only difference is that you should pass them as an anonymous hash if you pass them to a method. + +You can find more info about their values at https://torrentapi.org/apidocs_v2.txt + +=head2 search_string + +=head2 search_imdb + +This is the Imdb id (http://imdb.com) in the form 'tt123456' + +=head2 search_tvrage + +=head2 search_tvdb + +=head2 category + +Category can be quite confusing. +It accepts 'tv' and 'movies'. But, for the rest of categories only accepts its id numbers (or a semi-colon separated list of them). +Check Rarbg website to see what those are. They are not documented anywhere. + +=head2 limit + +It can be 25, 50 or 100. + +=head2 sort + +It can be seeders, leechers or last + +=head2 min_seeders + +=head2 min_leechers + +=head2 ranked -This attribute is ro. It's get automatically on every first request. It remains cached for further requests. As per API specification, it will expire in 15 minutes. +This marks if you want to get all indexed torrents or just the ones from rarbg team. +Defaults to all (0). =head1 METHODS @@ -46,11 +246,11 @@ Just a simple constructor. =head2 search -Calls Rarbg::torrentapi::Call and passes a Rarbg::torrentapi::Req formated for search. +Makes a call to the API in 'search' mode. It returns either a Rarbg::torrentapi::Error or an array of Rarbg::torrentapi::Res. =head2 list -Calls Rarbg::torrentapi::Call and passes a Rarbg::torrentapi::Req formated for list. +Makes a call to the API in 'list' mode. It returns either a Rarbg::torrentapi::Error or an array of Rarbg::torrentapi::Res. =head1 AUTHOR diff --git a/lib/Rarbg/torrentapi/Error.pm b/lib/Rarbg/torrentapi/Error.pm @@ -0,0 +1,48 @@ +package Rarbg::torrentapi::Error; + +use strict; +use 5.008_005; +our $VERSION = '0.01'; +use Moose; + +has 'error' => ( + is => 'ro', + isa => 'Str' +); + +has 'error_code' => ( + is => 'ro', + isa => 'Int' +); + +no Moose; +__PACKAGE__->meta->make_immutable; +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +Rarbg::torrentapi::Error - Error response class for Rarbg::torrentapi + +=head1 DESCRIPTION + +This is not meant to be used directly, see Rarbg::torrentapi + +=head1 AUTHOR + +Paco Esteban E<lt>paco@onna.beE<gt> + +=head1 COPYRIGHT + +Copyright 2015- Paco Esteban + +=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 diff --git a/lib/Rarbg/torrentapi/Res.pm b/lib/Rarbg/torrentapi/Res.pm @@ -0,0 +1,55 @@ +package Rarbg::torrentapi::Res; + +use strict; +use 5.008_005; +our $VERSION = '0.01'; +use Moose; + +has [qw( category download info_page pubdate title)] => ( + is => 'ro', + isa => 'Str' +); + +has [qw( seeders leechers ranked size)] => ( + is => 'ro', + isa => 'Int' +); + +has episode_info => ( + is => 'ro', + # sometimes we get undef, that breaks validation ... + # isa => 'HashRef', + # default => sub { {} } +); + +no Moose; +__PACKAGE__->meta->make_immutable; +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +Rarbg::torrentapi::Res - Response class for Rarbg::torrentapi + +=head1 DESCRIPTION + +This is not meant to be used directly, see Rarbg::torrentapi + +=head1 AUTHOR + +Paco Esteban E<lt>paco@onna.beE<gt> + +=head1 COPYRIGHT + +Copyright 2015- Paco Esteban + +=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 diff --git a/t/basic.t b/t/basic.t @@ -5,9 +5,22 @@ BEGIN { use_ok('Rarbg::torrentapi'); } -can_ok('Rarbg::torrentapi', qw( new search list )); +can_ok( 'Rarbg::torrentapi', + qw( new search list _renew_token _token_valid _make_request ) ); -my %attr = ( +my $tapi = new_ok('Rarbg::torrentapi'); +like( $tapi->_token, qr/\w{10}/, 'Token test' ); +diag( "I got token " . $tapi->_token ); +ok( $tapi->_token_valid, 'Token time test' ); +ok( $tapi->ranked == 0 ); +is( $tapi->_format, 'json_extended' ); +my $list = $tapi->list; +isa_ok( $list->[0], 'Rarbg::torrentapi::Res' ); +my $res = $tapi->search( + { + search_string => 'qwerasdf' + } ); +isa_ok( $res, 'Rarbg::torrentapi::Error' ); done_testing; diff --git a/t/error.t b/t/error.t @@ -0,0 +1,24 @@ +use strict; +use Test::More; +use JSON; + +BEGIN { + use_ok('Rarbg::torrentapi::Error'); +} + +# Testing Rarbg::torrentapi::Error methods and attributes +can_ok( 'Rarbg::torrentapi::Error', ('new') ); +can_ok( 'Rarbg::torrentapi::Error', qw( error error_code ) ); +my $error_msg = <<ERR; +{ + "error": "No results found", + "error_code": 20 +} +ERR +my $error_res = decode_json($error_msg); +my $error = Rarbg::torrentapi::Error->new($error_res); + +ok( $error->error_code == 20, 'Error code check' ); +is( $error->error, 'No results found', 'Error message check' ); + +done_testing; diff --git a/t/res.t b/t/res.t @@ -0,0 +1,49 @@ +use strict; +use Test::More; +use JSON; + +BEGIN { + use_ok('Rarbg::torrentapi::Res'); +} + +# Testing Rarbg::torrentapi::Res methods and attributes +can_ok( 'Rarbg::torrentapi::Res', ('new') ); +can_ok( 'Rarbg::torrentapi::Res', + qw( category download info_page pubdate title) ); +can_ok( 'Rarbg::torrentapi::Res', qw( seeders leechers ranked size) ); +can_ok( 'Rarbg::torrentapi::Res', ('episode_info') ); +my $res_msg = <<RES; + { + "category": "TV Episodes", + "download": "magnet:?xt=urn:btih:edbd27c890411a5e5659e9ae0daf631edc2d8ab7&dn=Star.Wars.Rebels.S01E13.HDTV.x264-BATV%5Brartv%5D&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce", + "episode_info": { + "airdate": "2015-03-02", + "epnum": "13", + "imdb": "tt2930604", + "seasonnum": "1", + "title": "Fire Across the Galaxy", + "tvdb": "283468", + "tvrage": "35995" + }, + "info_page": "https://torrentapi.org/redirect_to_info.php?token=d6fpv3lrij&p=8_0_4_9_2_2__edbd27c890", + "leechers": 0, + "pubdate": "2015-03-03 02:33:40 +0000", + "ranked": 1, + "seeders": 0, + "size": 188491315, + "title": "Star.Wars.Rebels.S01E13.HDTV.x264-BATV[rartv]" + } +RES +my $res_res = decode_json($res_msg); +my $res = Rarbg::torrentapi::Res->new($res_res); + +ok( $res->size == 188491315, 'Response int value test' ); +is( + $res->title, + 'Star.Wars.Rebels.S01E13.HDTV.x264-BATV[rartv]', + 'Response String value test' +); +isa_ok( $res->episode_info, 'HASH' ); +is( $res->episode_info->{imdb}, 'tt2930604', 'Episode info hash test' ); + +done_testing;