From: diegok Date: Tue, 25 Dec 2012 22:08:40 +0000 (+0100) Subject: Initial commit X-Git-Tag: v0.01~3 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fwww-eztv.git;a=commitdiff_plain;h=70a4c8fadae7e062e72a9ed4c19c3a2f6dac4cc8 Initial commit --- 70a4c8fadae7e062e72a9ed4c19c3a2f6dac4cc8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..d608452 --- /dev/null +++ b/dist.ini @@ -0,0 +1,41 @@ +name = WWW::EZTV +author = Diego Kuperman +license = Perl_5 +copyright_holder = Diego Kuperman +copyright_year = 2012 + +[@Basic] +[@Git] + +[AutoPrereqs] + +[Git::NextVersion] +first_version = 0.01 + +[PkgVersion] +[MetaConfig] +[MetaJSON] +[NextRelease] +[PodSyntaxTests] +[PodCoverageTests] +[PodWeaver] + +[MetaResources] +repository.web = http://github.com/diegok/www-eztv +repository.url = http://github.com/diegok/www-eztv +repository.type = git + +[GithubMeta] +user = diegok +issues = 1 + +;[ReadmeAnyFromPod] +; Default is plaintext README in build dir + +;[ReadmeAnyFromPod / ReadmePodInRoot] +;type = pod +;filename = README.pod +;location = root + +[Prereqs / TestRequires] +Test::More = 0.96 diff --git a/lib/WWW/EZTV.pm b/lib/WWW/EZTV.pm new file mode 100644 index 0000000..67debca --- /dev/null +++ b/lib/WWW/EZTV.pm @@ -0,0 +1,32 @@ +package WWW::EZTV; +use Moose; +with 'WWW::EZTV::UA'; +use WWW::EZTV::Show; + +has url => ( is => 'ro', lazy => 1, default => sub { Mojo::URL->new('http://eztv.it/') } ); +has url_shows => ( is => 'ro', lazy => 1, default => sub { shift->url->clone->path('/showlist/') } ); +has shows => + is => 'ro', + lazy => 1, + default => \&build_shows, + handles => { + find_show => 'first', + has_shows => 'size', + }; + +sub build_shows { + my $self = shift; + + $self->get_response( $self->url_shows )->dom->find('table.forum_header_border tr[name="hover"]')->map(sub { + my $tr = shift; + my $link = $tr->at('td:nth-child(1) a'); + WWW::EZTV::Show->new( + title => $link->all_text, + url => $self->url->clone->path($link->attrs('href')), + status => lc($tr->at('td:nth-child(2)')->all_text), + rating => $tr->at('td:nth-child(3)')->all_text + ); + }); +} + +1; diff --git a/lib/WWW/EZTV/Episode.pm b/lib/WWW/EZTV/Episode.pm new file mode 100644 index 0000000..0f2ffa2 --- /dev/null +++ b/lib/WWW/EZTV/Episode.pm @@ -0,0 +1,70 @@ +package WWW::EZTV::Episode; +use Moose; +with 'WWW::EZTV::UA'; + +# ABSTRACT: EZTV single episode + +has show => is => 'ro', isa => 'WWW::EZTV::Show', required => 1; +has title => is => 'ro', isa => 'Str', required => 1; +has url => is => 'ro', isa => 'Mojo::URL', required => 1; +has links => is => 'rw'; + +has _parsed => is => 'ro', lazy => 1, builder => '_parse'; + +has name => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{name} }; + +has season => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{season} }; + +has number => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{number} }; + +has version => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{version} }; + +has quality => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{quality} || 'standard' }; + +has size => is => 'ro', lazy => 1, + default => sub { shift->_parsed->{size} }; + +sub _parse { + my $title = shift->title; + + $title =~ /^\s* + (?.+?) + \s+ + (? + S (?\d+) E (?\d+) + |(?\d+) x (?\d+) + |(?\d+) of (?\d+) + ) + \s+ + (? + ((?\d+p)\s+)? + (?.*?) + ) + (?: + \s+ + \((? + \d+ + [^\)]+ + )\) + )? + \s*$/xi; + + return { + name => $+{name} || $title, + chapter => $+{chapter}, + number => $+{number} +0, + season => ($+{season}||0) +0, + total => ($+{total}||0) +0, + version => $+{version} || '', + quality => $+{quality} || 'standard', + team => $+{team}, + size => $+{size} + }; +} + +1; diff --git a/lib/WWW/EZTV/Link.pm b/lib/WWW/EZTV/Link.pm new file mode 100644 index 0000000..065544b --- /dev/null +++ b/lib/WWW/EZTV/Link.pm @@ -0,0 +1,9 @@ +package WWW::EZTV::Link; +use Moose; +with 'WWW::EZTV::UA'; + +# ABSTRACT: EZTV episode link + +has url => is => 'ro', isa => 'Str', required => 1; + +1; diff --git a/lib/WWW/EZTV/Show.pm b/lib/WWW/EZTV/Show.pm new file mode 100644 index 0000000..433b4e7 --- /dev/null +++ b/lib/WWW/EZTV/Show.pm @@ -0,0 +1,102 @@ +package WWW::EZTV::Show; +use Moose; +with 'WWW::EZTV::UA'; +use WWW::EZTV::Link; +use WWW::EZTV::Episode; + +# ABSTRACT: EZTV show object + +has title => is => 'ro', isa => 'Str', required => 1; +has name => is => 'ro', lazy => 1, default => \&_name; +has year => is => 'ro', lazy => 1, default => \&_year; +has url => is => 'ro', isa => 'Mojo::URL', required => 1; +has status => is => 'ro', isa => 'Str', required => 1; +has rating => is => 'ro', isa => 'Int', default => sub {0}; +has episodes => + is => 'ro', + lazy => 1, + builder => '_build_episodes', + handles => { + find_episode => 'first', + has_episodes => 'size', + }; + +sub _build_episodes { + my $self = shift; + $self->get_response($self->url)->dom->find('table.forum_header_noborder tr[name="hover"]')->map(sub{ + my $tr = shift; + my $a = $tr->at('td:nth-child(2) a'); + + WWW::EZTV::Episode->new( + title => $a->attrs('title'), + url => $self->url->clone->path($a->attrs('href')), + links => $tr->find('td:nth-child(3) a')->map(sub{ + WWW::EZTV::Link->new( url => shift->attrs('href') ) + }), + released => $tr->at('td:nth-child(4)')->all_text, + show => $self + ); + }); +} + +sub _name { + my $self = shift; + my $name = $self->title; + + # Chasers War on Everything, The + if ( $name =~ /^(.+),\s*([^,]+)$/ ) { $name = "$2 $1" } + + # Remove year: Castle (2009) + $name =~ s/\s* \(\d{4}\) \s*/ /x; + + # Trim and cleanup spaces + $self->_cleanup_str($name); +} + +sub _year { + my $self = shift; + if ( $self->title =~ /\((\d{4})\)/ ) { + return $1; + } +} + +sub _cleanup_str { + my $str = pop; + $str =~ s/^\s+|\s+$//g; + $str =~ s/\s+/ /g; + $str; +} + +1; + +=attr title +=cut + +=attr name +=cut + +=attr year +=cut + +=attr url +=cut + +=attr status +=cut + +=attr rating +=cut + +=attr episodes +Collection of episodes fetched for this show. +=cut + +=attr has_episodes +How many episodes has this show. +=cut + +=method find_episode +Find first L object matching the given criteria. +This method accept an anon function. +=cut + diff --git a/lib/WWW/EZTV/UA.pm b/lib/WWW/EZTV/UA.pm new file mode 100644 index 0000000..f2fbeeb --- /dev/null +++ b/lib/WWW/EZTV/UA.pm @@ -0,0 +1,21 @@ +package WWW::EZTV::UA; +use Moose::Role; +use Mojo::UserAgent; + +has ua => ( is => 'ro', lazy => 1, default => sub { $EZTV::Global::UA || ($EZTV::Global::UA = Mojo::UserAgent->new) } ); + +sub get_response { + my ($self, $url) = (shift, shift); + + my $tx = $self->ua->get( $url ); + if ( my $res = $tx->success ) { + return $res; + } + else { + my ($err, $code) = $tx->error; + my $message = shift || 'User agent error'; + die "$message: $err ($code)"; + } +} + +1; diff --git a/t/01-series.t b/t/01-series.t new file mode 100755 index 0000000..25d130d --- /dev/null +++ b/t/01-series.t @@ -0,0 +1,45 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; + +BEGIN { use_ok( 'WWW::EZTV' ); } + +ok( my $eztv = WWW::EZTV->new, 'Build eztv crawler' ); +isa_ok( $eztv->shows, 'Mojo::Collection' ); +isa_ok( $eztv->shows->[0], 'WWW::EZTV::Show' ); + +subtest 'All shows has name and URL' => sub { + my $has_year = 0; + $eztv->shows->each(sub { + my $show = shift; + ok( $show->name, 'Found show ' . $show->name ); + ok( $show->url, 'Has url ' . $show->url ); + ok( $show->status, 'Has status ' . $show->status ); + $has_year++ if $show->year; + }); + ok( $has_year, "Some shows has year info" ); +}; + +subtest 'Show object' => sub { + ok( my $show = $eztv->shows->[0], 'Pick first show' ); + diag( $show->name . ' was choosen!' ); + ok( $show->has_episodes, 'Has episodes' ); + ok( $show->episodes, 'Retrieve episodes' ); + $show->episodes->each(sub{ + my $ep = shift; + diag( 'Title: '. $ep->title ); + diag( 'Name: '. $ep->name ); + diag( 'Season: '. $ep->season ); + diag( 'Number: '. $ep->number ); + diag( 'Version: '. $ep->version ); + diag( 'Size: '. $ep->size ); + ok( $ep->season >= 1, 'Has season' ); + ok( $ep->number >= 1, 'Has number' ); + + ok( my $link = $ep->links->[0], 'Get first link' ); + ok( $link->url, 'Link has url' ); + }); +}; + +done_testing(); diff --git a/t/02-find.t b/t/02-find.t new file mode 100644 index 0000000..37d6a6e --- /dev/null +++ b/t/02-find.t @@ -0,0 +1,29 @@ +#!/usr/bin/env perl + +use strict; +use Test::More; + +BEGIN { use_ok( 'WWW::EZTV' ); } + +ok( my $eztv = WWW::EZTV->new, 'Build eztv crawler' ); + +my $show; + +subtest 'Find a show' => sub { + ok( $eztv->has_shows, 'Can fetch shows list' ); + ok( $show = $eztv->find_show(sub{ $_->name =~ /Walking dead/i }), 'Find a known show' ); + is( $show->name, 'The Walking Dead', 'Name looks good' ); + ok( $show->url, 'Has url ' . $show->url ); + ok( $show->status, 'Has status ' . $show->status ); +}; + +subtest 'Find episodes' => sub { + ok( $show->has_episodes, 'Show fetch show episodes' ); + ok( my $ep = $show->find_episode(sub{ $_->season == 3 && $_->number == 8 && $_->quality eq 'standard' }), 'Find a known episode' ); + diag( 'Title: ' . $ep->title ); + diag( 'Version: ' . $ep->version ); + diag( 'Size: ' . $ep->size ); + is( $ep->name, 'The Walking Dead', 'Name looks good' ); +}; + +done_testing();