make code more object oriented
[scrobby.git] / src / callback.cpp
blob74a34f889a3f52e32cf18abb6fec16543732b5dc
1 /***************************************************************************
2 * Copyright (C) 2008 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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 MPD::State old_state = MPD::psUnknown;
32 MPD::State current_state = MPD::psUnknown;
34 extern Handshake handshake;
35 extern MPD::Song s;
37 extern pthread_mutex_t curl_lock;
38 extern pthread_mutex_t handshake_lock;
40 extern bool notify_about_now_playing;
42 void ScrobbyErrorCallback(MPD::Connection *, int, string errormessage, void *)
44 ignore_newlines(errormessage);
45 Log("MPD: " + errormessage, llVerbose);
48 void ScrobbyStatusChanged(MPD::Connection *Mpd, MPD::StatusChanges changed, void *)
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)
59 if (!Mpd->GetElapsedTime())
60 changed.SongID = 1;
61 s.Playback()++;
63 if (changed.SongID || (old_state == MPD::psPlay && current_state == MPD::psStop))
65 s.Submit();
67 // in this case allow entering only once
68 if (old_state == MPD::psPlay && current_state == MPD::psStop)
69 old_state = MPD::psUnknown;
71 if (Mpd->GetElapsedTime() < 5)
72 s.SetStartTime();
74 if (current_state == MPD::psPlay || current_state == MPD::psPause)
77 s.SetData(Mpd->CurrentSong());
78 while (!s.Data());
79 notify_about_now_playing = !s.isStream();
82 if (notify_about_now_playing)
84 pthread_mutex_lock(&handshake_lock);
85 if (s.Data() && (!s.Data()->artist || !s.Data()->title))
87 Log("Playing song with missing tags detected.", llInfo);
89 else if (s.Data() && s.Data()->time <= 0)
91 Log("Playing song with unknown length detected.", llInfo);
93 else if (s.Data() && s.Data()->artist && s.Data()->title)
95 Log("Playing song detected: " + string(s.Data()->artist) + " - " + string(s.Data()->title), llVerbose);
97 if (handshake.status == "OK" && !handshake.nowplaying_url.empty())
99 Log("Sending now playing notification...", llInfo);
101 else
103 Log("Notification not sent due to problem with connection.", llInfo);
104 goto NOTIFICATION_FAILED;
107 string result, postdata;
108 CURLcode code;
110 pthread_mutex_lock(&curl_lock);
111 CURL *np_notification = curl_easy_init();
113 char *c_artist = curl_easy_escape(np_notification, s.Data()->artist, 0);
114 char *c_title = curl_easy_escape(np_notification, s.Data()->title, 0);
115 char *c_album = s.Data()->album ? curl_easy_escape(np_notification, s.Data()->album, 0) : NULL;
116 char *c_track = s.Data()->track ? curl_easy_escape(np_notification, s.Data()->track, 0) : NULL;
118 postdata = "s=";
119 postdata += handshake.session_id;
120 postdata += "&a=";
121 postdata += c_artist;
122 postdata += "&t=";
123 postdata += c_title;
124 postdata += "&b=";
125 if (c_album)
126 postdata += c_album;
127 postdata += "&l=";
128 postdata += IntoStr(s.Data()->time);
129 postdata += "&n=";
130 if (c_track)
131 postdata += c_track;
132 postdata += "&m=";
134 curl_free(c_artist);
135 curl_free(c_title);
136 curl_free(c_album);
137 curl_free(c_track);
139 Log("URL: " + handshake.nowplaying_url, llVerbose);
140 Log("Post data: " + postdata, llVerbose);
142 curl_easy_setopt(np_notification, CURLOPT_URL, handshake.nowplaying_url.c_str());
143 curl_easy_setopt(np_notification, CURLOPT_POST, 1);
144 curl_easy_setopt(np_notification, CURLOPT_POSTFIELDS, postdata.c_str());
145 curl_easy_setopt(np_notification, CURLOPT_WRITEFUNCTION, write_data);
146 curl_easy_setopt(np_notification, CURLOPT_WRITEDATA, &result);
147 curl_easy_setopt(np_notification, CURLOPT_CONNECTTIMEOUT, curl_timeout);
148 code = curl_easy_perform(np_notification);
149 curl_easy_cleanup(np_notification);
150 pthread_mutex_unlock(&curl_lock);
152 ignore_newlines(result);
154 if (result == "OK")
156 Log("Notification about currently playing song sent.", llInfo);
158 else
160 if (result.empty())
162 Log("Error while sending notification: " + string(curl_easy_strerror(code)), llInfo);
164 else
166 Log("Audioscrobbler returned status " + result, llInfo);
168 goto NOTIFICATION_FAILED;
171 if (0)
173 NOTIFICATION_FAILED:
175 handshake.Clear(); // handshake probably failed if we are here, so reset it
176 Log("Handshake status reset", llVerbose);
178 pthread_mutex_unlock(&handshake_lock);
179 notify_about_now_playing = 0;