File Coverage

blib/lib/WebService/IMDB/Title.pm
Criterion Covered Total %
statement 385 552 69.7
branch 90 130 69.2
condition 1 5 20.0
subroutine 109 121 90.0
pod 36 45 80.0
total 621 853 72.8


line stmt bran cond sub pod time code
1             # $Id: Title.pm 7370 2012-04-09 01:17:33Z chris $
2              
3             =head1 NAME
4              
5             WebService::IMDB::Title
6              
7             =cut
8              
9             package WebService::IMDB::Title;
10              
11 2     2   14 use strict;
  2         5  
  2         73  
12 2     2   11 use warnings;
  2         3  
  2         105  
13              
14             our $VERSION = '0.05';
15              
16 2     2   9 use base qw(WebService::IMDB::Base);
  2         4  
  2         1308  
17              
18 2     2   12 use Carp;
  2         4  
  2         143  
19             our @CARP_NOT = qw(WebService::IMDB);
20              
21 2     2   12 use HTTP::Request::Common;
  2         4  
  2         127  
22              
23 2     2   12 use URI;
  2         3  
  2         81  
24              
25 2     2   1191 use WebService::IMDB::Certificate;
  2         6  
  2         18  
26 2     2   1255 use WebService::IMDB::Credit;
  2         8  
  2         14  
27 2     2   1450 use WebService::IMDB::CreditList;
  2         6  
  2         15  
28 2     2   58 use WebService::IMDB::Date;
  2         3  
  2         120  
29 2     2   1057 use WebService::IMDB::Goof;
  2         5  
  2         14  
30 2     2   1028 use WebService::IMDB::Image;
  2         6  
  2         13  
31 2     2   61 use WebService::IMDB::News;
  2         4  
  2         14  
32 2     2   1298 use WebService::IMDB::ParentalGuideItem;
  2         6  
  2         19  
33 2     2   1295 use WebService::IMDB::Photo;
  2         6  
  2         13  
34 2     2   1174 use WebService::IMDB::Plot;
  2         5  
  2         14  
35 2     2   1267 use WebService::IMDB::Quote;
  2         10  
  2         23  
36 2     2   1316 use WebService::IMDB::Review;
  2         7  
  2         13  
37 2     2   1227 use WebService::IMDB::Runtime;
  2         5  
  2         62  
38 2     2   1148 use WebService::IMDB::Season;
  2         6  
  2         14  
39 2     2   63 use WebService::IMDB::Title::Stub;
  2         5  
  2         25  
40 2     2   1372 use WebService::IMDB::Trailer;
  2         7  
  2         14  
41 2     2   69 use WebService::IMDB::Trivium;
  2         4  
  2         18  
42 2     2   1340 use WebService::IMDB::UserComment;
  2         6  
  2         17  
43              
44             __PACKAGE__->mk_accessors(qw(
45             __cast_summary
46             __certificate
47             __creators
48             __credits
49             __directors_summary
50             __goofs
51             __image
52             __news
53             __parental_guide
54             __photos
55             __plots
56             __quote
57             __quotes
58             __release_date
59             __reviews
60             __runtime
61             __seasons
62             __series
63             __trailer
64             __trivia
65             __user_comment
66             __user_comments
67             __writers_summary
68             ));
69              
70             use constant {
71 2         12947 PAGE_MAINDETAILS => 1,
72             PAGE_EXTERNAL_REVIEWS => 2,
73             PAGE_EPISODES => 3,
74             PAGE_FULLCREDITS => 4,
75             PAGE_GOOFS => 5,
76             PAGE_NEWS => 6,
77             PAGE_PARENTALGUIDE => 7,
78             PAGE_PHOTOS => 8,
79             PAGE_PLOT => 9,
80             PAGE_QUOTES => 10,
81             PAGE_SYNOPSIS => 11,
82             PAGE_TRIVIA => 12,
83             PAGE_USERCOMMENTS => 13,
84              
85             PAGE_LAST => 13,
86 2     2   209 };
  2         11  
87              
88             # Also:
89             # 'more_cast',
90             # 'more_writers',
91             # 'more_plot',
92              
93              
94             =head1 METHODS
95              
96             =head2 tconst
97              
98             =head2 cast_summary
99              
100             =head2 certificate
101              
102             =head2 creators
103              
104             =head2 credits
105              
106             =head2 directors_summary
107              
108             =head2 genres
109              
110             =head2 goof
111              
112             =head2 goofs
113              
114             =head2 image
115              
116             =head2 news
117              
118             =head2 num_votes
119              
120             =head2 outline_plot
121              
122             =head2 parental_guide
123              
124             =head2 photos
125              
126             =head2 plots
127              
128             =head2 production_status
129              
130             =head2 quote
131              
132             =head2 quotes
133              
134             =head2 rating
135              
136             =head2 release_date
137              
138             =head2 reviews
139              
140             =head2 runtime
141              
142             =head2 seasons
143              
144             =head2 series
145              
146             =head2 synopsis
147              
148             =head2 tagline
149              
150             =head2 title
151              
152             =head2 trailer
153              
154             =head2 trivia
155              
156             =head2 trivium
157              
158             =head2 type
159              
160             =head2 user_comment
161              
162             =head2 user_comments
163              
164             =head2 writers_summary
165              
166             =head2 year
167              
168             =cut
169              
170              
171             ################################
172             #
173             # Primary properties
174             #
175             ################################
176              
177             sub _url {
178 19     19   37 my $self = shift;
179 19         38 my $page = shift;
180              
181 19         187 my $uri = URI->new();
182 19         1007 $uri->scheme("http");
183 19         1600 $uri->host($self->_domain());
184 19 100       1844 if ($page == PAGE_MAINDETAILS) {
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
185 8         44 $uri->path(sprintf("/title/%s/maindetails", $self->_id()));
186             } elsif ($page == PAGE_EXTERNAL_REVIEWS) {
187 1         7 $uri->path("/title/external_reviews");
188 1         38 $uri->query_form('tconst' => $self->_id());
189             } elsif ($page == PAGE_EPISODES) {
190 1         7 $uri->path("/title/episodes");
191 1         33 $uri->query_form('tconst' => $self->_id());
192             } elsif ($page == PAGE_FULLCREDITS) {
193 0         0 $uri->path("/title/fullcredits");
194 0         0 $uri->query_form('tconst' => $self->_id());
195             } elsif ($page == PAGE_GOOFS) {
196 1         5 $uri->path("/title/goofs");
197 1         32 $uri->query_form('tconst' => $self->_id());
198             } elsif ($page == PAGE_NEWS) {
199 1         5 $uri->path(sprintf("/title/%s/news", $self->_id()));
200             } elsif ($page == PAGE_PARENTALGUIDE) {
201 1         6 $uri->path("/title/parentalguide");
202 1         33 $uri->query_form('tconst' => $self->_id());
203             } elsif ($page == PAGE_PHOTOS) {
204 1         7 $uri->path("/title/photos");
205 1         34 $uri->query_form('tconst' => $self->_id());
206             } elsif ($page == PAGE_PLOT) {
207 1         6 $uri->path("/title/plot");
208 1         27 $uri->query_form('tconst' => $self->_id());
209             } elsif ($page == PAGE_QUOTES) {
210 1         5 $uri->path("/title/quotes");
211 1         30 $uri->query_form('tconst' => $self->_id());
212             } elsif ($page == PAGE_SYNOPSIS) {
213 1         7 $uri->path("/title/synopsis");
214 1         33 $uri->query_form('tconst' => $self->_id());
215             } elsif ($page == PAGE_TRIVIA) {
216 1         5 $uri->path("/title/trivia");
217 1         32 $uri->query_form('tconst' => $self->_id());
218             } elsif ($page == PAGE_USERCOMMENTS) {
219 1         7 $uri->path("/title/usercomments");
220 1         40 $uri->query_form('tconst' => $self->_id(), "limit" => 20); # TODO: Should perhaps be higher?
221             }
222              
223 19         1277 return $uri->as_string();
224             }
225              
226              
227             sub tconst {
228 7     7 1 5361 my $self = shift;
229 7         50 return $self->_content(PAGE_MAINDETAILS)->{'tconst'};
230             }
231              
232             sub cast_summary {
233 7     7 1 3337 my $self = shift;
234 7         21 return $self->_cast_summary();
235             }
236              
237             sub certificate {
238 1     1 1 3 my $self = shift;
239 1         6 return $self->_certificate();
240             }
241              
242             sub creators {
243 2     2 1 574 my $self = shift;
244 2         10 return $self->_creators()
245             }
246              
247             sub credits {
248 0     0 1 0 my $self = shift;
249 0         0 return $self->_credits()
250             }
251              
252             sub directors_summary {
253 2     2 1 1118 my $self = shift;
254 2         9 return $self->_directors_summary();
255             }
256              
257             sub genres {
258 2     2 1 642 my $self = shift;
259 2 50       9 if (exists $self->_content(PAGE_MAINDETAILS)->{'genres'}) { # TODO: Think about how to handle this correctly.
260 2         4 return [ @{$self->_content(PAGE_MAINDETAILS)->{'genres'}} ];
  2         6  
261             } else {
262 0         0 return [];
263             }
264             }
265              
266             sub goof {
267 1     1 1 2 my $self = shift;
268 1 50       5 if (exists $self->_content(PAGE_MAINDETAILS)->{'goof'}) {
269 1         6 return $self->_content(PAGE_MAINDETAILS)->{'goof'};
270             } else {
271 0         0 return undef;
272             }
273             }
274              
275             sub goofs {
276 2     2 1 642 my $self = shift;
277 2         8 return $self->_goofs();
278             }
279              
280             sub image {
281 1     1 1 473 my $self = shift;
282 1         4 return $self->_image();
283             }
284              
285             sub news {
286 3     3 1 1859 my $self = shift;
287 3         12 return $self->_news();
288             }
289              
290             sub num_votes {
291 1     1 1 632 my $self = shift;
292 1 50       9 if (exists $self->_content(PAGE_MAINDETAILS)->{'num_votes'}) {
293 1         5 return $self->_content(PAGE_MAINDETAILS)->{'num_votes'};
294             } else {
295 0         0 return undef;
296             }
297             }
298              
299             sub outline_plot {
300 2     2 1 5 my $self = shift;
301 2 50 33     12 if (exists $self->_content(PAGE_MAINDETAILS)->{'plot'} && exists $self->_content(PAGE_MAINDETAILS)->{'plot'}->{'outline'}) {
302 2         8 return $self->_content(PAGE_MAINDETAILS)->{'plot'}->{'outline'};
303             } else {
304 0         0 return undef;
305             }
306             }
307              
308             sub parental_guide {
309 2     2 1 625 my $self = shift;
310 2         8 return $self->_parental_guide();
311             }
312              
313             sub photos {
314 2     2 1 1418 my $self = shift;
315 2         9 return $self->_photos();
316             }
317              
318             sub plots {
319 4     4 1 883 my $self = shift;
320 4         15 return $self->_plots();
321             }
322              
323             sub production_status {
324 1     1 1 3 my $self = shift;
325 1 50       7 if (exists $self->_content(PAGE_MAINDETAILS)->{'production_status'}) {
326 1         4 return $self->_content(PAGE_MAINDETAILS)->{'production_status'};
327             } else {
328 0         0 return undef;
329             }
330             }
331              
332             sub quote {
333 1     1 1 389 my $self = shift;
334 1         7 return $self->_quote();
335             }
336              
337             sub quotes {
338 2     2 1 1598 my $self = shift;
339 2         57 return $self->_quotes();
340             }
341              
342             sub rating {
343 1     1 1 501 my $self = shift;
344 1 50       8 if (exists $self->_content(PAGE_MAINDETAILS)->{'rating'}) {
345 1         5 return $self->_content(PAGE_MAINDETAILS)->{'rating'};
346             } else {
347 0         0 return undef;
348             }
349             }
350              
351             sub release_date {
352 1     1 1 68 my $self = shift;
353 1         6 return $self->_release_date();
354             }
355              
356             sub reviews { # Should be "external_reviews"?
357 2     2 1 1491 my $self = shift;
358 2         10 return $self->_reviews();
359             }
360              
361             sub runtime {
362 1     1 1 511 my $self = shift;
363 1         5 return $self->_runtime();
364             }
365              
366             sub seasons {
367 3     3 1 1447 my $self = shift;
368 3         13 return $self->_seasons();
369             }
370              
371             sub series {
372 3     3 1 610 my $self = shift;
373 3         18 return $self->_series();
374             }
375              
376             sub synopsis {
377 1     1 1 503 my $self = shift;
378              
379             # We can't rely on $self->_content(PAGE_MAINDETAILS)->{'has'}; it doesn't always have synopsis present, even for titles that do
380             # return a synopsis in $self->_content(PAGE_SYNOPSIS) (e.g. tt0036342). For titles that don't have a synopsis, $self->_content(PAGE_SYNOPSIS)
381             # can either return a hash without a 'text' key, or returns a 404 status (e.g. http://app.imdb.com/title/synopsis?tconst=tt0035015)
382             # hence we test for both these cases.
383 1         3 my $content;
384 1         3 eval {
385 1         15 $content = $self->_content(PAGE_SYNOPSIS);
386             };
387              
388 1 50       11 if ($@ =~ m/404/) {
    50          
    50          
389 0         0 $@ = "";
390 0         0 return undef;
391             } elsif ($@) {
392 0         0 die $@;
393             } elsif (exists $content->{'text'}) {
394 1         8 return $content->{'text'};
395             } else {
396 0         0 return undef;
397             }
398              
399             }
400              
401             sub tagline {
402 1     1 1 3 my $self = shift;
403 1 50       7 if (exists $self->_content(PAGE_MAINDETAILS)->{'tagline'}) {
404 1         5 return $self->_content(PAGE_MAINDETAILS)->{'tagline'};
405             } else {
406 0         0 return undef;
407             }
408             }
409              
410             sub title {
411 4     4 1 12 my $self = shift;
412 4         23 return $self->_content(PAGE_MAINDETAILS)->{'title'};
413             }
414              
415             sub trailer {
416 1     1 1 4 my $self = shift;
417 1         5 return $self->_trailer();
418             }
419              
420             sub trivia {
421 2     2 1 1374 my $self = shift;
422 2         9 return $self->_trivia();
423             }
424              
425             sub trivium {
426 1     1 1 509 my $self = shift;
427 1 50       10 if (exists $self->_content(PAGE_MAINDETAILS)->{'trivium'}) {
428 1         6 return $self->_content(PAGE_MAINDETAILS)->{'trivium'};
429             } else {
430 0         0 return undef;
431             }
432             }
433              
434             sub type {
435 3     3 1 8 my $self = shift;
436 3         14 return $self->_content(PAGE_MAINDETAILS)->{'type'};
437             }
438              
439             sub user_comment {
440 1     1 1 3 my $self = shift;
441 1         6 return $self->_user_comment();
442             }
443              
444             sub user_comments {
445 2     2 1 1524 my $self = shift;
446 2         12 return $self->_user_comments();
447             }
448              
449             sub writers_summary {
450 2     2 1 1105 my $self = shift;
451 2         9 return $self->_writers_summary();
452             }
453              
454             sub year {
455 1     1 1 478 my $self = shift;
456 1         7 return $self->_content(PAGE_MAINDETAILS)->{'year'};
457             }
458              
459              
460             # Temporary aliases for soem IMDB::Film methods
461              
462             sub plot {
463 1     1 0 4 my $self = shift;
464 1         7 return $self->outline_plot();
465             }
466              
467             sub full_plot {
468 1     1 0 3 my $self = shift;
469 1 50       2 if (scalar @{$self->plots()}) {
  1         7  
470 1         16 return $self->plots()->[0]->text();
471             } else {
472 0         0 return undef;
473             }
474             }
475              
476              
477              
478              
479             sub language {
480 0     0 0 0 return undef;
481             }
482              
483             sub company {
484 0     0 0 0 return undef;
485             }
486              
487             sub directors {
488 0     0 0 0 return undef;
489             }
490              
491             sub cast {
492 0     0 0 0 return undef;
493             }
494              
495             sub certifications {
496 0     0 0 0 return undef;
497             }
498              
499             sub duration {
500 0     0 0 0 return undef;
501             }
502              
503             sub episodeof {
504 0     0 0 0 my $self = shift;
505 0 0       0 if (defined $self->series()) {
506 0         0 return [{'id' => substr($self->series()->tconst(), 2)}];
507             } else {
508 0         0 return undef;
509             }
510             }
511              
512             ################################
513             #
514             # Caching accessors
515             #
516             ################################
517              
518             sub _flush {
519 0     0   0 my $self = shift;
520              
521 0         0 $self->SUPER::_flush();
522              
523 0         0 $self->__cast_summary(undef);
524 0         0 $self->__certificate(undef);
525 0         0 $self->__creators(undef);
526 0         0 $self->__credits(undef);
527 0         0 $self->__directors_summary(undef);
528 0         0 $self->__goofs(undef);
529 0         0 $self->__image(undef);
530 0         0 $self->__news(undef);
531 0         0 $self->__parental_guide(undef);
532 0         0 $self->__photos(undef);
533 0         0 $self->__plots(undef);
534 0         0 $self->__quote(undef);
535 0         0 $self->__quotes(undef);
536 0         0 $self->__release_date(undef);
537 0         0 $self->__reviews(undef);
538 0         0 $self->__runtime(undef);
539 0         0 $self->__seasons(undef);
540 0         0 $self->__series(undef);
541 0         0 $self->__trailer(undef);
542 0         0 $self->__trivia(undef);
543 0         0 $self->__user_comment(undef);
544 0         0 $self->__user_comments(undef);
545 0         0 $self->__writers_summary(undef);
546             }
547              
548             sub _cast_summary {
549 7     7   16 my $self = shift;
550              
551 7 100       32 if (!defined $self->__cast_summary()) { $self->__cast_summary($self->_get_cast_summary()); }
  1         16  
552 7         99 return $self->__cast_summary();
553             }
554              
555             sub _certificate {
556 1     1   4 my $self = shift;
557              
558 1 50       8 if (!defined $self->__certificate()) { $self->__certificate([$self->_get_certificate()]); } # Wrap in array, because we need to cache undef too
  1         18  
559 1         258 return $self->__certificate()->[0];
560             }
561              
562             sub _creators {
563 2     2   5 my $self = shift;
564              
565 2 100       10 if (!defined $self->__creators()) { $self->__creators($self->_get_creators()); }
  1         20  
566 2         28 return $self->__creators();
567             }
568              
569             sub _credits {
570 0     0   0 my $self = shift;
571              
572 0 0       0 if (!defined $self->__credits()) { $self->__credits($self->_get_credits()); }
  0         0  
573 0         0 return $self->__credits();
574             }
575              
576             sub _directors_summary {
577 2     2   3 my $self = shift;
578              
579 2 100       12 if (!defined $self->__directors_summary()) { $self->__directors_summary($self->_get_directors_summary()); }
  1         18  
580 2         26 return $self->__directors_summary();
581             }
582              
583             sub _goofs {
584 2     2   4 my $self = shift;
585              
586 2 100       6 if (!defined $self->__goofs()) { $self->__goofs($self->_get_goofs()); }
  1         15  
587 2         27 return $self->__goofs();
588             }
589              
590             sub _image {
591 1     1   4 my $self = shift;
592              
593 1 50       7 if (!defined $self->__image()) { $self->__image([$self->_get_image()]); } # Wrap in array, because we need to cache undef too
  1         15  
594 1         12 return $self->__image()->[0];
595             }
596              
597             sub _news {
598 3     3   7 my $self = shift;
599              
600 3 100       14 if (!defined $self->__news()) { $self->__news($self->_get_news()); }
  1         16  
601 3         38 return $self->__news();
602             }
603              
604             sub _parental_guide {
605 2     2   4 my $self = shift;
606              
607 2 100       10 if (!defined $self->__parental_guide()) { $self->__parental_guide($self->_get_parental_guide()); }
  1         19  
608 2         23 return $self->__parental_guide();
609             }
610              
611             sub _photos {
612 2     2   4 my $self = shift;
613              
614 2 100       11 if (!defined $self->__photos()) { $self->__photos($self->_get_photos()); }
  1         17  
615 2         29 return $self->__photos();
616             }
617              
618             sub _plots {
619 4     4   6 my $self = shift;
620              
621 4 100       23 if (!defined $self->__plots()) { $self->__plots($self->_get_plots()); }
  1         16  
622 4         40 return $self->__plots();
623             }
624              
625             sub _quote {
626 1     1   2 my $self = shift;
627              
628 1 50       8 if (!defined $self->__quote()) { $self->__quote([$self->_get_quote()]); } # Wrap in array, because we need to cache undef too
  1         17  
629 1         12 return $self->__quote()->[0];
630             }
631              
632             sub _quotes {
633 2     2   6 my $self = shift;
634              
635 2 100       10 if (!defined $self->__quotes()) { $self->__quotes($self->_get_quotes()); }
  1         19  
636 2         29 return $self->__quotes();
637             }
638              
639             sub _release_date {
640 1     1   3 my $self = shift;
641              
642 1 50       5 if (!defined $self->__release_date()) { $self->__release_date([$self->_get_release_date()]); } # Wrap in array, because we need to cache undef too
  1         50  
643 1         58 return $self->__release_date()->[0];
644             }
645              
646             sub _reviews {
647 2     2   4 my $self = shift;
648              
649 2 100       11 if (!defined $self->__reviews()) { $self->__reviews($self->_get_reviews()); }
  1         17  
650 2         35 return $self->__reviews();
651             }
652              
653             sub _runtime {
654 1     1   3 my $self = shift;
655              
656 1 50       6 if (!defined $self->__runtime()) { $self->__runtime([$self->_get_runtime()]); } # Wrap in array, because we need to cache undef too
  1         29  
657 1         192 return $self->__runtime()->[0];
658             }
659              
660             sub _seasons {
661 3     3   8 my $self = shift;
662              
663 3 100       14 if (!defined $self->__seasons()) { $self->__seasons($self->_get_seasons()); }
  1         17  
664 3         34 return $self->__seasons();
665             }
666              
667             sub _series {
668 3     3   6 my $self = shift;
669              
670 3 100       16 if (!defined $self->__series()) { $self->__series([$self->_get_series()]); } # Wrap in array, because we need to cache undef too
  2         37  
671 3         35 return $self->__series()->[0];
672             }
673              
674             sub _trailer {
675 1     1   3 my $self = shift;
676              
677 1 50       6 if (!defined $self->__trailer()) { $self->__trailer([$self->_get_trailer()]); } # Wrap in array, because we need to cache undef too
  1         19  
678 1         12 return $self->__trailer()->[0];
679             }
680              
681             sub _trivia {
682 2     2   4 my $self = shift;
683              
684 2 100       10 if (!defined $self->__trivia()) { $self->__trivia($self->_get_trivia()); }
  1         16  
685 2         29 return $self->__trivia();
686             }
687              
688             sub _user_comment {
689 1     1   4 my $self = shift;
690              
691 1 50       7 if (!defined $self->__user_comment()) { $self->__user_comment([$self->_get_user_comment()]); } # Wrap in array, because we need to cache undef too
  1         18  
692 1         15 return $self->__user_comment()->[0];
693             }
694              
695             sub _user_comments {
696 2     2   4 my $self = shift;
697              
698 2 100       12 if (!defined $self->__user_comments()) { $self->__user_comments($self->_get_user_comments()); }
  1         19  
699 2         30 return $self->__user_comments();
700             }
701              
702             sub _writers_summary {
703 2     2   4 my $self = shift;
704              
705 2 100       9 if (!defined $self->__writers_summary()) { $self->__writers_summary($self->_get_writers_summary()); }
  1         18  
706 2         22 return $self->__writers_summary();
707             }
708              
709              
710             ################################
711             #
712             # Parsing methods
713             #
714             ################################
715              
716             sub _get_id {
717 8     8   15 my $self = shift;
718              
719 8         17 my $tconst;
720              
721 8 100       24 if (exists $self->_q()->{'tconst'}) {
    50          
722 6         81 $tconst = $self->_q()->{'tconst'}
723             } elsif (exists $self->_q()->{'imdbid'}) {
724 2         45 my $imdbid = $self->_q()->{'imdbid'};
725 2 50       33 my ($id) = $imdbid =~ m/^(?:tt)?(\d+)$/ or die "Failed to parse '$imdbid'";
726 2         18 $tconst = sprintf("tt%07d", $id);
727             } else {
728 0         0 croak "No valid search criteria";
729             }
730              
731             # The constructor calls _get_id to validate the supplied id too, such that a
732             # successful return from the constructor is indicative that the id is valid, and
733             # that the resource exists. We do that by trying to use the supplied id to
734             # fetch the resource.
735              
736 8         130 my $uri = URI->new();
737 8         514 $uri->scheme("http");
738 8         805 $uri->host($self->_domain());
739 8         775 $uri->path(sprintf("/title/%s/maindetails", $tconst));
740              
741 8         273 my $content = $self->_ws()->_response_decoded_json(GET $uri->as_string());
742              
743 8 50       64 if ($content->{'tconst'} ne $tconst) {
744 0         0 die "tconst failed round trip"
745             }
746              
747 8         271 return $tconst;
748             }
749              
750             sub _get_cast_summary {
751 1     1   2 my $self = shift;
752              
753 1         4 return [map {WebService::IMDB::Credit->_new($self->_ws(), $_)} @{$self->_content(PAGE_MAINDETAILS)->{'cast_summary'}}];
  4         14  
  1         6  
754              
755             }
756              
757             sub _get_certificate {
758 1     1   2 my $self = shift;
759              
760 1 50       6 if (exists $self->_content(PAGE_MAINDETAILS)->{'certificate'}) {
761 1         6 return WebService::IMDB::Certificate->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'certificate'});
762             } else {
763 0         0 return undef;
764             }
765              
766             }
767              
768             sub _get_creators {
769 1     1   3 my $self = shift;
770              
771 1 50       6 if (exists $self->_content(PAGE_MAINDETAILS)->{'creators'}) {
772 1         3 return [map {WebService::IMDB::Credit->_new($self->_ws(), $_)} @{$self->_content(PAGE_MAINDETAILS)->{'creators'}}];
  1         6  
  1         5  
773             } else {
774 0         0 return [];
775             }
776              
777             }
778              
779             sub _get_credits {
780 0     0   0 my $self = shift;
781              
782 0         0 return [map {WebService::IMDB::CreditList->_new($self->_ws(), $_)} @{$self->_content(PAGE_FULLCREDITS)->{'credits'}}];
  0         0  
  0         0  
783              
784             }
785              
786             sub _get_directors_summary {
787 1     1   2 my $self = shift;
788              
789 1         3 return [map {WebService::IMDB::Credit->_new($self->_ws(), $_)} @{$self->_content(PAGE_MAINDETAILS)->{'directors_summary'}}];
  1         5  
  1         5  
790              
791             }
792              
793             sub _get_goofs {
794 1     1   2 my $self = shift;
795              
796             return [
797 0         0 (map {WebService::IMDB::Goof->_new($self->_ws(), $_, 1)} @{$self->_content(PAGE_GOOFS)->{'spoilt'}}),
  1         4  
  34         90  
798 1         3 (map {WebService::IMDB::Goof->_new($self->_ws(), $_, '')} @{$self->_content(PAGE_GOOFS)->{'unspoilt'}}),
  1         5  
799             ];
800              
801             }
802              
803             sub _get_image {
804 1     1   3 my $self = shift;
805              
806 1 50       6 if (exists $self->_content(PAGE_MAINDETAILS)->{'image'}) {
807 1         4 return WebService::IMDB::Image->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'image'});
808             } else {
809 0         0 return undef;
810             }
811              
812             }
813              
814             sub _get_news {
815 1     1   12 my $self = shift;
816              
817             # Handle 500 errors, e.g. for:
818             # http://app.imdb.com/title/tt0095705/news
819             # http://app.imdb.com/title/tt0213847/news
820             # TODO: Is 'has' any more use in avoiding the problem here?
821 1         2 my $content;
822 1         3 eval {
823 1         5 $content = $self->_content(PAGE_NEWS);
824             };
825              
826 1 50       8 if ($@ =~ m/500/) {
    50          
827 0         0 $@ = "";
828 0         0 return undef;
829             } elsif ($@) {
830 0         0 die $@;
831             } else {
832 1         7 return WebService::IMDB::News->_new($self->_ws(), $content);
833             }
834              
835             }
836              
837             sub _get_parental_guide {
838 1     1   2 my $self = shift;
839              
840 1         10 return [map { WebService::IMDB::ParentalGuideItem->_new($self->_ws(), $_) } @{$self->_content(PAGE_PARENTALGUIDE)->{'parental_guide'}}];
  5         16  
  1         6  
841              
842             }
843              
844             sub _get_photos {
845 1     1   2 my $self = shift;
846              
847 1         2 return [map { WebService::IMDB::Photo->_new($self->_ws(), $_) } @{$self->_content(PAGE_PHOTOS)->{'photos'}}];
  100         257  
  1         6  
848              
849             }
850              
851             sub _get_plots {
852 1     1   2 my $self = shift;
853              
854 1         3 return [map {WebService::IMDB::Plot->_new($self->_ws(), $_)} @{$self->_content(PAGE_PLOT)->{'plots'}}];
  5         16  
  1         7  
855              
856             }
857              
858             sub _get_quote {
859 1     1   2 my $self = shift;
860 1 50       4 if (exists $self->_content(PAGE_MAINDETAILS)->{'quote'}) {
861 1         4 return WebService::IMDB::Quote->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'quote'});
862             } else {
863 0         0 return undef;
864             }
865             }
866              
867             sub _get_quotes {
868 1     1   3 my $self = shift;
869              
870 1         3 return [map {WebService::IMDB::Quote->_new($self->_ws(), $_)} @{$self->_content(PAGE_QUOTES)->{'quotes'}}];
  58         149  
  1         6  
871              
872             }
873              
874             sub _get_release_date {
875 1     1   2 my $self = shift;
876              
877 1 50       13 if (exists $self->_content(PAGE_MAINDETAILS)->{'release_date'}) {
878 1         7 return WebService::IMDB::Date->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'release_date'});
879             } else {
880 0         0 return undef;
881             }
882              
883             }
884              
885             sub _get_reviews {
886 1     1   3 my $self = shift;
887              
888 1         2 return [map {WebService::IMDB::Review->_new($self->_ws(), $_)} @{$self->_content(PAGE_EXTERNAL_REVIEWS)->{'reviews'}}];
  215         586  
  1         6  
889              
890             }
891              
892             sub _get_runtime {
893 1     1   3 my $self = shift;
894              
895 1 50       10 if (exists $self->_content(PAGE_MAINDETAILS)->{'runtime'}) {
896 1         5 return WebService::IMDB::Runtime->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'runtime'});
897             } else {
898 0         0 return undef;
899             }
900              
901             }
902              
903             sub _get_seasons {
904 1     1   3 my $self = shift;
905              
906 1 50       5 if (exists $self->_content(PAGE_EPISODES)->{'seasons'}) {
907 1         4 return [map {WebService::IMDB::Season->_new($self->_ws(), $_)} @{$self->_content(PAGE_EPISODES)->{'seasons'}}];
  9         32  
  1         6  
908             } else {
909 0         0 return [];
910             }
911              
912             }
913              
914             sub _get_series {
915 2     2   4 my $self = shift;
916              
917 2 50       13 if (exists $self->_content(PAGE_MAINDETAILS)->{'series'}) {
918 2         9 return WebService::IMDB::Title::Stub->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'series'});
919             } else {
920 0         0 return undef;
921             }
922              
923             }
924              
925             sub _get_trailer {
926 1     1   2 my $self = shift;
927              
928 1 50       7 if (exists $self->_content(PAGE_MAINDETAILS)->{'trailer'}) {
929 1         6 return WebService::IMDB::Trailer->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'trailer'});
930             } else {
931 0         0 return undef;
932             }
933              
934             }
935              
936             sub _get_trivia {
937 1     1   3 my $self = shift;
938              
939             return [
940 1         6 (map { WebService::IMDB::Trivium->_new($self->_ws(), $_, 1) } @{$self->_content(PAGE_TRIVIA)->{'spoilt'}}),
  1         5  
  87         222  
941 1         11 (map { WebService::IMDB::Trivium->_new($self->_ws(), $_, '') } @{$self->_content(PAGE_TRIVIA)->{'unspoilt'}}),
  1         6  
942             ];
943              
944             }
945              
946             sub _get_user_comment {
947 1     1   3 my $self = shift;
948              
949 1 50       7 if (exists $self->_content(PAGE_MAINDETAILS)->{'user_comment'}) {
950 1         7 return WebService::IMDB::UserComment->_new($self->_ws(), $self->_content(PAGE_MAINDETAILS)->{'user_comment'});
951             } else {
952 0         0 return undef;
953             }
954              
955             }
956              
957             sub _get_user_comments {
958 1     1   4 my $self = shift;
959              
960 1         2 return [map {WebService::IMDB::UserComment->_new($self->_ws(), $_)} @{$self->_content(PAGE_USERCOMMENTS)->{'user_comments'}}];
  20         74  
  1         6  
961              
962             }
963              
964             sub _get_writers_summary {
965 1     1   3 my $self = shift;
966              
967 1         3 return [map {WebService::IMDB::Credit->_new($self->_ws(), $_)} @{$self->_content(PAGE_MAINDETAILS)->{'writers_summary'}}];
  2         8  
  1         13  
968              
969             }
970              
971              
972              
973             ################################
974             #
975             # Debug / dev code
976             #
977             ################################
978              
979             sub _unparsed {
980 0     0     my $self = shift;
981              
982 2     2   31 use Storable qw(dclone);
  2         6  
  2         3530  
983 0   0       my $d = { map {$_ => dclone(eval { $self->_content($_) } || {} )} (1..PAGE_LAST) }; # See comments in synopsis(), _get_news() for why we need eval.
  0            
984              
985 0           delete $d->{PAGE_MAINDETAILS()}->{'tconst'};
986 0           delete $d->{PAGE_MAINDETAILS()}->{'cast_summary'};
987 0           delete $d->{PAGE_MAINDETAILS()}->{'certificate'};
988 0           delete $d->{PAGE_MAINDETAILS()}->{'creators'};
989 0           delete $d->{PAGE_FULLCREDITS()}->{'credits'};
990 0           delete $d->{PAGE_MAINDETAILS()}->{'directors_summary'};
991 0           delete $d->{PAGE_MAINDETAILS()}->{'genres'};
992 0           delete $d->{PAGE_MAINDETAILS()}->{'image'};
993 0           delete $d->{PAGE_MAINDETAILS()}->{'goof'};
994 0           delete $d->{PAGE_GOOFS()}->{'spoilt'};
995 0           delete $d->{PAGE_GOOFS()}->{'unspoilt'};
996 0           delete $d->{PAGE_MAINDETAILS()}->{'title'};
997 0           $d->{PAGE_NEWS()} = {};
998 0           delete $d->{PAGE_MAINDETAILS()}->{'num_votes'};
999 0           delete $d->{PAGE_MAINDETAILS()}->{'plot'}->{'outline'};
1000 0           delete $d->{PAGE_PARENTALGUIDE()}->{'parental_guide'};
1001 0           delete $d->{PAGE_PHOTOS()}->{'photos'};
1002 0           delete $d->{PAGE_PLOT()}->{'plots'};
1003 0           delete $d->{PAGE_MAINDETAILS()}->{'production_status'};
1004 0           delete $d->{PAGE_MAINDETAILS()}->{'quote'};
1005 0           delete $d->{PAGE_QUOTES()}->{'quotes'};
1006 0           delete $d->{PAGE_MAINDETAILS()}->{'rating'};
1007 0           delete $d->{PAGE_MAINDETAILS()}->{'release_date'};
1008 0           delete $d->{PAGE_EXTERNAL_REVIEWS()}->{'reviews'};
1009 0           delete $d->{PAGE_MAINDETAILS()}->{'runtime'};
1010 0           delete $d->{PAGE_EPISODES()}->{'seasons'};
1011 0           delete $d->{PAGE_MAINDETAILS()}->{'series'};
1012 0           delete $d->{PAGE_SYNOPSIS()}->{'text'};
1013 0           delete $d->{PAGE_MAINDETAILS()}->{'tagline'};
1014 0           delete $d->{PAGE_MAINDETAILS()}->{'title'};
1015 0           delete $d->{PAGE_MAINDETAILS()}->{'trailer'};
1016 0           delete $d->{PAGE_TRIVIA()}->{'spoilt'};
1017 0           delete $d->{PAGE_TRIVIA()}->{'unspoilt'};
1018 0           delete $d->{PAGE_MAINDETAILS()}->{'trivium'};
1019 0           delete $d->{PAGE_MAINDETAILS()}->{'type'};
1020 0           delete $d->{PAGE_MAINDETAILS()}->{'user_comment'};
1021 0           delete $d->{PAGE_USERCOMMENTS()}->{'user_comments'};
1022 0           delete $d->{PAGE_MAINDETAILS()}->{'writers_summary'};
1023 0           delete $d->{PAGE_MAINDETAILS()}->{'year'};
1024              
1025             # TODO: Check that these really aren't required
1026 0           delete $d->{PAGE_MAINDETAILS()}->{'can_rate'}; # What is this?
1027 0           delete $d->{PAGE_MAINDETAILS()}->{'has'};
1028 0           delete $d->{PAGE_MAINDETAILS()}->{'plot'}; # Should only have ->{'more'} remaining
1029              
1030 0           delete $d->{PAGE_USERCOMMENTS()}->{'limit'};
1031 0           delete $d->{PAGE_USERCOMMENTS()}->{'total'};
1032              
1033              
1034             # TODO: Check that there's nothing in these that doesn't occur in the dedicated pages
1035 0           delete $d->{PAGE_MAINDETAILS()}->{'news'};
1036 0           delete $d->{PAGE_MAINDETAILS()}->{'photos'};
1037 0           delete $d->{PAGE_MAINDETAILS()}->{'seasons'};
1038              
1039 0           delete $d->{PAGE_EXTERNAL_REVIEWS()}->{'tconst'};
1040 0           delete $d->{PAGE_EXTERNAL_REVIEWS()}->{'title'};
1041 0           delete $d->{PAGE_EXTERNAL_REVIEWS()}->{'type'};
1042 0           delete $d->{PAGE_EXTERNAL_REVIEWS()}->{'year'};
1043              
1044 0           delete $d->{PAGE_EPISODES()}->{'tconst'};
1045 0           delete $d->{PAGE_EPISODES()}->{'title'};
1046 0           delete $d->{PAGE_EPISODES()}->{'type'};
1047 0           delete $d->{PAGE_EPISODES()}->{'year'};
1048              
1049 0           delete $d->{PAGE_FULLCREDITS()}->{'tconst'};
1050 0           delete $d->{PAGE_FULLCREDITS()}->{'title'};
1051 0           delete $d->{PAGE_FULLCREDITS()}->{'type'};
1052 0           delete $d->{PAGE_FULLCREDITS()}->{'year'};
1053              
1054 0           delete $d->{PAGE_GOOFS()}->{'tconst'};
1055 0           delete $d->{PAGE_GOOFS()}->{'title'};
1056 0           delete $d->{PAGE_GOOFS()}->{'type'};
1057 0           delete $d->{PAGE_GOOFS()}->{'year'};
1058              
1059 0           delete $d->{PAGE_PHOTOS()}->{'tconst'};
1060 0           delete $d->{PAGE_PHOTOS()}->{'title'};
1061 0           delete $d->{PAGE_PHOTOS()}->{'type'};
1062 0           delete $d->{PAGE_PHOTOS()}->{'year'};
1063              
1064 0           delete $d->{PAGE_PLOT()}->{'tconst'};
1065 0           delete $d->{PAGE_PLOT()}->{'title'};
1066 0           delete $d->{PAGE_PLOT()}->{'type'};
1067 0           delete $d->{PAGE_PLOT()}->{'year'};
1068              
1069 0           delete $d->{PAGE_QUOTES()}->{'tconst'};
1070 0           delete $d->{PAGE_QUOTES()}->{'title'};
1071 0           delete $d->{PAGE_QUOTES()}->{'type'};
1072 0           delete $d->{PAGE_QUOTES()}->{'year'};
1073              
1074 0           delete $d->{PAGE_SYNOPSIS()}->{'tconst'};
1075 0           delete $d->{PAGE_SYNOPSIS()}->{'title'};
1076 0           delete $d->{PAGE_SYNOPSIS()}->{'type'};
1077 0           delete $d->{PAGE_SYNOPSIS()}->{'year'};
1078              
1079 0           delete $d->{PAGE_TRIVIA()}->{'tconst'};
1080 0           delete $d->{PAGE_TRIVIA()}->{'title'};
1081 0           delete $d->{PAGE_TRIVIA()}->{'type'};
1082 0           delete $d->{PAGE_TRIVIA()}->{'year'};
1083              
1084 0           delete $d->{PAGE_USERCOMMENTS()}->{'tconst'};
1085 0           delete $d->{PAGE_USERCOMMENTS()}->{'title'};
1086 0           delete $d->{PAGE_USERCOMMENTS()}->{'type'};
1087 0           delete $d->{PAGE_USERCOMMENTS()}->{'year'};
1088              
1089 0           return $d;
1090             }
1091              
1092             1;