1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
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. *
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. *
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>
31 extern Handshake myHandshake
;
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
;
47 // now playing song's metadata could change, so update it
48 s
.SetData(Mpd
->CurrentSong());
52 old_state
= current_state
;
53 current_state
= Mpd
->GetState();
54 if (old_state
== MPD::psStop
&& current_state
== MPD::psPlay
)
57 if (changed
.ElapsedTime
)
60 if (Mpd
->GetElapsedTime() == Mpd
->GetCrossfade() + 1)
64 if (changed
.SongID
|| (old_state
== MPD::psPlay
&& current_state
== MPD::psStop
))
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
)
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
)
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;
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
;
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
;
117 << "s=" << myHandshake
.SessionID
123 postdata
<< "&l=" << s
.Data
->time
129 postdata
<< c_mb_trackid
;
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
);
160 Log(llInfo
, "Notification about currently playing song sent.");
166 Log(llInfo
, "Error while sending notification: %s", curl_easy_strerror(code
));
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.
173 Log(llVerbose
, "Handshake reset");
174 MPD::Song::NowPlayingNotify
= 1;