1 /***************************************************************************
2 * Copyright (C) 2008 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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
23 #include <curl/curl.h>
28 #include "configuration.h"
36 Handshake myHandshake
;
42 void signal_handler(int);
44 bool handshake_sent_properly();
47 int main(int argc
, char **argv
)
49 DefaultConfiguration(Config
);
53 ParseArgv(Config
, argc
, argv
);
55 if (!Config
.file_config
.empty())
57 if (!ReadConfiguration(Config
, Config
.file_config
))
59 std::cerr
<< "cannot read configuration file: " << Config
.file_config
<< std::endl
;
63 else if (!ReadConfiguration(Config
, Config
.user_home_folder
+ "/.scrobbyconf"))
65 if (!ReadConfiguration(Config
, "/etc/scrobby.conf"))
67 std::cerr
<< "default configuration files not found!\n";
71 if (Config
.log_level
== llUndefined
)
73 Config
.log_level
= llInfo
;
75 if (Config
.lastfm_user
.empty() || (Config
.lastfm_md5_password
.empty() && Config
.lastfm_password
.empty()))
77 std::cerr
<< "last.fm user/password is not set.\n";
81 if (!CheckFiles(Config
))
88 std::cerr
<< "couldn't daemonize!\n";
91 MPD::Song::GetCached();
93 MPD::Connection
*Mpd
= new MPD::Connection
;
95 if (Config
.mpd_host
!= "localhost")
96 Mpd
->SetHostname(Config
.mpd_host
);
97 if (Config
.mpd_port
!= 6600)
98 Mpd
->SetPort(Config
.mpd_port
);
100 Mpd
->SetTimeout(Config
.mpd_timeout
);
101 Mpd
->SetStatusUpdater(ScrobbyStatusChanged
, NULL
);
102 Mpd
->SetErrorHandler(ScrobbyErrorCallback
, NULL
);
104 signal(SIGHUP
, signal_handler
);
105 signal(SIGINT
, signal_handler
);
106 signal(SIGTERM
, signal_handler
);
107 signal(SIGPIPE
, SIG_IGN
);
111 int handshake_delay
= 0;
115 time_t handshake_ts
= 0;
118 while (!usleep(500000))
121 if (now
> handshake_ts
&& myHandshake
.Status
!= "OK")
124 if (handshake_sent_properly() && !myHandshake
.Status
.empty())
126 Log(llInfo
, "Handshake returned %s", myHandshake
.Status
.c_str());
128 if (myHandshake
.Status
== "OK")
130 Log(llInfo
, "Connected to Audioscrobbler!");
135 handshake_delay
+= 10;
136 Log(llInfo
, "Connection to Audioscrobbler refused, retrieving in %d seconds...", handshake_delay
);
137 handshake_ts
= time(0)+handshake_delay
;
140 if (Mpd
->Connected())
144 else if (now
> mpd_ts
)
147 Log(llVerbose
, "Connecting to MPD...");
150 Log(llInfo
, "Connected to MPD at %s !", Config
.mpd_host
.c_str());
156 Log(llInfo
, "Cannot connect to MPD, retrieving in %d seconds...", mpd_delay
);
157 mpd_ts
= time(0)+mpd_delay
;
169 Log(llInfo
, "Shutting down...");
170 if (remove(Config
.file_pid
.c_str()) != 0)
171 Log(llInfo
, "Couldn't remove pid file!");
174 void signal_handler(int)
179 bool handshake_sent_properly()
182 string handshake_url
;
184 string timestamp
= IntoStr(time(NULL
));
186 handshake_url
= "http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=mpc&v="VERSION
"&u=";
187 handshake_url
+= Config
.lastfm_user
;
188 handshake_url
+= "&t=";
189 handshake_url
+= timestamp
;
190 handshake_url
+= "&a=";
191 handshake_url
+= md5sum((Config
.lastfm_md5_password
.empty() ? md5sum(Config
.lastfm_password
) : Config
.lastfm_md5_password
) + timestamp
);
193 CURL
*hs
= curl_easy_init();
194 curl_easy_setopt(hs
, CURLOPT_URL
, handshake_url
.c_str());
195 curl_easy_setopt(hs
, CURLOPT_WRITEFUNCTION
, write_data
);
196 curl_easy_setopt(hs
, CURLOPT_WRITEDATA
, &result
);
197 curl_easy_setopt(hs
, CURLOPT_CONNECTTIMEOUT
, curl_timeout
);
198 code
= curl_easy_perform(hs
);
199 curl_easy_cleanup(hs
);
201 if (code
!= CURLE_OK
)
203 Log(llInfo
, "Error while sending handshake: %s", curl_easy_strerror(code
));
207 size_t i
= result
.find("\n");
208 myHandshake
.Status
= result
.substr(0, i
);
209 if (myHandshake
.Status
!= "OK")
211 result
= result
.substr(i
+1);
212 i
= result
.find("\n");
213 myHandshake
.SessionID
= result
.substr(0, i
);
214 result
= result
.substr(i
+1);
215 i
= result
.find("\n");
216 myHandshake
.NowPlayingURL
= result
.substr(0, i
);
217 result
= result
.substr(i
+1);
218 IgnoreNewlines(result
);
219 myHandshake
.SubmissionURL
= result
;