move x outside a loop, its value has to be in memory
[scrobby.git] / src / song.cpp
bloba7e638e399a737082c45307de5c30c6ed9034887
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>
23 #include <string>
24 #include <vector>
26 #include "misc.h"
27 #include "scrobby.h"
28 #include "song.h"
30 using std::string;
32 extern Handshake handshake;
34 extern pthread_mutex_t curl_lock;
35 extern pthread_mutex_t handshake_lock;
37 extern std::vector<string> SongsQueue;
39 MPD::Song::Song() : itsSong(0),
40 itsStartTime(0),
41 itsNoticedPlayback(0),
42 itsIsStream(0)
46 MPD::Song::~Song()
48 if (itsSong)
49 mpd_freeSong(itsSong);
52 void MPD::Song::Clear()
54 if (itsSong)
55 mpd_freeSong(itsSong);
56 itsSong = 0;
57 itsStartTime = 0;
58 itsNoticedPlayback = 0;
59 itsIsStream = 0;
62 void MPD::Song::SetData(mpd_Song *song)
64 if (!song)
65 return;
66 if (itsSong)
67 mpd_freeSong(itsSong);
68 itsSong = song;
69 itsIsStream = strncmp("http://", itsSong->file, 7) == 0;
72 void MPD::Song::SetStartTime()
74 itsStartTime = time(NULL);
77 void MPD::Song::Submit()
79 if (!itsSong)
80 return;
82 if (itsIsStream)
84 itsSong->time = itsNoticedPlayback;
87 pthread_mutex_lock(&handshake_lock);
88 if (canBeSubmitted())
90 if (handshake.status != "OK" || handshake.submission_url.empty())
92 Log(llInfo, "Problems with handshake status, queue song at position %d...", SongsQueue.size());
93 goto SUBMISSION_FAILED;
96 Log(llInfo, "Submitting song...");
98 string result, postdata;
99 CURLcode code;
101 pthread_mutex_lock(&curl_lock);
102 CURL *submission = curl_easy_init();
104 char *c_artist = curl_easy_escape(submission, itsSong->artist, 0);
105 char *c_title = curl_easy_escape(submission, itsSong->title, 0);
106 char *c_album = itsSong->album ? curl_easy_escape(submission, itsSong->album, 0) : NULL;
107 char *c_track = itsSong->track ? curl_easy_escape(submission, itsSong->track, 0) : NULL;
109 postdata = "s=";
110 postdata += handshake.session_id;
111 postdata += "&a[0]=";
112 postdata += c_artist;
113 postdata += "&t[0]=";
114 postdata += c_title;
115 postdata += "&i[0]=";
116 postdata += IntoStr(itsStartTime);
117 postdata += "&o[0]=P";
118 postdata += "&r[0]=";
119 postdata += "&l[0]=";
120 postdata += IntoStr(itsSong->time);
121 postdata += "&b[0]=";
122 if (c_album)
123 postdata += c_album;
124 postdata += "&n[0]=";
125 if (c_track)
126 postdata += c_track;
127 postdata += "&m[0]=";
129 curl_free(c_artist);
130 curl_free(c_title);
131 curl_free(c_album);
132 curl_free(c_track);
134 Log(llVerbose, "URL: %s", handshake.submission_url.c_str());
135 Log(llVerbose, "Post data: %s", postdata.c_str());
137 curl_easy_setopt(submission, CURLOPT_URL, handshake.submission_url.c_str());
138 curl_easy_setopt(submission, CURLOPT_POST, 1);
139 curl_easy_setopt(submission, CURLOPT_POSTFIELDS, postdata.c_str());
140 curl_easy_setopt(submission, CURLOPT_WRITEFUNCTION, write_data);
141 curl_easy_setopt(submission, CURLOPT_WRITEDATA, &result);
142 curl_easy_setopt(submission, CURLOPT_CONNECTTIMEOUT, curl_timeout);
143 code = curl_easy_perform(submission);
144 curl_easy_cleanup(submission);
145 pthread_mutex_unlock(&curl_lock);
147 ignore_newlines(result);
149 if (result == "OK")
151 Log(llInfo, "Song submitted.");
153 else
155 if (result.empty())
157 Log(llInfo, "Error while submitting song: %s", curl_easy_strerror(code));
159 else
161 Log(llInfo, "Audioscrobbler returned status %s", result.c_str());
163 goto SUBMISSION_FAILED;
166 if (0)
168 SUBMISSION_FAILED: // so we cache not submitted song
170 handshake.Clear(); // handshake probably failed if we are here, so reset it
171 Log(llVerbose, "Handshake status reset");
173 string cache;
174 string offset = IntoStr(SongsQueue.size());
176 char *c_artist = curl_easy_escape(0, itsSong->artist, 0);
177 char *c_title = curl_easy_escape(0, itsSong->title, 0);
178 char *c_album = itsSong->album ? curl_easy_escape(0, itsSong->album, 0) : NULL;
179 char *c_track = itsSong->track ? curl_easy_escape(0, itsSong->track, 0) : NULL;
181 cache = "&a[";
182 cache += offset;
183 cache += "]=";
184 cache += c_artist;
185 cache += "&t[";
186 cache += offset;
187 cache += "]=";
188 cache += c_title;
189 cache += "&i[";
190 cache += offset;
191 cache += "]=";
192 cache += IntoStr(itsStartTime);
193 cache += "&o[";
194 cache += offset;
195 cache += "]=P";
196 cache += "&r[";
197 cache += offset;
198 cache += "]=";
199 cache += "&l[";
200 cache += offset;
201 cache += "]=";
202 cache += IntoStr(itsSong->time);
203 cache += "&b[";
204 cache += offset;
205 cache += "]=";
206 if (c_album)
207 cache += c_album;
208 cache += "&n[";
209 cache += offset;
210 cache += "]=";
211 if (c_track)
212 cache += c_track;
213 cache += "&m[";
214 cache += offset;
215 cache += "]=";
217 Log(llVerbose, "Metadata: %s", cache.c_str());
219 curl_free(c_artist);
220 curl_free(c_title);
221 curl_free(c_album);
222 curl_free(c_track);
224 Cache(cache);
225 SongsQueue.push_back(cache);
226 Log(llInfo, "Song cached.");
228 pthread_mutex_unlock(&handshake_lock);
229 Clear();
232 bool MPD::Song::isStream() const
234 return itsIsStream;
237 int & MPD::Song::Playback()
239 return itsNoticedPlayback;
242 const mpd_Song *& MPD::Song::Data() const
244 return (const mpd_Song *&)itsSong;
247 bool MPD::Song::canBeSubmitted()
249 if (!itsStartTime || itsSong->time < 30 || !itsSong->artist || !itsSong->title)
251 if (!itsStartTime)
253 Log(llInfo, "Song's start time isn't known, not submitting.");
255 else if (itsSong->time < 30)
257 Log(llInfo, "Song's length is too short, not submitting.");
259 else if (!itsSong->artist || !itsSong->title)
261 Log(llInfo, "Song has missing tags, not submitting.");
263 return false;
265 else if (itsNoticedPlayback < 4*60 && itsNoticedPlayback < itsSong->time/2)
267 Log(llInfo, "Noticed playback was too short, not submitting.");
268 return false;
270 return true;