File Coverage

blib/lib/WWW/Shorten/Yourls.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package WWW::Shorten::Yourls;
2              
3 1     1   23900 use warnings;
  1         2  
  1         31  
4 1     1   5 use strict;
  1         1  
  1         34  
5 1     1   5 use Carp;
  1         4  
  1         80  
6              
7 1     1   5 use base qw( WWW::Shorten::generic Exporter );
  1         1  
  1         976  
8              
9             use JSON::Any;
10              
11             require XML::Simple;
12             require Exporter;
13              
14             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16             our @EXPORT = qw(new version);
17              
18             my @ISA = qw(Exporter);
19              
20             use vars qw( @ISA @EXPORT );
21              
22              
23             =head1 NAME
24              
25             WWW::Shorten::Yourls - Interface to shortening URLs using L
26              
27             =head1 VERSION
28              
29             $Revision: 0.06 $
30              
31             =cut
32              
33             BEGIN {
34             our $VERSION = do { my @r = (q$Revision: 0.06 $ =~ /\d+/g); sprintf "%1d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
35             $WWW::Shorten::Yourls::VERBOSITY = 2;
36             }
37              
38             # ------------------------------------------------------------
39              
40              
41             =head1 SYNOPSIS
42              
43             WWW::Shorten::Yourls provides an easy interface for shortening URLs using http://yourls.org. In addition to shortening URLs, you can pull statistics that yourls.org gathers regarding each shortened
44             WWW::Shorten::Yourls uses XML::Simple to convert the xml response for the meta info and click stats to create a hashref of the results.
45              
46             WWW::Shorten::Yourls provides two interfaces. The first is the common C and C that WWW::Shorten provides. However, due to the way the yourls.org API works, additional arguments are required. The second provides a better way of retrieving additional information and statistics about a yourls.org URL.
47              
48             use WWW::Shorten::Yourls;
49              
50             my $url = "http://www.example.com";
51              
52             my $tmp = makeashorterlink($url, 'MY_YOURLS_USERNAME', 'MY_YOURLS_PASSWORD');
53             my $tmp1 = makealongerlink($tmp, 'MY_YOURLS_USERNAME', 'MY_YOURLS_PASSWORD');
54              
55             or
56              
57             use WWW::Shorten::Yourls;
58              
59             my $url = "http://www.example.com";
60             my $yourls = WWW::Shorten::Yourls->new(USER => "my_user_id",
61             APIKEY => "my_api_key");
62              
63             $yourls->shorten(URL => $url);
64             print "shortened URL is $yourls->{url}\n";
65              
66             $yourls->expand(URL => $yourls->{url});
67             print "expanded/original URL is $yourls->{longurl}\n";
68              
69             =head1 FUNCTIONS
70              
71             =head2 new
72              
73             Create a new yourls.org object using your yourls.org user id and yourls.org api key.
74              
75             my $yourls = WWW::Shorten::Yourls->new(URL => "http://www.example.com/this_is_one_example.html",
76             USER => "yourls_user_id",
77             PASSWORD => "yourls_password");
78              
79             =cut
80              
81             sub new {
82             my ($class) = shift;
83             my %args = @_;
84             $args{source} ||= "teknatusyourls";
85             use File::Spec;
86             my $yourlsrc = $^O =~/Win32/i ? File::Spec->catfile($ENV{HOME}, "_yourls") : File::Spec->catfile($ENV{HOME}, ".yourls");
87             if (-r $yourlsrc){
88             open my $fh, "<", $yourlsrc or die "can't open .yourls file $!";
89             while(<$fh>){
90             $args{USER} ||= $1 if m{^USER=(.*)};
91             $args{PASSWORD} ||= $1 if m{^PASSWORD=(.*)};
92             $args{SIGNATURE} ||= $1 if m{^SIGNATURE=(.*)};
93             }
94             close $fh;
95             }
96             if (((!$args{USER} && !$args{PASSWORD}) && (!$args{USER} && !$args{SIGNATURE})) || !$args{BASE}) {
97             carp("USER/PASSWORD or USER/SIGNATURE and BASE are required parameters.\n");
98             return -1;
99             }
100             my $yourls;
101             $yourls->{USER} = $args{USER};
102             $yourls->{PASSWORD} = $args{PASSWORD};
103             $yourls->{BASE} = $args{BASE};
104             $yourls->{SIGNATURE} = $args{SIGNATURE};
105             $yourls->{json} = JSON::Any->new;
106             $yourls->{browser} = LWP::UserAgent->new(agent => $args{source});
107             $yourls->{xml} = new XML::Simple(SuppressEmpty => 1);
108             my ($self) = $yourls;
109             bless $self, $class;
110             }
111              
112              
113             =head2 makeashorterlink
114              
115             The function C will call the yourls.org API site passing it
116             your long URL and will return the shorter yourls.org version.
117              
118             yourls.org requires the use of a user id and password to shorten links.
119              
120             makeashorterlink($url,$uid,$passwd,$base);
121              
122             =cut
123              
124             sub makeashorterlink #($;%)
125             {
126             my $url = shift or croak('No URL passed to makeashorterlink');
127             my ($user, $password, $base) = @_ or croak('No username, password or Yourls service URL passed to makeshorterlink');
128             if (!defined $url || !defined $user || !defined $password ) {
129             croak("url, user, password, base are required for shortening a URL with yourls.org - in that specific order");
130             &help();
131             }
132             my $ua = __PACKAGE__->ua();
133             my $yourls;
134             $yourls->{json} = JSON::Any->new;
135             $yourls->{xml} = new XML::Simple(SuppressEmpty => 1);
136             my $yurl = $base . "/yourls-api.php";
137             $yourls->{response} = $ua->post($yurl, [
138             'url' => $url,
139             'format' => 'json',
140             'action' => 'shorturl',
141             'username' => $user,
142             'password' => $password,
143             ]);
144             $yourls->{response}->is_success || die 'Failed to get yourls.org link: ' . $yourls->{response}->status_line;
145             $yourls->{url} = $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{shorturl} if (defined $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{statusCode} && $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{statusCode} == 200);
146             return $yourls->{url};
147             }
148              
149             =head2 makealongerlink
150              
151             The function C does the reverse. C
152             will accept as an argument either the full yourls.org URL or just the
153             yourls.org identifier. yourls.org requires the use of a user name and API
154             Key when using the API.
155              
156             If anything goes wrong, then the function will return C.
157              
158             makealongerlink($url,$uid,$passwd,$base);
159              
160             THIS IS NOT WORKING RIGHT NOW AS YOURLS DOESN'T SUPPORT EXPANDING A URL.
161              
162             =cut
163              
164             sub makealongerlink #($,%)
165             {
166             my $url = shift or croak('No shortened yourls.org URL passed to makealongerlink');
167             my ($user, $password, $base) = @_ or croak('No username, password, or base passed to makealongerlink');
168             my $ua = __PACKAGE__->ua();
169             my $yurl = $base . "/yourls-api.php";
170             my $yourls;
171             $yourls->{json} = JSON::Any->new;
172             $yourls->{xml} = new XML::Simple(SuppressEmpty => 1);
173             $yourls->{response} = $ua->post($yurl, [
174             'shorturl' => $url,
175             'format' => 'json',
176             'action' => 'expand',
177             'username' => $user,
178             'password' => $password,
179             ]);
180             $yourls->{response}->is_success || die 'Failed to get yourls.org link: ' . $yourls->{response}->status_line;
181             $yourls->{longurl} = $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{longurl} if (defined $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{statusCode} && $yourls->{json}->jsonToObj($yourls->{response}->{_content})->{statusCode} == 200);
182             return $yourls->{longurl};
183             }
184              
185             =head2 shorten
186              
187             Shorten a URL using http://yourls.org. Calling the shorten method will return the shortened URL but will also store it in yourls.org object until the next call is made.
188              
189             my $url = "http://www.example.com";
190             my $shortstuff = $yourls->shorten(URL => $url);
191              
192             print "yurl is " . $yourls->{url} . "\n";
193             or
194             print "yurl is $shortstuff\n";
195              
196             =cut
197              
198              
199             sub shorten {
200             my $self = shift;
201             my %args = @_;
202             if (!defined $args{URL}) {
203             croak("URL is required.\n");
204             return -1;
205             }
206             $args{format} ||= 'json';
207             if (!$self->{SIGNATURE}) {
208             $self->{response} = $self->{browser}->post($self->{BASE} . '/yourls-api.php', [
209             'url' => $args{URL},
210             # 'keyword' => $args{keyword},
211             'format' => $args{format},
212             'action' => 'shorturl',
213             'username' => $self->{USER},
214             'password' => $self->{PASSWORD},
215             ]);
216             } else {
217             $self->{response} = $self->{browser}->post($self->{BASE} . '/yourls-api.php', [
218             'url' => $args{URL},
219             # 'keyword' => $args{keyword},
220             'format' => $args{format},
221             'action' => 'shorturl',
222             'signature' => $self->{SIGNATURE},
223             ]);
224             }
225             $self->{response}->is_success || die 'Failed to get yourls.org link: ' . $self->{response}->status_line;
226             $self->{url} = $self->{json}->jsonToObj($self->{response}->{_content})->{shorturl} if (defined $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} && $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} == 200);
227             return $self->{url}
228             }
229              
230             =head2 expand
231              
232             Expands a shortened yourls.org URL to the original long URL.
233              
234             THIS ONLY WORKS WITH YOURLS 1.4+
235             Versions prior to Yourls 1.4 don't support expansion of shortened URLs.
236              
237             =cut
238             sub expand {
239             my $self = shift;
240             my %args = @_;
241             $args{URL} ||= $self->{url};
242             if (!defined $args{URL}) {
243             croak("URL is required.\n");
244             return -1;
245             }
246             $args{format} ||= 'json';
247             if (!$self->{SIGNATURE}) {
248             $self->{response} = $self->{browser}->post($self->{BASE} . '/yourls-api.php', [
249             'shorturl' => $args{URL},
250             'action' => 'expand',
251             'username' => $self->{USER},
252             'password' => $self->{PASSWORD},
253             'format' => $args{format}
254             ]);
255             } else {
256             $self->{response} = $self->{browser}->post($self->{BASE} . '/yourls-api.php', [
257             'shorturl' => $args{URL},
258             'action' => 'expand',
259             'signature' => $self->{SIGNATURE},
260             'format' => $args{format}
261             ]);
262             }
263             $self->{response}->is_success || die 'Failed to get yourls.org link: ' . $self->{response}->status_line;
264             $self->{longurl} = $self->{json}->jsonToObj($self->{response}->{_content})->{longurl} if (defined $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} && $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} == 200);
265             return $self->{longurl};
266             }
267              
268             =head2 clicks
269              
270             Get click thru information for a shortened yourls.org URL. By default, the method will use the value that's stored in $yourls->{url}. To be sure you're getting info on the correct URL, it's a good idea to set this value before getting any info on it.
271              
272             THIS HAS NOT BEEN IMPLEMENTED YET AS YOURLS DOESN'T SUPPORT THIS FUNCTIONALITY.
273              
274             =cut
275              
276             sub clicks {
277             my $self = shift;
278             my %args = @_;
279             $args{URL} ||= $self->{url};
280             if (!defined $args{URL}) {
281             croak("URL is required.\n");
282             return -1;
283             }
284             if (!$self->{SIGNATURE}) {
285             $self->{response} = $self->{browser}->post($self->{BASE} . '/yourls-api.php', [
286             'action' => 'url-stats',
287             'format' => 'json',
288             'shorturl' => $args{URL},
289             'username' => $self->{USER},
290             'password' => $self->{PASSWORD},
291             ]);
292             } else {
293             $self->{response} = $self->{browser}->get($self->{BASE} . '/yourls-api.php?action=url-stats&format=json&shorturl=' . $args{URL} . '&signature=' . $self->{SIGNATURE});
294             }
295             $self->{response}->is_success || die 'Failed to get yourls.org link: ' . $self->{response}->status_line;
296             if (defined $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} && $self->{json}->jsonToObj($self->{response}->{_content})->{statusCode} == 200) {
297             $self->{$args{URL}}->{clicks} = $self->{json}->jsonToObj($self->{response}->{_content})->{link}->{clicks};
298             $self->{$args{URL}}->{info} = $self->{json}->jsonToObj($self->{response}->{_content});
299             }
300             return $self->{$args{URL}};
301             }
302              
303             =head2 errors
304              
305             THIS IS NOT WORKING RIGHT NOW AS YOURLS DOESN'T SUPPORT ERROR RESPONSES FROM A URL.
306              
307             =cut
308              
309             sub errors {
310             my $self = shift;
311             if (!$self->{SIGNATURE}) {
312             $self->{response} = $self->{browser}->post($self->{BASE} . '/errors', [
313             'username' => $self->{USER},
314             'password' => $self->{PASSWORD},
315             ]);
316             } else {
317             $self->{response} = $self->{browser}->post($self->{BASE} . '/errors', [
318             'signature' => $self->{SIGNATURE},
319             ]);
320             }
321             $self->{response}->is_success || die 'Failed to get yourls.org link: ' . $self->{response}->status_line;
322             $self->{$self->{url}}->{content} = $self->{xml}->XMLin($self->{response}->{_content});
323             $self->{$self->{url}}->{errorCode} = $self->{$self->{url}}->{content}->{errorCode};
324             if ($self->{$self->{url}}->{errorCode} == 0 ) {
325             $self->{$self->{url}}->{clicks} = $self->{$self->{url}}->{content}->{results};
326             return $self->{$self->{url}}->{clicks};
327             } else {
328             return;
329             }
330             }
331              
332             =head2 version
333              
334             Gets the module version number
335              
336             =cut
337             sub version {
338             my $self = shift;
339             my($version) = shift;# not sure why $version isn't being set. need to look at it
340             warn "Version $version is later then $WWW::Shorten::Yourls::VERSION. It may not be supported" if (defined ($version) && ($version > $WWW::Shorten::Yourls::VERSION));
341             return $WWW::Shorten::Yourls::VERSION;
342             }#version
343              
344              
345             =head1 FILES
346              
347             $HOME/.yourls or _yourls on Windows Systems.
348              
349             You may omit USER and PASSWORD in the constructor if you set them in the .yourls config file on separate lines using the syntax:
350              
351             USER=username
352             PASSWORD=password
353              
354              
355             =head1 AUTHOR
356              
357             Pankaj Jain, C<< >>
358              
359             =head1 BUGS
360              
361             Please report any bugs or feature requests to C, or through
362             the web interface at L. I will
363             be notified, and then you'll automatically be notified of progress on your bug as I make changes.
364              
365              
366             =head1 SUPPORT
367              
368             You can find documentation for this module with the perldoc command.
369              
370             perldoc WWW::Shorten::Yourls
371              
372              
373             You can also look for information at:
374              
375             =over 4
376              
377             =item * RT: CPAN's request tracker
378              
379             L
380              
381             =item * AnnoCPAN: Annotated CPAN documentation
382              
383             L
384              
385             =item * CPAN Ratings
386              
387             L
388              
389             =item * Search CPAN
390              
391             L
392              
393             =back
394              
395              
396             =head1 ACKNOWLEDGEMENTS
397              
398             =over
399              
400             =item http://yourls.org for a great tool.
401              
402             =item Larry Wall, Damian Conway, and all the amazing folks giving us Perl and continuing to work on it over the years.
403              
404             =item Mizar, C<< >>, Peter Edwards, C< >>, Joerg Meltzer, C<< >> for great patches to WWW::Shorten:Bitly which this module is based on.
405              
406             =back
407              
408             =head1 COPYRIGHT & LICENSE
409              
410             =over
411              
412             =item Copyright (c) 2009 Pankaj Jain, All Rights Reserved L.
413              
414             =item Copyright (c) 2009 Teknatus Solutions LLC, All Rights Reserved L.
415              
416             =back
417              
418             This program is free software; you can redistribute it and/or modify it
419             under the same terms as Perl itself.
420              
421             =head1 DISCLAIMER OF WARRANTY
422              
423             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
424             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
425             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
426             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
427             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
428             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
429             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
430             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
431             NECESSARY SERVICING, REPAIR, OR CORRECTION.
432              
433             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
434             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
435             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
436             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
437             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
438             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
439             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
440             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
441             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
442             SUCH DAMAGES.
443              
444             =head1 SEE ALSO
445              
446             L, L, L.
447              
448             =cut
449              
450             1; # End of WWW::Shorten::Yourls