File Coverage

blib/lib/TMDB/Session.pm
Criterion Covered Total %
statement 63 88 71.5
branch 12 38 31.5
condition 4 19 21.0
subroutine 15 15 100.0
pod 0 3 0.0
total 94 163 57.6


line stmt bran cond sub pod time code
1             package TMDB::Session;
2              
3             #######################
4             # LOAD CORE MODULES
5             #######################
6 3     3   21 use strict;
  3         4  
  3         121  
7 3     3   17 use warnings FATAL => 'all';
  3         5  
  3         178  
8 3     3   17 use Carp qw(croak carp);
  3         5  
  3         200  
9              
10             #######################
11             # LOAD CPAN MODULES
12             #######################
13 3     3   1433 use JSON::MaybeXS;
  3         37659  
  3         224  
14 3     3   655 use Encode qw();
  3         21508  
  3         90  
15 3     3   2433 use HTTP::Tiny qw();
  3         166214  
  3         129  
16 3     3   1671 use URI::Encode qw();
  3         4498  
  3         155  
17 3     3   24 use Params::Validate qw(validate_with :types);
  3         6  
  3         664  
18 3     3   1711 use Locale::Codes::Language qw(all_language_codes);
  3         859424  
  3         679  
19 3     3   35 use Object::Tiny qw(apikey apiurl lang debug client encoder json);
  3         7  
  3         36  
20              
21             #######################
22             # VERSION
23             #######################
24             our $VERSION = '1.3.0';
25              
26             #######################
27             # PACKAGE VARIABLES
28             #######################
29              
30             # Valid language codes
31             my %valid_lang_codes = map { $_ => 1 } all_language_codes('alpha-2');
32              
33             # Default Headers
34             my $default_headers = {
35             'Accept' => 'application/json',
36             'Content-Type' => 'application/json',
37             };
38              
39             # Default User Agent
40             my $default_ua = 'perl-tmdb-client';
41              
42             #######################
43             # PUBLIC METHODS
44             #######################
45              
46             ## ====================
47             ## Constructor
48             ## ====================
49             sub new {
50 1     1 0 3 my $class = shift;
51             my %opts = validate_with(
52             params => \@_,
53             spec => {
54             apikey => {
55             type => SCALAR,
56             },
57             apiurl => {
58             type => SCALAR,
59             optional => 1,
60             default => 'https://api.themoviedb.org/3',
61             },
62             lang => {
63             type => SCALAR,
64             optional => 1,
65             callbacks => {
66             'valid language code' =>
67 1     1   2145 sub { $valid_lang_codes{ lc $_[0] } },
68             },
69             },
70 1         30 client => {
71             type => OBJECT,
72             isa => 'HTTP::Tiny',
73             optional => 1,
74             default => HTTP::Tiny->new(
75             agent => $default_ua,
76             default_headers => $default_headers,
77             ),
78             },
79             encoder => {
80             type => OBJECT,
81             isa => 'URI::Encode',
82             optional => 1,
83             default => URI::Encode->new(),
84             },
85             json => {
86             type => OBJECT,
87             can => [qw(decode)],
88             optional => 1,
89             default => JSON::MaybeXS->new(),
90             },
91             debug => {
92             type => BOOLEAN,
93             optional => 1,
94             default => 0,
95             },
96             },
97             );
98              
99 1 50       95 $opts{lang} = lc $opts{lang} if $opts{lang};
100 1         18 my $self = $class->SUPER::new(%opts);
101 1         22 return $self;
102             } ## end sub new
103              
104             ## ====================
105             ## Talk
106             ## ====================
107             sub talk {
108 75     75 0 2704 my ( $self, $args ) = @_;
109              
110             # Build Call
111             my $url
112 75         1385 = $self->apiurl . '/' . $args->{method} . '?api_key=' . $self->apikey;
113             # add language by default
114 75 100       1456 $args->{params}->{language} = $self->lang unless (exists $args->{params}->{language});
115 75 50       343 if ( $args->{params} ) {
116 75         101 foreach
117 22         68 my $param ( sort { lc $a cmp lc $b } keys %{ $args->{params} } )
  75         320  
118             {
119 93 50       199 next unless defined $args->{params}->{$param};
120 93         311 $url .= "&${param}=" . $args->{params}->{$param};
121             } ## end foreach my $param ( sort { ...})
122             } ## end if ( $args->{params} )
123              
124             # Encode
125 75         1454 $url = $self->encoder->encode($url);
126              
127             # Talk
128 75 50       5093 warn "DEBUG: GET -> $url\n" if $self->debug;
129 75         1519 my $response = $self->client->get($url);
130              
131             # Debug
132 75 50       7345 if ( $self->debug ) {
133 0 0       0 warn "DEBUG: Got a successful response\n" if $response->{success};
134 0         0 warn "DEBUG: Got Status -> $response->{status}\n";
135             warn "DEBUG: Got Reason -> $response->{reason}\n"
136 0 0       0 if $response->{reason};
137             warn "DEBUG: Got Content -> $response->{content}\n"
138 0 0       0 if $response->{content};
139             } ## end if ( $self->debug )
140              
141             # Return
142 75 50       499 return unless $self->_check_status($response);
143 75 50 66     185 if ( $args->{want_headers} and exists $response->{headers} ) {
144              
145             # Return headers only
146 4         25 return $response->{headers};
147             } ## end if ( $args->{want_headers...})
148 71 50       161 return unless $response->{content}; # Blank Content
149             return $self->json->decode(
150 71         1394 Encode::decode( 'utf-8-strict', $response->{content} ) ); # Real Response
151             } ## end sub talk
152              
153             ## ====================
154             ## PAGINATE RESULTS
155             ## ====================
156             sub paginate_results {
157 15     15 0 491 my ( $self, $args ) = @_;
158              
159 15         41 my $response = $self->talk($args);
160 15   50     614 my $results = $response->{results} || [];
161              
162             # Paginate
163 15 0 33     40 if ( $response->{page}
      0        
164             and $response->{total_pages}
165             and ( $response->{total_pages} > $response->{page} ) )
166             {
167 0   0     0 my $page_limit = $args->{max_pages} || '1';
168 0         0 my $current_page = $response->{page};
169 0         0 while ($page_limit) {
170 0 0       0 last if ( $current_page == $page_limit );
171 0         0 $current_page++;
172 0         0 $args->{params}->{page} = $current_page;
173 0         0 my $next_page = $self->talk($args);
174 0         0 push @$results, @{ $next_page->{results} },;
  0         0  
175 0 0       0 last if ( $next_page->{page} == $next_page->{total_pages} );
176 0         0 $page_limit--;
177             } ## end while ($page_limit)
178             } ## end if ( $response->{page}...)
179              
180             # Done
181 15 50       32 return @$results if wantarray;
182 15         89 return $results;
183             } ## end sub paginate_results
184              
185             #######################
186             # INTERNAL
187             #######################
188              
189             # Check Response status
190             sub _check_status {
191 75     75   132 my ( $self, $response ) = @_;
192              
193 75 50       236 if ( $response->{success} ) {
194 75         180 return 1;
195             }
196              
197 0 0         if ( $response->{content} ) {
198 0           my ( $code, $message );
199 0           my $ok = eval {
200              
201             my $status = $self->json->decode(
202 0           Encode::decode( 'utf-8-strict', $response->{content} ) );
203              
204 0           $code = $status->{status_code};
205 0           $message = $status->{status_message};
206              
207 0           1;
208             };
209              
210 0 0 0       if ( $ok and $code and $message ) {
      0        
211 0           carp sprintf( 'TMDB API Error (%s): %s', $code, $message );
212             }
213             } ## end if ( $response->{content...})
214              
215 0           return;
216             } ## end sub _check_status
217              
218             #######################
219             1;