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
;
41 void signal_handler(int);
43 bool handshake_sent_properly();
46 int main(int argc
, char **argv
)
48 DefaultConfiguration(Config
);
52 ParseArgv(Config
, argc
, argv
);
54 if (!Config
.file_config
.empty())
56 if (!ReadConfiguration(Config
, Config
.file_config
))
58 std::cerr
<< "cannot read configuration file: " << Config
.file_config
<< std::endl
;
62 else if (!ReadConfiguration(Config
, Config
.user_home_folder
+ "/.scrobbyconf"))
64 if (!ReadConfiguration(Config
, "/etc/scrobby.conf"))
66 std::cerr
<< "default configuration files not found!\n";
70 if (Config
.log_level
== llUndefined
)
72 Config
.log_level
= llInfo
;
74 if (Config
.lastfm_user
.empty() || (Config
.lastfm_md5_password
.empty() && Config
.lastfm_password
.empty()))
76 std::cerr
<< "last.fm user/password is not set.\n";
80 if (!CheckFiles(Config
))
87 std::cerr
<< "couldn't daemonize!\n";
90 MPD::Song::GetCached();
92 MPD::Connection
*Mpd
= new MPD::Connection
;
94 if (Config
.mpd_host
!= "localhost")
95 Mpd
->SetHostname(Config
.mpd_host
);
96 if (Config
.mpd_port
!= 6600)
97 Mpd
->SetPort(Config
.mpd_port
);
99 Mpd
->SetTimeout(Config
.mpd_timeout
);
100 Mpd
->SetStatusUpdater(ScrobbyStatusChanged
, NULL
);
101 Mpd
->SetErrorHandler(ScrobbyErrorCallback
, NULL
);
103 signal(SIGHUP
, signal_handler
);
104 signal(SIGINT
, signal_handler
);
105 signal(SIGTERM
, signal_handler
);
106 signal(SIGPIPE
, SIG_IGN
);
110 int handshake_delay
= 0;
114 time_t handshake_ts
= 0;
120 if (now
> handshake_ts
&& myHandshake
.Status
!= "OK")
123 if (handshake_sent_properly() && !myHandshake
.Status
.empty())
125 Log(llInfo
, "Handshake returned %s", myHandshake
.Status
.c_str());
127 if (myHandshake
.Status
== "OK")
129 Log(llInfo
, "Connected to Audioscrobbler!");
134 handshake_delay
+= 10;
135 Log(llInfo
, "Connection to Audioscrobbler refused, retrieving in %d seconds...", handshake_delay
);
136 handshake_ts
= time(0)+handshake_delay
;
139 if (Mpd
->Connected())
143 else if (now
> mpd_ts
)
146 Log(llVerbose
, "Connecting to MPD...");
149 Log(llInfo
, "Connected to MPD at %s !", Config
.mpd_host
.c_str());
155 Log(llInfo
, "Cannot connect to MPD, retrieving in %d seconds...", mpd_delay
);
156 mpd_ts
= time(0)+mpd_delay
;
168 Log(llInfo
, "Shutting down...");
169 if (remove(Config
.file_pid
.c_str()) != 0)
170 Log(llInfo
, "Couldn't remove pid file!");
173 void signal_handler(int)
178 bool handshake_sent_properly()
181 string handshake_url
;
183 string timestamp
= IntoStr(time(NULL
));
185 handshake_url
= "http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=mpc&v="VERSION
"&u=";
186 handshake_url
+= Config
.lastfm_user
;
187 handshake_url
+= "&t=";
188 handshake_url
+= timestamp
;
189 handshake_url
+= "&a=";
190 handshake_url
+= md5sum((Config
.lastfm_md5_password
.empty() ? md5sum(Config
.lastfm_password
) : Config
.lastfm_md5_password
) + timestamp
);
192 CURL
*hs
= curl_easy_init();
193 curl_easy_setopt(hs
, CURLOPT_URL
, handshake_url
.c_str());
194 curl_easy_setopt(hs
, CURLOPT_WRITEFUNCTION
, write_data
);
195 curl_easy_setopt(hs
, CURLOPT_WRITEDATA
, &result
);
196 curl_easy_setopt(hs
, CURLOPT_CONNECTTIMEOUT
, curl_connecttimeout
);
197 curl_easy_setopt(hs
, CURLOPT_TIMEOUT
, curl_timeout
);
198 curl_easy_setopt(hs
, CURLOPT_DNS_CACHE_TIMEOUT
, 0);
199 curl_easy_setopt(hs
, CURLOPT_NOPROGRESS
, 1);
200 curl_easy_setopt(hs
, CURLOPT_NOSIGNAL
, 1);
201 code
= curl_easy_perform(hs
);
202 curl_easy_cleanup(hs
);
204 if (code
!= CURLE_OK
)
206 Log(llInfo
, "Error while sending handshake: %s", curl_easy_strerror(code
));
210 size_t i
= result
.find("\n");
211 myHandshake
.Status
= result
.substr(0, i
);
212 if (myHandshake
.Status
!= "OK")
214 result
= result
.substr(i
+1);
215 i
= result
.find("\n");
216 myHandshake
.SessionID
= result
.substr(0, i
);
217 result
= result
.substr(i
+1);
218 i
= result
.find("\n");
219 myHandshake
.NowPlayingURL
= result
.substr(0, i
);
220 result
= result
.substr(i
+1);
221 IgnoreNewlines(result
);
222 myHandshake
.SubmissionURL
= result
;