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 ***************************************************************************/
23 #include <curl/curl.h>
27 #include "configuration.h"
35 Handshake myHandshake
;
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)
57 int main(int argc
, char **argv
)
59 DefaultConfiguration(Config
);
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
;
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";
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";
91 if (!CheckFiles(Config
))
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
);
121 int handshake_delay
= 0;
125 time_t handshake_ts
= 0;
133 if (now
> handshake_ts
&& !myHandshake
.OK())
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!");
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())
157 else if (now
> mpd_ts
)
160 Log(llVerbose
, "Connecting to MPD...");
163 Log(llInfo
, "Connected to MPD at %s !", Config
.mpd_host
.c_str());
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())
179 Log(llInfo
, "Submission failed, retrieving in %d seconds...", queue_delay
);
180 queue_ts
= time(0)+queue_delay
;
189 bool Handshake::Send()
192 string handshake_url
;
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
));
221 size_t i
= result
.find("\n");
222 Status
= result
.substr(0, i
);
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.");
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
;