File Coverage

blib/lib/Audio/Scrobbler2.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Audio::Scrobbler2;
2              
3 1     1   32151 use strict;
  1         2  
  1         44  
4 1     1   6 use warnings;
  1         2  
  1         35  
5              
6 1     1   479 use WWW::Curl::Easy;
  0            
  0            
7             use Digest::MD5 qw( md5_hex );
8             use JSON::XS qw( decode_json );
9             use URI::Escape qw( uri_escape );
10              
11             BEGIN {
12             use Exporter ();
13             use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
14              
15             $VERSION = '0.05';
16             @ISA = qw(Exporter);
17             @EXPORT = qw();
18             @EXPORT_OK = qw();
19             %EXPORT_TAGS = ();
20             }
21              
22             sub new {
23             my ($class, $api_key, $api_secret) = @_;
24              
25             my $self = {
26             "curl" => WWW::Curl::Easy->new,
27             "api_url" => "http://ws.audioscrobbler.com/2.0/",
28             "api_key" => $api_key,
29             "api_secret" => $api_secret
30             };
31              
32             bless ($self, ref ($class) || $class);
33              
34             return $self;
35             }
36              
37             sub _signature {
38             my ($self, $params) = @_;
39             my $signature = join("", map { $_ . $params->{$_} } sort keys %$params);
40              
41             return md5_hex( $signature . $self->{"api_secret"} );
42             }
43              
44             sub _request {
45             my ($self, $params, $method) = @_;
46             my $response;
47             my $fields = join("&", "format=json", map { join("=", $_, uri_escape($params->{$_})) } keys %$params);
48              
49             if ( $method and $method eq "POST" ) {
50             $self->{"curl"}->setopt(CURLOPT_POST, 1);
51             $self->{"curl"}->setopt(CURLOPT_POSTFIELDS, $fields);
52             $self->{"curl"}->setopt(CURLOPT_URL, $self->{"api_url"});
53             }
54             else {
55             $self->{"curl"}->setopt(CURLOPT_URL, join("?", $self->{"api_url"}, $fields));
56             }
57              
58             $self->{"curl"}->setopt(CURLOPT_CONNECTTIMEOUT, 5);
59             $self->{"curl"}->setopt(CURLOPT_TIMEOUT, 30);
60             $self->{"curl"}->setopt(CURLOPT_WRITEDATA, \$response);
61             $self->{"curl"}->perform;
62             $self->{"curl"}->cleanup;
63              
64             return $response;
65             }
66              
67             sub auth_getToken {
68             my ($self) = @_;
69             my $response = $self->_request({ method => "auth.getToken", api_key => $self->{"api_key"} });
70              
71             $self->{"api_token"} = decode_json($response)->{"token"} || 0;
72              
73             return $self->{"api_token"};
74             }
75              
76             sub auth_getSession {
77             my ($self) = @_;
78              
79             # TODO: token exception need place here
80              
81             my $sig_params = {
82             api_key => $self->{"api_key"},
83             method => "auth.getSession",
84             token => $self->{"api_token"}
85             };
86              
87             my $response = $self->_request({ %$sig_params, api_sig => $self->_signature($sig_params) });
88              
89             # TODO: error handling
90              
91             $self->{"api_session"} = decode_json($response)->{"session"}->{"key"} || 0;
92              
93             return $self->{"api_session"};
94             }
95              
96             sub set_session_key {
97             my ($self, $key) = @_;
98              
99             $self->{"api_session"} = $key;
100             }
101              
102             sub track_updateNowPlaying {
103             my ($self, $artist, $track) = @_;
104              
105             my $sig_params = {
106             track => $track,
107             artist => $artist,
108             api_key => $self->{"api_key"},
109             sk => $self->{"api_session"},
110             method => "track.updateNowPlaying"
111             };
112              
113             my $response = $self->_request({ %$sig_params, api_sig => $self->_signature($sig_params) }, "POST");
114              
115             return decode_json($response);
116             }
117              
118             sub track_scrobble {
119             my ($self, $artist, $track) = @_;
120              
121             my $sig_params = {
122             track => $track,
123             artist => $artist,
124             api_key => $self->{"api_key"},
125             timestamp => time,
126             sk => $self->{"api_session"},
127             method => "track.scrobble"
128             };
129              
130             my $response = $self->_request({ %$sig_params, api_sig => $self->_signature($sig_params) }, "POST");
131              
132             return decode_json($response);
133             }
134              
135              
136             =head1 NAME
137              
138             Audio::Scrobbler2 - Interface to last.fm scrobbler API
139              
140              
141             =head1 SYNOPSIS
142              
143             use Audio::Scrobbler2;
144              
145             my $scrobbler = Audio::Scrobbler2->new($api_key, $api_secret);
146             my $api_token = $scrobbler->auth_getToken();
147              
148             # web-auth required
149             # http://www.last.fm/api/auth/?api_key=$api_key&token=$api_token
150             my $api_session = $scrobbler->auth_getSession();
151              
152             $scrobbler->track_scrobble("Artist Name", "Track Name");
153              
154              
155             =head1 METHODS
156              
157             =head2 new
158              
159             Create and return new Audio::Scrobbler2 object.
160              
161              
162             =head1 AUTHOR
163              
164             Roman (Ky6uk) Nuritdinov
165             CPAN ID: BAGET
166             baget@cpan.org
167             http://ky6uk.org
168              
169              
170             =head1 COPYRIGHT
171              
172             This program is free software; you can redistribute
173             it and/or modify it under the same terms as Perl itself.
174              
175             The full text of the license can be found in the
176             LICENSE file included with this module.
177              
178              
179             =cut
180              
181             1;