Initial commit
authordiegok <diego@freekeylabs.com>
Tue, 25 Dec 2012 22:08:40 +0000 (23:08 +0100)
committerdiegok <diego@freekeylabs.com>
Tue, 25 Dec 2012 22:08:40 +0000 (23:08 +0100)
.gitignore [new file with mode: 0644]
dist.ini [new file with mode: 0644]
lib/WWW/EZTV.pm [new file with mode: 0644]
lib/WWW/EZTV/Episode.pm [new file with mode: 0644]
lib/WWW/EZTV/Link.pm [new file with mode: 0644]
lib/WWW/EZTV/Show.pm [new file with mode: 0644]
lib/WWW/EZTV/UA.pm [new file with mode: 0644]
t/01-series.t [new file with mode: 0755]
t/02-find.t [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1377554
--- /dev/null
@@ -0,0 +1 @@
+*.swp
diff --git a/dist.ini b/dist.ini
new file mode 100644 (file)
index 0000000..d608452
--- /dev/null
+++ b/dist.ini
@@ -0,0 +1,41 @@
+name    = WWW::EZTV
+author  = Diego Kuperman <diego@freekeylabs.com>
+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 (file)
index 0000000..67debca
--- /dev/null
@@ -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 (file)
index 0000000..0f2ffa2
--- /dev/null
@@ -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*
+      (?<name>.+?)
+      \s+
+      (?<chapter>
+        S (?<season>\d+) E (?<number>\d+)
+       |(?<season>\d+) x (?<number>\d+)
+       |(?<number>\d+) of (?<total>\d+)
+      )
+      \s+
+      (?<version>
+        ((?<quality>\d+p)\s+)?
+        (?<team>.*?)
+      )
+      (?: 
+        \s+
+        \((?<size> 
+          \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 (file)
index 0000000..065544b
--- /dev/null
@@ -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 (file)
index 0000000..433b4e7
--- /dev/null
@@ -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<WWW::EZTV::Episode> 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 (file)
index 0000000..f2fbeeb
--- /dev/null
@@ -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 (executable)
index 0000000..25d130d
--- /dev/null
@@ -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 (file)
index 0000000..37d6a6e
--- /dev/null
@@ -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();