increase tolerance in detecting new songs if songid didn't change
[scrobby.git] / src / callback.cpp
blobe6ed791a62e64782dd4f09365d1a150c317c7690
1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include <curl/curl.h>
22 #include <cstring>
24 #include "callback.h"
25 #include "misc.h"
26 #include "scrobby.h"
27 #include "song.h"
29 using std::string;
31 extern Handshake myHandshake;
32 extern MPD::Song s;
34 void ScrobbyErrorCallback(MPD::Connection *, int, string errormessage, void *)
36 IgnoreNewlines(errormessage);
37 Log(llVerbose, "MPD: %s", errormessage.c_str());
40 void ScrobbyStatusChanged(MPD::Connection *Mpd, MPD::StatusChanges changed, void *)
42 static MPD::State old_state = MPD::psUnknown;
43 static MPD::State current_state = MPD::psUnknown;
45 if (changed.Playlist)
47 // now playing song's metadata could change, so update it
48 s.SetData(Mpd->CurrentSong());
50 if (changed.State)
52 old_state = current_state;
53 current_state = Mpd->GetState();
54 if (old_state == MPD::psStop && current_state == MPD::psPlay)
55 changed.SongID = 1;
57 if (changed.ElapsedTime)
60 if (Mpd->GetElapsedTime() == Mpd->GetCrossfade() + 2)
61 changed.SongID = 1;
62 s.Playback++;
64 if (changed.SongID || (old_state == MPD::psPlay && current_state == MPD::psStop))
66 s.Submit();
68 // in this case allow entering only once
69 if (old_state == MPD::psPlay && current_state == MPD::psStop)
70 old_state = MPD::psUnknown;
72 if (Mpd->GetElapsedTime() < Mpd->GetCrossfade()+curl_connecttimeout+curl_timeout)
73 time(&s.StartTime);
75 if (current_state == MPD::psPlay || current_state == MPD::psPause)
77 s.SetData(Mpd->CurrentSong());
78 MPD::Song::NowPlayingNotify = s.Queue.size()+s.SubmitQueue.size() != 1 && s.Data && !s.isStream();
82 if (!MPD::Song::NowPlayingNotify || !s.Data)
83 return;
85 MPD::Song::NowPlayingNotify = 0;
87 if (!s.Data->artist || !s.Data->title)
89 Log(llInfo, "Playing song with missing tags detected.");
91 else if (s.Data->time <= 0)
93 Log(llInfo, "Playing song with unknown length detected.");
95 else if (s.Data->artist && s.Data->title)
97 if (!myHandshake.OK())
99 MPD::Song::NowPlayingNotify = 1;
100 return;
103 Log(llVerbose, "Playing song detected: %s - %s", s.Data->artist, s.Data->title);
104 Log(llInfo, "Sending now playing notification...");
106 std::ostringstream postdata;
107 string result, postdata_str;
108 CURLcode code;
110 char *c_artist = curl_easy_escape(0, s.Data->artist, 0);
111 char *c_title = curl_easy_escape(0, s.Data->title, 0);
112 char *c_album = s.Data->album ? curl_easy_escape(0, s.Data->album, 0) : NULL;
113 char *c_track = s.Data->track ? curl_easy_escape(0, s.Data->track, 0) : NULL;
114 char *c_mb_trackid = s.Data->musicbrainz_trackid ? curl_easy_escape(0, s.Data->musicbrainz_trackid, 0) : NULL;
116 postdata
117 << "s=" << myHandshake.SessionID
118 << "&a=" << c_artist
119 << "&t=" << c_title
120 << "&b=";
121 if (c_album)
122 postdata << c_album;
123 postdata << "&l=" << s.Data->time
124 << "&n=";
125 if (c_track)
126 postdata << c_track;
127 postdata << "&m=";
128 if (c_mb_trackid)
129 postdata << c_mb_trackid;
131 curl_free(c_artist);
132 curl_free(c_title);
133 curl_free(c_album);
134 curl_free(c_track);
135 curl_free(c_mb_trackid);
137 postdata_str = postdata.str();
139 Log(llVerbose, "URL: %s", myHandshake.NowPlayingURL.c_str());
140 Log(llVerbose, "Post data: %s", postdata_str.c_str());
142 CURL *np_notification = curl_easy_init();
143 curl_easy_setopt(np_notification, CURLOPT_URL, myHandshake.NowPlayingURL.c_str());
144 curl_easy_setopt(np_notification, CURLOPT_POST, 1);
145 curl_easy_setopt(np_notification, CURLOPT_POSTFIELDS, postdata_str.c_str());
146 curl_easy_setopt(np_notification, CURLOPT_WRITEFUNCTION, write_data);
147 curl_easy_setopt(np_notification, CURLOPT_WRITEDATA, &result);
148 curl_easy_setopt(np_notification, CURLOPT_CONNECTTIMEOUT, curl_connecttimeout);
149 curl_easy_setopt(np_notification, CURLOPT_TIMEOUT, curl_timeout);
150 curl_easy_setopt(np_notification, CURLOPT_DNS_CACHE_TIMEOUT, 0);
151 curl_easy_setopt(np_notification, CURLOPT_NOPROGRESS, 1);
152 curl_easy_setopt(np_notification, CURLOPT_NOSIGNAL, 1);
153 code = curl_easy_perform(np_notification);
154 curl_easy_cleanup(np_notification);
156 IgnoreNewlines(result);
158 if (result == "OK")
160 Log(llInfo, "Notification about currently playing song sent.");
162 else
164 if (result.empty())
166 Log(llInfo, "Error while sending notification: %s", curl_easy_strerror(code));
168 else
170 Log(llInfo, "Audioscrobbler returned status %s", result.c_str());
171 // it can return only OK or BADSESSION, so if we are here, BADSESSION was returned.
172 myHandshake.Clear();
173 Log(llVerbose, "Handshake reset");
174 MPD::Song::NowPlayingNotify = 1;