increase tolerance in detecting new songs if songid didn't change
[scrobby.git] / src / scrobby.cpp
blob94e0cb9f35dafb6133c1dec52d34fbdd3b80ecb8
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 <csignal>
22 #include <cstdlib>
23 #include <curl/curl.h>
24 #include <iostream>
26 #include "callback.h"
27 #include "configuration.h"
28 #include "misc.h"
29 #include "scrobby.h"
30 #include "song.h"
31 #include "mpdpp.h"
33 using std::string;
35 Handshake myHandshake;
36 MPD::Song s;
38 namespace
40 time_t now = 0;
42 void do_at_exit()
44 s.Submit();
45 s.ExtractQueue();
46 Log(llInfo, "Shutting down...");
47 if (remove(Config.file_pid.c_str()) != 0)
48 Log(llInfo, "Couldn't remove pid file!");
51 void signal_handler(int)
53 exit(0);
57 int main(int argc, char **argv)
59 DefaultConfiguration(Config);
61 if (argc > 1)
63 ParseArgv(Config, argc, argv);
65 if (!Config.file_config.empty())
67 if (!ReadConfiguration(Config, Config.file_config))
69 std::cerr << "cannot read configuration file: " << Config.file_config << std::endl;
70 return 1;
73 else if (!ReadConfiguration(Config, Config.user_home_folder + "/.scrobbyconf"))
75 if (!ReadConfiguration(Config, "/etc/scrobby.conf"))
77 std::cerr << "default configuration files not found!\n";
78 return 1;
81 if (Config.log_level == llUndefined)
83 Config.log_level = llInfo;
85 if (Config.lastfm_user.empty() || (Config.lastfm_md5_password.empty() && Config.lastfm_password.empty()))
87 std::cerr << "last.fm user/password is not set.\n";
88 return 1;
90 ChangeToUser();
91 if (!CheckFiles(Config))
93 return 1;
95 if (Config.daemonize)
97 if (!Daemonize())
98 std::cerr << "couldn't daemonize!\n";
101 MPD::Song::GetCached();
103 MPD::Connection *Mpd = new MPD::Connection;
105 if (Config.mpd_host != "localhost")
106 Mpd->SetHostname(Config.mpd_host);
107 if (Config.mpd_port != 6600)
108 Mpd->SetPort(Config.mpd_port);
110 Mpd->SetTimeout(Config.mpd_timeout);
111 Mpd->SetStatusUpdater(ScrobbyStatusChanged, NULL);
112 Mpd->SetErrorHandler(ScrobbyErrorCallback, NULL);
114 signal(SIGHUP, signal_handler);
115 signal(SIGINT, signal_handler);
116 signal(SIGTERM, signal_handler);
117 signal(SIGPIPE, SIG_IGN);
119 atexit(do_at_exit);
121 int handshake_delay = 0;
122 int queue_delay = 0;
123 int mpd_delay = 0;
125 time_t handshake_ts = 0;
126 time_t queue_ts = 0;
127 time_t mpd_ts = 0;
129 while (!sleep(1))
131 time(&now);
133 if (now > handshake_ts && !myHandshake.OK())
135 myHandshake.Clear();
136 if (myHandshake.Send() && !myHandshake.Status.empty())
138 Log(llInfo, "Handshake returned %s", myHandshake.Status.c_str());
140 if (myHandshake.OK())
142 Log(llInfo, "Connected to Audioscrobbler!");
143 handshake_delay = 0;
145 else
147 handshake_delay += 20;
148 Log(llInfo, "Connection to Audioscrobbler refused, retrieving in %d seconds...", handshake_delay);
149 handshake_ts = time(0)+handshake_delay;
153 if (Mpd->Connected())
155 Mpd->UpdateStatus();
157 else if (now > mpd_ts)
159 s.Submit();
160 Log(llVerbose, "Connecting to MPD...");
161 if (Mpd->Connect())
163 Log(llInfo, "Connected to MPD at %s !", Config.mpd_host.c_str());
164 mpd_delay = 0;
166 else
168 mpd_delay += 10;
169 Log(llInfo, "Cannot connect to MPD, retrieving in %d seconds...", mpd_delay);
170 mpd_ts = time(0)+mpd_delay;
174 if (now > queue_ts && (!MPD::Song::SubmitQueue.empty() || !MPD::Song::Queue.empty()))
176 if (!MPD::Song::SendQueue())
178 queue_delay += 30;
179 Log(llInfo, "Submission failed, retrieving in %d seconds...", queue_delay);
180 queue_ts = time(0)+queue_delay;
182 else
183 queue_delay = 0;
186 return 0;
189 bool Handshake::Send()
191 CURLcode code;
192 string handshake_url;
193 string result;
194 string timestamp = IntoStr(time(NULL));
196 handshake_url = "http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=mpc&v="VERSION"&u=";
197 handshake_url += Config.lastfm_user;
198 handshake_url += "&t=";
199 handshake_url += timestamp;
200 handshake_url += "&a=";
201 handshake_url += md5sum((Config.lastfm_md5_password.empty() ? md5sum(Config.lastfm_password) : Config.lastfm_md5_password) + timestamp);
203 CURL *hs = curl_easy_init();
204 curl_easy_setopt(hs, CURLOPT_URL, handshake_url.c_str());
205 curl_easy_setopt(hs, CURLOPT_WRITEFUNCTION, write_data);
206 curl_easy_setopt(hs, CURLOPT_WRITEDATA, &result);
207 curl_easy_setopt(hs, CURLOPT_CONNECTTIMEOUT, curl_connecttimeout);
208 curl_easy_setopt(hs, CURLOPT_TIMEOUT, curl_timeout);
209 curl_easy_setopt(hs, CURLOPT_DNS_CACHE_TIMEOUT, 0);
210 curl_easy_setopt(hs, CURLOPT_NOPROGRESS, 1);
211 curl_easy_setopt(hs, CURLOPT_NOSIGNAL, 1);
212 code = curl_easy_perform(hs);
213 curl_easy_cleanup(hs);
215 if (code != CURLE_OK)
217 Log(llInfo, "Error while sending handshake: %s", curl_easy_strerror(code));
218 return false;
221 size_t i = result.find("\n");
222 Status = result.substr(0, i);
223 if (Status != "OK")
225 if (Status == "BANNED")
227 Log(llInfo, "Ops, this version of scrobby is banned. Please update to the newest one or if it's the newest, inform me about it (electricityispower@gmail.com)");
229 else if (Status == "BADAUTH")
231 Log(llInfo, "User authentication failed. Please recheck your username/password settings.");
233 else
234 return false;
235 exit(1);
237 result = result.substr(i+1);
238 i = result.find("\n");
239 SessionID = result.substr(0, i);
240 result = result.substr(i+1);
241 i = result.find("\n");
242 NowPlayingURL = result.substr(0, i);
243 result = result.substr(i+1);
244 IgnoreNewlines(result);
245 SubmissionURL = result;
246 return true;