File Coverage

blib/lib/WebService/Embedly.pm
Criterion Covered Total %
statement 84 88 95.4
branch 34 38 89.4
condition n/a
subroutine 11 11 100.0
pod 3 3 100.0
total 132 140 94.2


line stmt bran cond sub pod time code
1             package WebService::Embedly;
2              
3 3     3   624939 use Any::Moose;
  3         75687  
  3         25  
4 3     3   2578 use Any::Moose '::Util::TypeConstraints';
  3         8  
  3         13  
5              
6             #use Mouse;
7             #use Mouse::Util::TypeConstraints;
8              
9 3     3   1213 use LWP::UserAgent;
  3         11  
  3         63  
10 3     3   2125 use JSON;
  3         35118  
  3         20  
11             #use URI;
12 3     3   475 use URI::Escape;
  3         7  
  3         695  
13 3     3   20 use Ouch qw(:traditional);
  3         5  
  3         430  
14 3     3   2214 use Regexp::Common qw /URI/;
  3         6294  
  3         21  
15             our $VERSION = '0.10';
16              
17             =encoding utf8
18              
19             =head1 NAME
20              
21             WebService::Embedly - Perl interface to the Embedly API
22              
23             =head1 VERSION
24              
25             Version 0.10
26              
27             =cut
28              
29             =head1 SYNOPSIS
30              
31             use WebService::Embedly;
32             use Ouch qw(:traditional);
33              
34             my $embedly = WebService::Embedly->new({ api_key => 'get_your_key_at_embed.ly',
35             maxwidth => 500 });
36              
37             my $oembed_ref;
38             my $e = try {
39             $oembed_ref = $embedly->oembed('http://youtu.be/I8CSt7a7gWY');
40             };
41              
42             if ( catch_all, $e) {
43             warn("embedly api failed: ".$e);
44             return;
45             }
46              
47             #made it here, everything good.
48             my $embed_html = $oembed_ref->{html};
49              
50             =cut
51              
52             =head1 DESCRIPTION
53              
54             The C is a class implementing for querying the Embed.ly web service. Prior to using this module you should go to L and sign up for an api_key.
55              
56             You can quickly try out the API by executing: ./sample/usage.pl --apikey you_api_key_from_embed.ly
57              
58             C exposes three methods: oembed, preview, objectify. Each method has additional bits of metadata about the request URL. oembed method follows the oembed standard documented here L
59              
60             Refer to L to learn more about the data that is returned for preview L and objectify L
61              
62             Exception handling is used to expose failures. The Ouch module (:traditional) is used to handle try/catch blocks. See the Exception block below for all the possible catches. Example:
63              
64             my $e = try {
65             $oembed_ref = $embedly->oembed('http://youtu.be/I8CSt7a7gWY');
66             };
67              
68             if ( catch 500, $e) {
69             #Server is down
70             return;
71             }
72             if ( catch 401, $e) {
73             #Your API key has used all its credits
74             return;
75             }
76             elsif ( catch_all, $e) {
77             #I hate the individual exception catching, lets get this over with it.
78             return;
79             }
80              
81              
82             C uses Mouse (lighter version of Moose) to handle its object management.
83              
84             =cut
85              
86             =head1 CONSTRUCTOR
87              
88             You must pass the api_key into the constructor:
89              
90             my $embedly = WebService::Embedly->new({ api_key => 'get_your_key_at_embed.ly'});
91              
92             C uses LWP::UserAgent to handle its web requests. You have the option to pass in your own LWP object in case of special requirements, like a proxy server:
93              
94             my $ua = LWP::UserAgent->new();
95             $ua->proxy('http', 'http://proxy.sn.no:8001/');
96              
97             my $embedly = WebService::Embedly->new({ api_key => 'get_your_key_at_embed.ly',
98             ua => $ua
99             });
100              
101             =head2 Optional Params
102              
103             C supports all optional parameters at the time of this writing L. Refer to the embedly documentation for the complete description. In the majority of cases you only need to pay attention to the maxwidth param. It is highly recommended to specify maxwidth since the embed html could overflow the space you provide for it.
104              
105             =head3 maxwidth
106              
107             This is the maximum width of the embed in pixels. maxwidth is used for scaling down embeds so they fit into a certain width. If the container for an embed is 500px you should pass maxwidth=500 in the query parameters.
108              
109             =head3 maxheight
110              
111             This is the maximum height of the embed in pixels.
112              
113             =head3 width
114              
115             Will scale embeds type rich and video to the exact width that a developer specifies in pixels.
116              
117             =head3 format (default: json)
118              
119             The response format - Accepted values: (xml, json)
120              
121             =head3 callback
122              
123             Returns a (jsonp) response format. The callback is the name of the javascript function to execute.
124              
125             =head3 wmode
126              
127             Will append the wmode value to the flash object. Possible values include window, opaque and transparent.
128              
129             =head3 allowscripts (default: false)
130              
131             By default Embedly does not return script embeds for jsonp requests. They just don’t work and cause lots of issues. In some cases, you may need the script tag for saving and displaying later. Accepted values: (true, false)
132              
133             =head3 nostyle (default: false)
134              
135             There are a number of embeds that Embedly has created including Amazon.com, Foursquare, and Formspring. These all have style elements and inline styles associated with them that make the embeds look good. Accepted values: (true, false)
136              
137             =head3 autoplay (default: false)
138              
139             This will tell the video/rich media to automatically play when the media is loaded. Accepted values: (true, false)
140              
141             =head3 videosrc (default: false)
142              
143             Either true Embedly will use the video_src meta or Open Graph tag to create a video object to embed. Accepted values: (true, false)
144              
145             =head3 words
146              
147             The words parameter has a default value of 50 and works by trying to split the description at the closest sentence to that word count.
148              
149             =head3 chars
150              
151             chars is much simpler than words. Embedly will blindly truncate a description to the number of characters you specify adding ... at the end when needed.
152              
153             =cut
154              
155             =head1 EXCEPTIONS
156              
157             All exceptions are thrown in terms of http status codes. Exceptions from the web service are passed through directly. For example L and scroll down to view the Error Codes. For most situations you can simply do this:
158              
159             my $e = try {
160             $oembed_ref = $embedly->oembed('http://youtu.be/I8CSt7a7gWY');
161             };
162              
163             if ( catch_all, $e) {
164             warn("embedly api failed: ".$e);
165             #do something...
166             }
167              
168             =cut
169              
170             has 'api_key' => (
171             is => 'ro',
172             isa => 'Str',
173             required => 1,
174             );
175              
176             has 'oembed_base_uri' => (
177             is => 'ro',
178             isa => 'Str',
179             default => 'http://api.embed.ly/1/oembed'
180             );
181              
182             has 'preview_base_uri' => (
183             is => 'ro',
184             isa => 'Str',
185             default => 'http://api.embed.ly/1/preview'
186             );
187              
188             has 'objectify_base_uri' => (
189             is => 'ro',
190             isa => 'Str',
191             default => 'http://api.embed.ly/1/objectify'
192             );
193              
194             has 'ua' => (
195             is => 'ro',
196             isa => 'LWP::UserAgent',
197             required => 1,
198             default => sub { my $ua = LWP::UserAgent->new;
199             $ua->timeout(10);
200             return $ua;
201             },
202             );
203              
204             has 'json' => (
205             is => 'ro',
206             isa => 'JSON',
207             required => 1,
208             default => sub { JSON->new->utf8; },
209             );
210              
211             has 'maxwidth' => (
212             is => 'rw',
213             isa => 'Int',
214             required => 0,
215             predicate => 'has_maxwidth'
216             );
217              
218             has 'maxheight' => (
219             is => 'rw',
220             isa => 'Int',
221             required => 0,
222             predicate => 'has_maxheight'
223             );
224              
225             has 'width' => (
226             is => 'rw',
227             isa => 'Int',
228             required => 0,
229             predicate => 'has_width'
230             );
231              
232             has 'format' => (
233             is => 'rw',
234             isa => 'Str',
235             required => 0,
236             predicate => 'has_format'
237             );
238              
239             has 'callback' => (
240             is => 'rw',
241             isa => 'Str',
242             required => 0,
243             predicate => 'has_callback'
244             );
245              
246             has 'wmode' => (
247             is => 'rw',
248             isa => 'Str',
249             required => 0,
250             predicate => 'has_wmode'
251             );
252              
253             has 'allowscripts' => (
254             is => 'rw',
255             isa => 'Str',
256             required => 0,
257             predicate => 'has_allowscripts'
258             );
259              
260              
261             has 'nostyle' => (
262             is => 'rw',
263             isa => 'Str',
264             required => 0,
265             predicate => 'has_nostyle'
266             );
267              
268             has 'autoplay' => (
269             is => 'rw',
270             isa => 'Str',
271             required => 0,
272             predicate => 'has_autoplay'
273             );
274              
275             has 'videosrc' => (
276             is => 'rw',
277             isa => 'Str',
278             required => 0,
279             predicate => 'has_videosrc'
280             );
281              
282              
283             has 'words' => (
284             is => 'rw',
285             isa => 'Int',
286             required => 0,
287             predicate => 'has_words'
288             );
289              
290              
291             has 'chars' => (
292             is => 'rw',
293             isa => 'Int',
294             required => 0,
295             predicate => 'has_chars'
296             );
297              
298              
299              
300             #optional params
301              
302             =head1 METHODS
303              
304             =head2 oembed;
305              
306             =head2 preview;
307              
308             =head2 objectify;
309              
310             Embed.ly provide three different methods: oembed, preview, objectify depending on the amount of information/access you need each take the same parameters. However different data is returned depending on which method used.
311              
312             There are three ways to call each method
313              
314             =head3 Single URL
315              
316             Fetch metadata about a single URL - call method with full url as a string
317              
318             $oembed_ref = $embedly->oembed('http://youtu.be/I8CSt7a7gWY');
319              
320             =head3 Multiple URLs
321              
322             Fetch metadata about multiple URLs - call method with array ref of urls
323              
324             my @urls = qw(http://yfrog.com/ng41306327j http://twitter.com/embedly/status/29481593334 http://blog.embed.ly/31814817 http://soundcloud.com/mrenti/merenti-la-karambaa);
325             $oembed_ref = $embedly->oembed(\@urls);
326              
327             =head3 Extra Information
328              
329             Fetch metadata about URL(s) and include additional query arguments L - call methods with with hash ref of attributes
330              
331             my $query_ref = {
332              
333              
334             Can throw an exception (ouch) so wrap in an eval or use Ouch module and refer to its syntax
335              
336             =cut
337              
338             sub oembed {
339 22     22 1 37319 my ($self, $embed_url) = @_;
340              
341 22         158 my $res = $self->_request( { embed_url => $embed_url,
342             base_uri => $self->oembed_base_uri
343             } );
344              
345 5         21 return ($res);
346             }
347              
348              
349             sub preview {
350 1     1 1 1625 my ($self, $embed_url) = @_;
351              
352 1         9 my $res = $self->_request( { embed_url => $embed_url,
353             base_uri => $self->preview_base_uri
354             } );
355              
356 0         0 return ($res);
357             }
358              
359             sub objectify {
360 1     1 1 1669 my ($self, $embed_url) = @_;
361              
362 1         10 my $res = $self->_request( { embed_url => $embed_url,
363             base_uri => $self->objectify_base_uri
364             } );
365              
366 1         5 return ($res);
367             }
368              
369             sub _request {
370 24     24   41 my ($self, $in) = @_;
371              
372 24         50 my $embed_url = $in->{embed_url};
373 24         36 my $base_uri = $in->{base_uri};
374              
375 24         115 my %params = ( key => $self->api_key );
376              
377 24 100       71 if (ref($embed_url) eq 'ARRAY') {
378 3         4 my $cnt = int(@{$embed_url});
  3         8  
379 3 100       10 if ($cnt > 20) {
380 1         4 throw 400, 'Cannot pass more than 20 urls in a single request';
381             }
382              
383 2         3 my @escaped_urls;
384 2         5 foreach my $e_url (@{$embed_url}) {
  2         4  
385 22 100       772 unless ( $RE{URI}{HTTP}->{-scheme => qr/https?/}->matches($e_url) ) {
386 1         130 throw 400, 'Look-up URL does not look like a properly formatted url: ' . $e_url;
387             }
388 21         3173 push @escaped_urls, uri_escape_utf8($e_url) ;
389             }
390 1         32 $params{urls} = join (',', @escaped_urls);
391             }
392             else {
393             #quick check to see if we have a url
394 21 50       145 unless ( $RE{URI}{HTTP}->{-scheme => qr/https?/}->matches($embed_url) ) {
395 0         0 throw 400, 'Look-up URL does not look like a properly formatted url: ' . $embed_url;
396             }
397 21         4460 $params{url} = uri_escape_utf8($embed_url);
398             }
399              
400             # can't use query_form because embedly can't handle full application/x-www-form-urlencoded for multi urls (the comma between urls needs to stay a comma and not escaped to %2C) boo
401             # my $uri = URI->new($base_uri);
402             # $uri->query_form($params);
403              
404 22         836 my $url = $base_uri . '?';
405 22         62 foreach my $param (keys %params) {
406 44         115 $url .= $param .'='. $params{$param} . '&';
407             }
408              
409 22 50       108 if ( $self->has_maxwidth ) {
410 22         112 $url .= 'maxwidth='. $self->maxwidth . '&';
411             }
412              
413 22 100       87 if ( $self->has_maxheight ) {
414 11         35 $url .= 'maxheigth='. $self->maxheight . '&';
415             }
416              
417 22 100       83 if ( $self->has_width ) {
418 10         28 $url .= 'width='. $self->width . '&';
419             }
420              
421 22 100       100 if ( $self->has_format ) {
422 9         29 $url .= 'format='. $self->format . '&';
423             }
424              
425 22 100       76 if ( $self->has_callback ) {
426 8         25 $url .= 'callback='. $self->callback . '&';
427             }
428              
429 22 100       76 if ( $self->has_wmode ) {
430 7         17 $url .= 'wmode='. $self->wmode . '&';
431             }
432              
433 22 100       72 if ( $self->has_allowscripts ) {
434 6         10 $url .= 'allowscripts=true&';
435             }
436              
437 22 100       74 if ( $self->has_nostyle ) {
438 5         10 $url .= 'nostyle=true&';
439             }
440              
441 22 100       99 if ( $self->has_autoplay ) {
442 4         5 $url .= 'autoplay=true&';
443             }
444              
445 22 100       65 if ( $self->has_videosrc ) {
446 3         6 $url .= 'videosrc=true&';
447             }
448              
449 22 100       69 if ( $self->has_words ) {
450 2         8 $url .= 'words='. $self->words . '&';
451             }
452              
453 22 100       74 if ( $self->has_chars ) {
454 1         5 $url .= 'chars='. $self->chars . '&';
455             }
456              
457             #take off the trailing '&'
458 22         42 chop ($url);
459              
460             # warn ($url);
461              
462 22         129 my $res = $self->ua->get($url);
463              
464 22 100       46097 if ($res->is_success) {
465 6         58 my $data_ref;
466 6         9 eval {
467 6         51 $data_ref = $self->json->decode($res->decoded_content);
468             };
469 6 50       1162 if ($@) {
470             #Should be a different code than 500
471 0         0 throw 500, 'Could not parse JSON response', $@;
472             }
473 6         43 return $data_ref;
474             }
475             else {
476             ## figure out all the different failures form the API
477 16 50       173 if ($res->code) {
478 16         180 throw $res->code, $res->status_line;
479             }
480             else {
481 0           throw 500, 'HTTP Request to embed.ly failed', $res->status_line;
482             }
483             }
484             }
485              
486             =head1 AUTHOR
487              
488             Jason Wieland C
489              
490             =head1 BUGS
491              
492             Please report any bugs or feature requests through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
493              
494             =head1 SUPPORT
495              
496             You can find documentation for this module with the perldoc command.
497              
498             perldoc WebService::Embedly
499              
500             You can also look for information at: https://github.com/jwieland/embedly-perl
501              
502             =over 4
503              
504             =item * View source / report bugs
505              
506             L
507              
508             =back
509              
510              
511             =head1 ACKNOWLEDGEMENTS
512              
513              
514             =head1 LICENSE AND COPYRIGHT
515              
516             Copyright 2012 Jason Wieland and 12engines LLC
517              
518             This program is free software; you can redistribute it and/or modify it
519             under the terms of either: the GNU General Public License as published
520             by the Free Software Foundation; or the Artistic License.
521              
522             See L for more information.
523              
524             =cut
525              
526             __PACKAGE__->meta->make_immutable();
527              
528             1; # End of WebService::Embedly