LJSUP-17669: Login.bml form refactoring
[livejournal.git] / cgi-bin / LJ / LastFM.pm
blob944ab0580da7ae8814021395bafa23eb506045e2
1 #!/usr/bin/perl
3 # LastFM - API to LastFM
4 package LJ::LastFM;
6 use strict;
8 use LWP::UserAgent;
9 use HTML::Entities;
10 use XML::Parser;
11 use Encode;
13 # Get current track
14 sub current {
15 my $username = LJ::eurl(shift);
17 return { error => "Missing last.fm credentials" }
18 unless $LJ::LAST_FM_API_KEY && $LJ::LAST_FM_API_URL;
20 my $ua = LJ::get_useragent( role=>'last_fm', timeout=>$LJ::LAST_FM_TIMEOUT );
21 my $url = "$LJ::LAST_FM_API_URL&api_key=$LJ::LAST_FM_API_KEY&user=$username";
22 my $response = $ua->get($url);
23 unless ($response->is_success) {
24 return { error => "Can't retrieve data from last.fm: " . $response->status_line };
27 my $content = $response->content();
29 # process xml
30 my $in_current_play_tag = 0; # if we are inside track tag with nowplaying attribute
31 my $current_tag = ''; # a name of a current tag
33 # error
34 my $error_code = 0;
35 my $error_message = '';
37 # now plaing song attributes
38 my $artist = '';
39 my $name = '';
41 # Handlers.
42 # on tag start:
43 my $handler_start = sub {
44 my $expat = shift;
45 my $element = shift;
46 my %attr = @_;
48 # catch tag 'track' with 'nowplaying=true'
49 if ($element eq "track"
50 && exists($attr{'nowplaying'}) && $attr{'nowplaying'} eq "true") {
51 $in_current_play_tag = 1;
52 return;
55 $error_code = $attr{'code'}
56 if ($element eq "error" && exists($attr{'code'}));
58 # for all other tags just remember name
59 $current_tag = $element;
62 # on tag end:
63 my $handler_end = sub {
64 my $expat = shift;
65 my $element = shift;
66 my %attr = @_;
68 # if we leave 'track' tag
69 if ($element eq "track") {
70 $in_current_play_tag = 0;
73 # forget a name of a current tag
74 $current_tag = '';
77 # inside a tag:
78 my $handler_char = sub {
79 my $expat = shift;
80 my $string = shift;
82 # 'error'
83 if ($current_tag eq 'error') {
84 $error_message = $string;
85 return;
88 # pay attention only on current playing tracks
89 return unless($in_current_play_tag);
91 # remember song attributes
92 if ($current_tag eq "artist") {
93 $artist .= $string;
94 return;
97 if ($current_tag eq "name") {
98 $name .= $string;
99 return;
103 my $parser = new XML::Parser(Handlers => {
104 Start => $handler_start,
105 End => $handler_end,
106 Char => $handler_char,
108 eval { $parser->parse($content); };
109 if ($@) { # invalid xml
110 return { error => "Can't retrieve data from last.fm: wrong response from server" };
113 if ($error_message) {
114 return { error => "Can't retrieve data from last.fm: $error_message" };
117 # This prevents worker from die when it catch unicode characters in last.fm title.
118 # (turn off UTF-8 flags from text strings)
119 ($artist, $name) = map { Encode::is_utf8($_) ? Encode::encode("utf8", $_) : $_ } ($artist, $name);
121 if ($artist || $name) {
122 my $track = HTML::Entities::decode(
123 ($artist ? $artist : 'Unknown artist') . ' - ' . ($name ? $name : 'Unknown track' ) . $LJ::LAST_FM_SIGN_TEXT
125 return { data => $track };
126 } else {
127 return { error => 'No "now listening" track in last.fm data' };
131 sub format_current_music_string {
132 my $string = shift;
134 if ($string =~ $LJ::LAST_FM_SIGN_RE) {
136 my ($artist, $track) = $string =~ /^\s*(.*)\s{1}-\s{1}(.*)$LJ::LAST_FM_SIGN_RE/;
138 if ($artist && $track) {
139 $string = $artist ne 'Unknown artist' ? qq{<a href='$LJ::LAST_FM_ARTIST_URL'>$artist</a>} : $artist;
140 $string .= ' - ';
141 $string .= $track ne 'Unknown track' ? qq{<a href='$LJ::LAST_FM_TRACK_URL'>$track</a>} : $track;
143 $string .= " $LJ::LAST_FM_SIGN_TEXT";
145 $string =~ s/%artist%/$artist/g;
146 $artist = LJ::eurl($artist);
147 $string =~ s/%artist_esc%/$artist/g;
149 $string =~ s/%track%/$track/g;
150 $track = LJ::eurl($track);
151 $string =~ s/%track_esc%/$track/g;
154 $string =~ s!Last\.fm!$LJ::LAST_FM_SIGN_URL!;
158 return $string;