From: Marius Gavrilescu Date: Sun, 15 Mar 2015 10:05:03 +0000 (+0200) Subject: Initial commit X-Git-Tag: 0.001 X-Git-Url: http://git.ieval.ro/?a=commitdiff_plain;h=8cd8ac7b32cecdffd5fe44b284d0a82ddd03421b;p=webservice-strike.git Initial commit --- 27da1d36f6be05af35e74a57848cabf138cf3fc3 diff --git a/Changes b/Changes new file mode 100644 index 0000000..3678ea0 --- /dev/null +++ b/Changes @@ -0,0 +1,4 @@ +Revision history for Perl extension WebService::Strike. + +0.001 2015-03-15T12:05 + - Initial release diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..2bfcc0f --- /dev/null +++ b/MANIFEST @@ -0,0 +1,10 @@ +Changes +Makefile.PL +MANIFEST +README +t/WebService-Strike.t +t/WebService-Strike-Torrent.t +t/perlcritic.t +t/perlcriticrc +lib/WebService/Strike.pm +lib/WebService/Strike/Torrent.pm diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..494aabf --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,28 @@ +use 5.014000; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'WebService::Strike', + VERSION_FROM => 'lib/WebService/Strike.pm', + ABSTRACT_FROM => 'lib/WebService/Strike.pm', + AUTHOR => 'Marius Gavrilescu ', + MIN_PERL_VERSION => '5.14.0', + LICENSE => 'perl', + SIGN => 1, + BUILD_REQUIRES => { + qw/Test::RequiresInternet 0 + Try::Tiny 0/, + }, + PREREQ_PM => { + qw/Date::Parse 0 + JSON::MaybeXS 0 + Sort::ByExample 0 + URI::Escape 0/, + }, + META_ADD => { + dynamic_config => 0, + resources => { + repository => 'http://git.ieval.ro/?p=webservice-strike.git', + } + } +); diff --git a/README b/README new file mode 100644 index 0000000..73a6258 --- /dev/null +++ b/README @@ -0,0 +1,32 @@ +WebService-Strike version 0.001 +=============================== + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + +* Test::RequiresInternet +* Try::Tiny +* Date::Parse +* JSON::MaybeXS +* Sort::ByExample +* URI::Escape + +COPYRIGHT AND LICENCE + +Copyright (C) 2015 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.20.2 or, +at your option, any later version of Perl 5 you may have available. + + diff --git a/lib/WebService/Strike.pm b/lib/WebService/Strike.pm new file mode 100644 index 0000000..8ff1e55 --- /dev/null +++ b/lib/WebService/Strike.pm @@ -0,0 +1,91 @@ +package WebService::Strike; + +use 5.014000; +use strict; +use warnings; +use parent qw/Exporter/; + +our @EXPORT = qw/strike/; ## no critic (ProhibitAutomaticExportation) +our @EXPORT_OK = qw/strike_query strike/; +our $VERSION = '0.001'; +our $BASE_URL = 'http://getstrike.net/api/torrents/'; + +use JSON::MaybeXS qw/decode_json/; +use HTTP::Tiny; +use Sort::ByExample qw/sbe/; +use WebService::Strike::Torrent; + +sub _ht { HTTP::Tiny->new(agent => "WebService-Strike/$VERSION") } + +sub strike_query { + my (@hashes) = @_; + my $url = "$BASE_URL/info/?hashes=" . join ',', map { uc } @hashes; + my $ht = _ht; + my $response = $ht->get($url); + die $response unless $response->{success}; ## no critic (RequireCarping) + $response = decode_json $response->{content}; + + die $response unless ref $response eq 'ARRAY'; ## no critic (RequireCarping) + my $sorter = sbe(\@hashes, {xform => sub { $_[0]->hash }}); + my @torrents = map { WebService::Strike::Torrent->new($_) } @{$response->[1]}; + @torrents = $sorter->(@torrents); + wantarray ? @torrents : $torrents[0] +} + +BEGIN { *strike = \&strike_query } + +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +WebService::Strike - Get torrent info from getstrike.net API + +=head1 SYNOPSIS + + use WebService::Strike; + my $t = strike 'B425907E5755031BDA4A8D1B6DCCACA97DA14C04'; + say $t->title; # Arch Linux 2015.01.01 (x86\/x64) + say $t->magnet; # Returns a magnet link + my $torrent = $t->torrent; # Returns the torrent file + $t->torrent('file.torrent'); # Downloads the torrent file to 'file.torrent' + +=head1 DESCRIPTION + +Strike API is a service for getting information about a torrent given +its info hash. WebService::Strike is a wrapper for this service. + +=over + +=item B(I<@info_hashes>) + +Returns a list of hashrefs, one for each info hash. The hashrefs are +blessed into the L package. Dies in case +of error. + +=item B + +Alias for B. Not exported by default. + +=back + +=head1 SEE ALSO + +L, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2015 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.20.2 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/lib/WebService/Strike/Torrent.pm b/lib/WebService/Strike/Torrent.pm new file mode 100644 index 0000000..8c8a894 --- /dev/null +++ b/lib/WebService/Strike/Torrent.pm @@ -0,0 +1,179 @@ +package WebService::Strike::Torrent; + +use 5.014000; +use strict; +use warnings; +use parent qw/Class::Accessor::Fast/; + +our $VERSION = '0.001'; + +use Date::Parse qw/str2time/; +use JSON::MaybeXS qw/decode_json/; +use URI::Escape qw/uri_escape/; +use WebService::Strike; + +__PACKAGE__->mk_ro_accessors(qw/torrent_hash torrent_title torrent_category sub_category seeds leeches file_count size upload_date uploader_username file_info file_names file_lengths/); + +BEGIN { + *hash = *torrent_hash; + *title = *torrent_title; + *category = *torrent_category; + *count = *file_count; + *date = *upload_date; + *uploader = *uploader_username; + *names = *file_names; + *lengths = *file_lengths; +}; + +sub new{ + my ($self, @args) = @_; + $self = $self->SUPER::new(@args); + $self->{torrent_hash} = uc $self->hash; + $self->{upload_date} = str2time $self->date; + $self->{file_names} = $self->file_info->[0]->{file_names}; + $self->{file_lengths} = $self->file_info->[0]->{file_lengths}; + $self +} + +sub magnet{ + my ($self) = @_; + 'magnet:?xt=urn:btih:' . $self->hash . '&dn=' . uri_escape $self->title +} + +sub torrent{ + my ($self, $file) = @_; + my $url = $WebService::Strike::BASE_URL . '/downloads/?hash=' . $self->hash; + my $ht = WebService::Strike::_ht(); ## no critic (ProtectPrivate) + my $response = $ht->get($url); + return unless $response->{success}; + $response = decode_json $response->{content}; + $url = $response->{message}; + + if (defined $file) { + $response = $ht->mirror($url, $file); + return $response->{success} + } else { + $response = $ht->get($url); + return $response->{success} && $response->{content} + } +} + +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +WebService::Strike::Torrent - Class representing information about a torrent + +=head1 SYNOPSIS + + use WebService::Strike; + my $t = strike 'B425907E5755031BDA4A8D1B6DCCACA97DA14C04'; + say $t->hash; # B425907E5755031BDA4A8D1B6DCCACA97DA14C04 + say $t->title; # Arch Linux 2015.01.01 (x86/x64) + say $t->category; # Applications + say $t->sub_category; # '' (empty string) + say $t->seeds; + say $t->leeches; + say $t->count; # 1 + say $t->size; # 587 MB + say $t->date; # 1420495200 + say $t->uploader; # The_Doctor- + say @{$t->names}; # archlinux-2015.01.01-dual.iso + say @{$t->lengths}; # 615514112 + say $t->magnet; # magnet:?xt=urn:btih:B425907E5755031BDA4A8D1B6DCCACA97DA14C04&dn=Arch%20Linux%202015.01.01%20%28x86%2Fx64%29 + my $tor = $t->torrent; # $torrent contains the torrent file contents + $t->torrent('x.torrent'); # Download torrent file to x.torrent + +=head1 DESCRIPTION + +WebService::Strike::Torrent is a class that represents information +about a torrent. + +Methods: + +=over + +=item B, B + +The info_hash of the torrent. + +=item B, B<torrent_title> + +The title of the torrent. + +=item B<category>, B<torrent_category> + +The category of the torrent. + +=item B<sub_category> + +The subcategory of the torrent. + +=item B<seeds> + +The number of seeders. + +=item B<leeches> + +The number of leechers. + +=item B<count>, B<file_count> + +The number of files contained in the torrent. + +=item B<size> + +The total size of the files in the torrent as a human-readable string. +See B<file_lengths> for exact sizes. + +=item B<date>, B<upload_date> + +Unix timestamp when the torrent was uploaded, with precision of one day. + +=item B<uploader>, B<uploader_username> + +Username of the user who uploaded the torrent. + +=item B<file_names> + +Arrayref of paths of files in the torrent. + +=item B<file_lengths> + +Arrayref of lengths of files in the torrent, in bytes. + +=item B<magnet> + +Magnet link for the torrent. + +=item B<torrent>([I<$filename>]) + +Downloads the torrent from Strike. With no arguments, returns the +contents of the torrent file. With an argument, stores the torrent in +I<$filename>. + +Both forms return a true value for success and false for failure. + +=back + +=head1 SEE ALSO + +L<WebService::Strike>, L<http://getstrike.net/api/> + +=head1 AUTHOR + +Marius Gavrilescu, E<lt>marius@ieval.roE<gt> + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2015 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.20.2 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/t/WebService-Strike-Torrent.t b/t/WebService-Strike-Torrent.t new file mode 100644 index 0000000..9787119 --- /dev/null +++ b/t/WebService-Strike-Torrent.t @@ -0,0 +1,39 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test::More tests => 14; +BEGIN { use_ok('WebService::Strike::Torrent') } + +my %data = ( + leeches => 13, + size => '587 MB', + torrent_hash => 'b425907e5755031bda4a8d1b6dccaca97da14c04', + file_count => 1, + sub_category => '', + torrent_category => 'Applications', + file_info => [{ + file_names => [ 'archlinux-2015.01.01-dual.iso' ], + file_lengths => [ 615514112 ], + }], + upload_date => 'Jan 6, 2015', + seeds => 645, + uploader_username => 'The_Doctor-', + torrent_title => 'Arch Linux 2015.01.01 (x86/x64)' +); + +my $t = WebService::Strike::Torrent->new(\%data); + +is $t->hash, 'B425907E5755031BDA4A8D1B6DCCACA97DA14C04', 'hash'; +is $t->title, 'Arch Linux 2015.01.01 (x86/x64)', 'title'; +is $t->category, 'Applications', 'category'; +is $t->sub_category, '', 'sub_category'; +is $t->seeds, 645, 'seeds'; +is $t->leeches, 13, 'leeches'; +is $t->count, 1, 'count'; +is $t->size, '587 MB', 'size'; +is $t->date, 1420495200,'date'; +is $t->uploader, 'The_Doctor-', 'uploader'; +is $t->names->[0], 'archlinux-2015.01.01-dual.iso', 'names'; +is $t->lengths->[0], 615514112, 'lengths'; +is $t->magnet, 'magnet:?xt=urn:btih:B425907E5755031BDA4A8D1B6DCCACA97DA14C04&dn=Arch%20Linux%202015.01.01%20%28x86%2Fx64%29', 'magnet'; diff --git a/t/WebService-Strike.t b/t/WebService-Strike.t new file mode 100644 index 0000000..ffd59ad --- /dev/null +++ b/t/WebService-Strike.t @@ -0,0 +1,27 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test::RequiresInternet qw/getstrike.net 80/; +use Test::More tests => 6; +use Try::Tiny; +BEGIN { use_ok('WebService::Strike') }; + +my ($t1, $t2, $t3) = strike qw/B425907E5755031BDA4A8D1B6DCCACA97DA14C04 5D4FD5A64E436A831383773F85FB38B888B9ECC9 85DF191A921C20B2DDAFF72368CAB93BA18C5ACE/; + +subtest 'order' => sub { + plan tests => 3; + is $t1->hash, 'B425907E5755031BDA4A8D1B6DCCACA97DA14C04', 'hash #1'; + is $t2->hash, '5D4FD5A64E436A831383773F85FB38B888B9ECC9', 'hash #2'; + is $t3->hash, '85DF191A921C20B2DDAFF72368CAB93BA18C5ACE', 'hash #3' +}; + +is $t1->date, 1420495200, 'date'; +is $t2->title, 'FreeBSD 7.1 i386.DVD.iso', 'title'; +like $t1->torrent, qr/^d/, 'torrent file starts with d'; + +try { + strike 'aaa'; +} catch { + is $_->{status}, 404, 'non-existent torrent status is 404'; +}; diff --git a/t/perlcritic.t b/t/perlcritic.t new file mode 100644 index 0000000..79e93dc --- /dev/null +++ b/t/perlcritic.t @@ -0,0 +1,10 @@ +#!/usr/bin/perl +use v5.14; +use warnings; + +use Test::More; + +BEGIN { plan skip_all => '$ENV{RELEASE_TESTING} is false' unless $ENV{RELEASE_TESTING} } +use Test::Perl::Critic -profile => 't/perlcriticrc'; + +all_critic_ok 'lib' diff --git a/t/perlcriticrc b/t/perlcriticrc new file mode 100644 index 0000000..96564fe --- /dev/null +++ b/t/perlcriticrc @@ -0,0 +1,35 @@ +severity = 1 + +[-BuiltinFunctions::ProhibitComplexMappings] +[-CodeLayout::RequireTidyCode] +[-ControlStructures::ProhibitPostfixControls] +[-ControlStructures::ProhibitUnlessBlocks] +[-Documentation::PodSpelling] +[-Documentation::RequirePodLinksIncludeText] +[-InputOutput::RequireBracedFileHandleWithPrint] +[-References::ProhibitDoubleSigils] +[-RegularExpressions::ProhibitEnumeratedClasses] +[-RegularExpressions::RequireLineBoundaryMatching] +[-Subroutines::RequireFinalReturn] +[-ValuesAndExpressions::ProhibitConstantPragma] +[-ValuesAndExpressions::ProhibitEmptyQuotes] +[-ValuesAndExpressions::ProhibitLeadingZeros] +[-ValuesAndExpressions::ProhibitMagicNumbers] +[-ValuesAndExpressions::ProhibitNoisyQuotes] +[-Variables::ProhibitLocalVars] +[-Variables::ProhibitPackageVars] +[-Variables::ProhibitPunctuationVars] + +[BuiltinFunctions::ProhibitStringyEval] +allow_includes = 1 + +[RegularExpressions::RequireExtendedFormatting] +minimum_regex_length_to_complain_about = 20 + +[Documentation::RequirePodSections] +lib_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE +script_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE + +[Subroutines::RequireArgUnpacking] +short_subroutine_statements = 5 +allow_subscripts = 1