File Coverage

blib/lib/WebService/Bluga/Webthumb.pm
Criterion Covered Total %
statement 24 70 34.2
branch 0 32 0.0
condition 0 16 0.0
subroutine 8 13 61.5
pod 3 3 100.0
total 35 134 26.1


line stmt bran cond sub pod time code
1             package WebService::Bluga::Webthumb;
2              
3 2     2   572986 use warnings;
  2         5  
  2         162  
4 2     2   12 use strict;
  2         5  
  2         58  
5 2     2   22 use Carp;
  2         6  
  2         214  
6 2     2   13 use Digest::MD5;
  2         4  
  2         118  
7 2     2   1793 use LWP::UserAgent;
  2         148134  
  2         93  
8 2     2   23 use URI;
  2         5  
  2         52  
9 2     2   1368 use Path::Class;
  2         104545  
  2         151  
10 2     2   1372 use POSIX qw(strftime);
  2         14571  
  2         15  
11              
12             =head1 NAME
13              
14             WebService::Bluga::Webthumb - fetch website thumbnails via webthumb.bluga.net
15              
16             =cut
17              
18             our $VERSION = '0.06';
19              
20             =head1 SYNOPSIS
21              
22             use WebService::Bluga::Webthumb;
23             my $wt = WebService::Bluga::Webthumb->new(
24             user => $user_id,
25             api_key => $api_key,
26             size => $size, # small, medium, medium2, large (default: medium)
27             cache => $cache_days, # optional - default 14
28            
29             # optional settings for local caching:
30             cache_dir => '....',
31             cache_url_stub => '/images/thumbs/',
32             );
33              
34             # get a thumbnail URL using the default settings
35             my $thumb_url = wt->thumb_url($url);
36              
37             # Get a thumbnail URL overriding some settings:
38             my $thumb_url = $wt->thumb_url($url, { size => 'large' });
39              
40              
41              
42             =head1 Class methods
43              
44             =over 4
45              
46             =item new
47              
48             Create a new WebService::Bluga::Webthumb object. Takes the following params:
49              
50             =over 4
51              
52             =item user
53              
54             Your webthumb user ID, available from your L
55             page.
56              
57             =item api_key
58              
59             Your webthumb API key. also available from your user page. (This is used to
60             construct the hash of the thumbnail URL, but not sent directly.)
61              
62             =item size
63              
64             The size of the thumbnail to generate. Size can be:
65              
66             =over 4
67              
68             =item * small - 80x60
69              
70             =item * medium - 160x120
71              
72             =item * medium2 - 320x240
73              
74             =item * large - 640x480
75              
76             =back
77              
78              
79             =item cache
80              
81             How many days a generated thumbnail can be cached on the webthumb servers before
82             a fresh one is generated. Generating a thumbnail uses a credit whereas serving
83             up a cached one uses a fraction of a credit, so don't set this too low.
84              
85             If not specified, defaults to 14 days.
86              
87             =item cache_dir
88              
89             If set, generated thumbnails will be saved into this directory, and the URL
90             returned will be constructed using C (so the C
91             setting should be set to the URL at which the contents of C are
92             available) - thus we're serving cached thumbnails ourselves, which costs no
93             credits at all and eases the load on the bluga.net servers.
94              
95             The age of the cached thumbnail will be compared against the C setting,
96             and if it's too old, the cached thumbnail will be replaced with a fresh one.
97              
98             If you set C you B also set C to the URL
99             at which the contents of that directory can be served from - it's up to you
100             to make that happen via your preferred method.
101              
102             Note that if fetching and caching the thumbnail fails, we will return the
103             direct URL to the webthumb API such that the client's browser gets a chance
104             to fetch it from there instead. I'm not sure this is the best behaviour,
105             it was what happened before 0.06 without much thought put in to it. It makes
106             some sense as it may lead to the client being able to fetch the thumbnail
107             if the problem was between our server and the webthumb service, but it may
108             also be an unexpected surprise - so a future release may add an option to
109             change this behaviour and cause a hard failure if fetching & caching the
110             thumbnail fails (poke me if that would be useful to you!)
111              
112             =item cache_url_stub
113              
114             As above, if you use C to arrange for generated thumbnails to be
115             fetched and cached locally, you must set C to the URL at
116             which the contents of that directory are served; the returned thumbnail URL
117             will then be the value of C with the filename (which is the
118             hash of the URL and desired size) appended).
119              
120             =item timeout
121              
122             When fetching thumbnails from the webthumb server to cache locally, this
123             timeout value decides how long we wait - it defaults to 3 seconds.
124              
125             =back
126              
127             =cut
128              
129             sub new {
130 0     0 1   my $class = shift;
131 0 0         if (@_ % 2 != 0) {
132 0           croak "Uneven number of parameters provided";
133             }
134              
135 0           my %params = @_;
136            
137             # TODO: more extensive validation
138 0 0 0       if (!$params{user} || !$params{api_key}) {
139 0           croak "'user' and 'api_key' params must be provided";
140             }
141              
142 0 0 0       if (exists $params{size}
    0          
143 0           && !grep { $params{size} eq $_ } qw(small medium medium2 large)
144             ) {
145 0           croak "Invalid size $params{size} supplied!";
146             } elsif (!exists $params{size}) {
147 0           $params{size} = 'medium';
148             }
149              
150 0 0         if (!exists $params{cache}) {
151 0           $params{cache} = 14;
152             }
153              
154 0 0 0       if (exists $params{cache_dir} && ! exists $params{cache_url_stub}) {
155 0           croak "Must supply cache_url_stub if you supply cache_dir";
156             }
157              
158 0           my $self = \%params;
159 0           bless $self => $class;
160              
161             $self->{ua} = LWP::UserAgent->new(
162             agent => __PACKAGE__ . '/' . $VERSION,
163 0   0       timeout => $params{timeout} || 3,
164             );
165 0           return $self;
166             }
167              
168             =back
169              
170             =head1 Instance methods
171              
172             =over 4
173              
174             =item thumb_url
175              
176             Given an URL, and optionally C / C params to override those from
177             the object, returns an URL to the thumbnail, to use in an IMG tag.
178              
179             =cut
180              
181             sub thumb_url {
182 0     0 1   my ($self, $url, $params) = @_;
183              
184             # Get our params, use defaults from the object
185 0   0       $params ||= {};
186             $params->{$_} ||= $self->{$_}
187 0   0       for qw(size cache cache_dir cache_url_stub);
188              
189             # First, if we're caching locally, we need to see if we already have a
190             # cached version; if so, it's easy
191 0 0         if (my $url = $self->_get_cached_url($url, $params)) {
192 0           return $url;
193             }
194              
195             # Generate the appropriate URL:
196 0           my $uri = URI->new('http://webthumb.bluga.net/easythumb.php');
197             $uri->query_form(
198             url => $url,
199             size => $params->{size},
200             cache => $params->{cache},
201             user => $self->{user},
202             hash => Digest::MD5::md5_hex(join '',
203             strftime("%Y%m%d", gmtime(time())),
204             $url,
205             $self->{api_key}
206 0           ),
207             );
208              
209             # If we're caching, we want to fetch the resulting thumbnail and store it
210             # locally, then return the URL to that instead
211 0 0         if ($params->{cache_dir}) {
212 0           my $req = $self->{ua}->get($uri);
213 0 0         if ($req->is_success) {
214 0           my $url = $self->_cache_image($url, $params, $req->content);
215 0 0         return $url if defined $url;
216             } else {
217             # We couldn't cache it, just return the calculated URL; maybe
218             # the user will have more luck fetching it directly as they
219             # would have without caching enabled (and this is the implied
220             # behaviour before 0.06 switched to using a real UA object with
221             # the timeout set, and checking for success here)
222             # Maybe we should have an option which allows us to throw
223             # an error here so calling code can differentiate easily?
224 0           return $uri->as_string;
225             }
226             }
227              
228 0           return $uri->as_string;
229             }
230              
231             =item easy_thumb
232              
233             An alias for C. This name was used in 0.01 to reflect the fact that
234             it used the L rather than
235             the full API; however, I think C is rather clearer as to the actual
236             purpose of the method, and the implementation of it is somewhat unimportant, so
237             consider this method somewhat deprecated (but likely to be supported
238             indefinitely.)
239              
240             =cut
241              
242 0     0 1   sub easy_thumb { shift->thumb_url(@_); }
243              
244              
245             sub _get_cached_url {
246 0     0     my ($self, $url, $params) = @_;
247              
248             my $dir = Path::Class::dir($params->{cache_dir})
249 0 0         or return;
250             my $file = $dir->file(
251             Digest::MD5::md5_hex($url . $params->{size})
252 0 0         ) or return;
253 0 0         my $stat = $file->stat or return;
254 0 0         if ($stat->mtime < time - ($params->{cache} * 24 * 60 * 60)) {
255 0           $file->remove;
256 0           return;
257             } else {
258 0           return $params->{cache_url_stub} . $file->basename;
259             }
260             }
261              
262             sub _cache_image {
263 0     0     my ($self, $url, $params, $img_content) = @_;
264              
265             my $dir = Path::Class::dir($params->{cache_dir})
266 0 0         or return;
267             my $file = $dir->file(
268             Digest::MD5::md5_hex($url . $params->{size})
269 0 0         ) or return;
270 0           $file->spew($img_content);
271 0           return $params->{cache_url_stub} . $file->basename;
272             }
273              
274              
275             =back
276              
277             =head1 AUTHOR
278              
279             David Precious, C<< >>
280              
281             =head1 ACKNOWLEDGEMENTS
282              
283             James Ronan
284              
285              
286             =head1 CONTRIBUTING
287              
288             This module is developed on GitHub at:
289              
290             L
291              
292             Bug reports / suggestions / pull requests are all very welcome.
293              
294             If you find this module useful, please feel free to
295             L
296              
297              
298             =head1 BUGS
299              
300             Bug reports via L
301             GitHub|https://github.com/bigpresh/WebService-Bluga-Webthumb/issues> are
302             preferred, as the module is developed on GitHub, and issues can be correlated to
303             commits. Bug reports via L
304             queue|http://rt.cpan.org/NoAuth/ReportBug.html?Queue=WebService-Bluga-Webthumb>
305             are still valued though, if you'd prefer that way.
306              
307             =head1 SEE ALSO
308              
309             See the API documentation at L
310              
311             For a basic description of the service, see L
312              
313              
314             =head1 SUPPORT
315              
316             You can find documentation for this module with the perldoc command.
317              
318             perldoc WebService::Bluga::Webthumb
319              
320              
321              
322             =head1 LICENSE AND COPYRIGHT
323              
324             Copyright 2011 David Precious.
325              
326             This program is free software; you can redistribute it and/or modify it
327             under the terms of either: the GNU General Public License as published
328             by the Free Software Foundation; or the Artistic License.
329              
330             See http://dev.perl.org/licenses/ for more information.
331              
332              
333             =cut
334              
335             1; # End of WebService::Bluga::Webthumb