File Coverage

blib/lib/WebService/MoviePosterDB.pm
Criterion Covered Total %
statement 109 122 89.3
branch 26 44 59.0
condition 18 26 69.2
subroutine 14 14 100.0
pod 2 2 100.0
total 169 208 81.2


line stmt bran cond sub pod time code
1             # $Id: MoviePosterDB.pm 6486 2011-06-13 13:42:02Z chris $
2              
3             =head1 NAME
4              
5             WebService::MoviePosterDB - OO Perl interface to the movie poster database MoviePosterDB.
6              
7              
8             =head1 SYNOPSIS
9              
10             use WebService::MoviePosterDB;
11              
12             my $ws = WebService::MoviePosterDB->new(api_key => "key", api_secret => "secret", cache => 1, cache_exp => "12h");
13              
14             my $movie = $ws->search(type => "Movie", imdbid => "tt0114814", width => 300);
15              
16             print $movie->title(), ": \n\n";
17             print $movie->page(), "\n\n";
18              
19             foreach ( @{$movie->posters()} ) {
20             print $_->image_location(), "\n";
21             }
22              
23              
24             =head1 DESCRIPTION
25              
26             WebService::MusicBrainz is an object-oriented interface to MoviePosterDB. It can
27             be used to retrieve artwork for IMDB titles.
28              
29             =cut
30              
31              
32             package WebService::MoviePosterDB;
33              
34 1     1   22373 use strict;
  1         2  
  1         31  
35 1     1   5 use warnings;
  1         1  
  1         85  
36              
37             our $VERSION = '0.18';
38              
39 1     1   823 use Cache::FileCache;
  1         129705  
  1         46  
40              
41 1     1   8 use Carp;
  1         2  
  1         62  
42              
43 1     1   6 use Digest::MD5 qw(md5_hex);
  1         1  
  1         48  
44              
45 1     1   5 use File::Spec::Functions qw(tmpdir);
  1         2  
  1         53  
46              
47 1     1   1128 use JSON;
  1         18065  
  1         6  
48 1     1   10622 use LWP::UserAgent;
  1         88844  
  1         39  
49 1     1   11 use URI;
  1         2  
  1         135  
50              
51 1     1   696 use WebService::MoviePosterDB::Movie;
  1         4  
  1         8  
52              
53             =head1 METHODS
54              
55             =head2 new(%opts)
56              
57             Constructor.
58              
59             %opts can contain:
60              
61             =over 4
62              
63             =item api_key, api_secret
64              
65             A key and secret are required to use the API. Contact movieposterdb.com for details.
66              
67             =item cache
68              
69             Whether to cache responses. Defaults to true
70              
71             =item cache_root
72              
73             The root dir for the cache. Defaults to tmpdir();
74              
75             =item cache_exp
76              
77             How long to cache responses for. Defaults to "1h"
78              
79             =back
80              
81             =cut
82              
83             sub new {
84 5     5 1 2524 my $class = shift;
85 5         14 my %args = @_;
86 5         11 my $self = {};
87              
88 5         11 bless $self, $class;
89              
90 5 100 100     57 if ((!exists $args{'api_version'} || !defined $args{'api_version'} || $args{'api_version'} == 1) && !exists $args{'api_key'}) {
      100        
91 2         365 carp "version 1 API is no longer available, using demo credentials";
92 2         17 $self->{'api_key'} = "demo";
93 2         5 $self->{'api_secret'} = "demo";
94             } else {
95 3         45 $self->{'api_key'} = $args{'api_key'};
96 3         8 $self->{'api_secret'} = $args{'api_secret'};
97             }
98              
99 5 100 66     42 if (!defined $self->{'api_key'} || !defined $self->{'api_secret'}) {
100 2         240 croak "api_key and/or api_secret missing";
101             }
102              
103 3   33     21 $self->{'_cache_root'} = $args{'cache_root'} || tmpdir();
104 3   50     146 $self->{'_cache_exp'} = $args{'cache_exp'} || "1h";
105 3 50       10 $self->{'_cache'} = defined $args{'cache'} ? $args{'cache'} : 1;
106              
107 3 50       13 if ($self->{'_cache'}) {
108 3         33 $self->{'_cacheObj'} = Cache::FileCache->new( {'cache_root' => $self->{'_cache_root'}, 'namespace' => "WebService-MoviePosterDB", 'default_expires_in' => $self->{'_cache_exp'}} );
109             }
110              
111 3         847 $self->{'_useragent'} = LWP::UserAgent->new();
112 3         30469 $self->{'_useragent'}->env_proxy();
113 3         152293 $self->{'_useragent'}->agent("WebService::MoviePosterDB/$VERSION");
114              
115 3         249 return $self;
116             }
117              
118              
119             =head2 search(type => "Movie", %args)
120              
121             Accesses MoviePosterDB and returns a WebService::MoviePosterDB::Movie object.
122              
123             %args can contain:
124              
125             =over 4
126              
127             =item type
128              
129             Controls the type of resource being requested. Currently only supports "Movie".
130              
131             =item tconst
132              
133             IMDB id for the title, e.g. tt0114814
134              
135             =item imdbid
136              
137             Alias for tconst
138              
139             =item title
140              
141             Name of the title
142              
143             =item width
144              
145             Image width for returned artwork
146              
147             =back
148              
149             =cut
150              
151             sub search {
152 5     5 1 26966 my $self = shift;
153 5         29 my %args = @_;
154              
155 5 50       28 croak "Unknown type" unless ($args{'type'} eq "Movie");
156              
157 5         11 my %_args;
158              
159 5 100 100     46 if (exists $args{'imdb_code'}) {
    100          
160 1         6 $_args{'imdb_code'} = sprintf("%d", $args{'imdb_code'}); # Trim leading zeroes
161             } elsif (exists $args{'tconst'} || exists $args{'imdbid'}) {
162 3 100       14 my $tconst = exists $args{'tconst'} ? $args{'tconst'} : $args{'imdbid'};
163 3 50       23 my ($id) = $tconst =~ m/^tt(\d{6,7})$/ or croak "Unable to parse tconst '$tconst'";
164 3         17 $_args{'imdb_code'} = sprintf("%d", $id); # Trim leading zeroes
165             }
166 5 100       15 if (exists $args{'title'}) { $_args{'title'} = $args{'title'}; }
  1         4  
167 5 50       17 if (exists $args{'width'}) { $_args{'width'} = $args{'width'}; }
  5         11  
168              
169             # Ugly hack. The demi api service appears to normalise the title key to lower case before returning the secret hash.
170 5 50 66     35 if (exists $_args{'title'} && $self->{'api_key'} eq "demo" && $self->{'api_secret'} eq "demo") { $_args{'title'} = lc $_args{'title'}; }
  1   66     4  
171              
172 5         13 $_args{'api_key'} = $self->{'api_key'};
173 5         25 $_args{'secret'} = $self->_get_secret(%_args);
174              
175 5         31 my $uri = URI->new();
176 5         173 $uri->scheme("http");
177 5         292 $uri->host("api.movieposterdb.com");
178 5         276 $uri->path("json");
179 5         136 $uri->query_form( map { my ($n, $v) = ($_, $_args{$_}); utf8::encode($n); utf8::encode($v); ($n => $v); } sort keys %_args );
  20         37  
  20         35  
  20         30  
  20         54  
180              
181 5         484 my $json = JSON->new()->decode($self->_get_page($uri->as_string()));
182              
183 5         81 return WebService::MoviePosterDB::Movie->_new($json);
184              
185             }
186              
187             sub _get_secret {
188 5     5   7 my $self = shift;
189 5         18 my %args = @_;
190              
191 5 50 33     40 if ($self->{'api_key'} eq "demo" && $self->{'api_secret'} eq "demo") {
192              
193 5         9 my %_args;
194              
195 5 100       23 if (exists $args{'title'}) {$_args{'title'} = $args{'title'}; }
  1         4  
196 5 100       15 if (exists $args{'imdb_code'}) {$_args{'imdb_code'} = $args{'imdb_code'}; }
  4         14  
197              
198 5         366 $_args{'type'} = "JSON";
199 5         46 $_args{'api_key'} = $self->{'api_key'};
200 5         12 $_args{'api_secret'} = $self->{'api_secret'};
201              
202 5         44 my $uri = URI->new();
203 5         5230 $uri->scheme("http");
204 5         12915 $uri->host("api.movieposterdb.com");
205 5         673 $uri->path("console");
206 5         195 $uri->query_form( map { my ($n, $v) = ($_, $_args{$_}); utf8::encode($n); utf8::encode($v); ($n => $v); } sort keys %_args );
  20         41  
  20         37  
  20         32  
  20         71  
207              
208 5         518 my $page = $self->_get_page($uri->as_string());
209 5 50       69 my ($s) = $page =~ m/secret=([a-f0-9]{12})/ or die "Failed to extract secret";
210              
211 5         34 return $s;
212              
213             } else {
214 0         0 my $v = $self->{'api_secret'};
215 0 0       0 if (exists $args{'imdb_code'}) { $v .= sprintf("%d", $args{'imdb_code'}); }
  0         0  
216 0 0       0 if (exists $args{'title'}) { $v .= $args{'title'}; }
  0         0  
217              
218 0         0 utf8::encode($v);
219              
220 0         0 return substr(md5_hex($v), 10, 12);
221             }
222              
223             }
224              
225             sub _get_page {
226 10     10   59 my $self = shift;
227 10         16 my $url = shift;
228              
229 10         16 my $content;
230              
231 10 50       33 if ($self->{'_cache'}) {
232 10         254 $content = $self->{'_cacheObj'}->get($url);
233             }
234              
235 10 50       140837 if (! defined $content) {
236 0         0 my $response = $self->{'_useragent'}->get($url);
237              
238 0 0       0 if($response->code() ne "200") {
239 0         0 croak "URL (", $url, ") Request Failed - Code: ", $response->code(), " Error: ", $response->message(), "\n";
240             }
241              
242 0         0 $content = $response->decoded_content();
243              
244 0 0       0 if ($self->{'_cache'}) {
245 0         0 $self->{'_cacheObj'}->set($url, $content);
246             }
247             }
248              
249 10         113 return $content;
250             }
251              
252             1;
253              
254              
255             =head1 NOTES
256              
257             The version 1 API, previously used by default, stopped as of 2011-09-27, and credentials
258             are required to access the version 2 API. It is possible to access the
259             version 2 API using test credentials (key, secret = "demo"), and this will be
260             done for legacy applications that try to use the version 1 API. However, this
261             feature is only intended for test purposes: legacy applications should be adapted,
262             and new applications should not use it.
263              
264              
265             =head1 AUTHOR
266              
267             Christopher Key
268              
269              
270             =head1 COPYRIGHT AND LICENCE
271              
272             Copyright (C) 2010-2011 Christopher Key
273              
274             This library is free software; you can redistribute it and/or modify
275             it under the same terms as Perl itself, either Perl version 5.8.4 or,
276             at your option, any later version of Perl 5 you may have available.
277              
278             =cut