1 /* gmpc-lastfmradio (GMPC plugin)
2 * Copyright (C) 2008-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <gmpc/plugin.h>
25 #include <gmpc/config1.h>
26 #include <gmpc/gmpc_easy_download.h>
27 #include "lfr_plugin.h"
31 #define HANDSHAKE "http://ws.audioscrobbler.com/radio/handshake.php?version=1.1.1&platform=linux&username=%s&passwordmd5=%s&debug=0&partner="
32 #define REQURL "http://ws.audioscrobbler.com/radio/adjust.php?session=%s&url=lastfm://%s/%s%s&debug=0"
33 #define NPURL "http://ws.audioscrobbler.com/radio/np.php?session=%s"
35 #define BUFFER_SIZE 256
38 QUERY_TYPE_PLAYSTREAM,
42 typedef struct _Query{
48 char buffer[BUFFER_SIZE];
55 class Last:FM from G:Object
57 private gchar *username = {cfg_get_single_value_as_string(config,CONFIG_NAME, "username")} destroywith g_free;
58 private gchar *password_md5 = {cfg_get_single_value_as_string(config,CONFIG_NAME, "password")} destroywith g_free;
59 private gchar *sessionid = {NULL} destroywith g_free;
60 private gchar *stream_url = {NULL} destroywith g_free;
65 file_stream_read_done(GEADAsyncHandler *handle, GEADStatus status ,gpointer data)
68 Self *self = SELF(q->self);
69 if(status == GEAD_PROGRESS)
71 self_processing(self, TRUE);
74 if(status == GEAD_FAILED || status == GEAD_CANCELLED)
76 gchar *msg = g_markup_printf_escaped("Failed to read from Last.FM: %s",
77 gmpc_easy_handler_get_uri(handle));
78 self_error_callback(self,TRUE,msg);
83 if(status == GEAD_DONE)
86 q->data = (char *)gmpc_easy_handler_get_data(handle, &(length));
87 q->data_size = length;
88 if(q->type == QUERY_TYPE_SESSION)
90 gchar **lines = g_strsplit(q->data, "\n", 0);
92 for(i=0; lines && lines[i];i++) {
93 gchar **values = g_strsplit(lines[i], "=", 2);
95 if(strcmp(values[0], "session") == 0)
97 self->_priv->sessionid = g_strdup(values[1]);
99 else if (strcmp(values[0], "stream_url") == 0)
101 self->_priv->stream_url = g_strdup(values[1]);
107 self_connection_changed(self, self_is_connected(self));
108 if(self->_priv->sessionid == NULL || self->_priv->stream_url == NULL){
109 self_error_callback(self, TRUE,"Last.FM: Invalid password or username");
112 else if (q->type == QUERY_TYPE_PLAYSTREAM)
114 if(strncmp(q->data, "response=OK", strlen("response=OK")) == 0)
115 self_play_stream(self, self->_priv->stream_url);
117 self_error_callback(self, FALSE,"Last.FM: Radio station is not playable");
119 }else if (q->type == QUERY_TYPE_NP)
121 mpd_Song *song = mpd_newSong();
122 gchar **lines = g_strsplit(q->data, "\n", 0);
124 for(i=0; lines && lines[i];i++) {
125 gchar **values = g_strsplit(lines[i], "=", 2);
126 if(values && values[0] && values[1]) {
127 if(strcmp(values[0], "artist") == 0)
129 song->artist = g_strdup(values[1]);
131 else if (strcmp(values[0], "album") == 0)
133 song->album = g_strdup(values[1]);
135 else if (strcmp(values[0], "track") == 0)
137 song->title = g_strdup(values[1]);
143 if(song->artist && song->title)
145 self_song_info_available(self, song);
147 self_error_callback(self, FALSE,"Last.FM: Insufficient song information available");
148 self_song_info_available(self, NULL);
157 self_processing(self, FALSE);
164 do_playstream(self, const gchar *url)
167 if(self->_priv->sessionid == NULL) return;
168 self_processing(self, TRUE);
169 q = g_malloc0(sizeof(*q));
171 q->file = g_strdup(url);
172 q->type = QUERY_TYPE_PLAYSTREAM;
174 gmpc_easy_async_downloader(q->file,self_file_stream_read_done,q);
193 return (self->_priv->sessionid != NULL && self->_priv->stream_url);
198 signal last NONE (BOOLEAN)
200 connection_changed(self, gboolean connected)
204 signal last NONE (STRING)
206 play_stream(self,gchar *stream)
210 signal last NONE (BOOLEAN)
212 processing(self, gboolean processing)
216 signal last NONE (POINTER)
218 song_info_available(self, mpd_Song *song)
225 signal last NONE (BOOLEAN,STRING)
227 error_callback(self, gboolean fatal,const gchar *errormsg)
236 return self->_priv->username;
242 return self->_priv->stream_url;
246 set_login(self, const gchar *username, const gchar *password)
248 self->_priv->username = g_strdup(username);
251 const gchar *chk = NULL;
252 GChecksum *ck = g_checksum_new(G_CHECKSUM_MD5);
253 g_checksum_update(ck,(guchar *)password, -1);
254 chk = g_checksum_get_string(ck);
256 self->_priv->password_md5 = g_strdup(chk);
259 cfg_set_single_value_as_string(config,CONFIG_NAME, "username", self->_priv->username);
260 cfg_set_single_value_as_string(config, CONFIG_NAME, "password", self->_priv->password_md5);
268 /* check requirments */
269 if(self->_priv->username == NULL || self->_priv->password_md5 == NULL) return;
271 /* If we have a session reset it. and signal disconnect */
272 if(self->_priv->stream_url) { g_free(self->_priv->stream_url); self->_priv->stream_url = NULL; }
273 if(self->_priv->sessionid) { g_free(self->_priv->sessionid); self->_priv->sessionid = NULL; }
274 self_connection_changed(self, self_is_connected(self));
275 self_processing(self, TRUE);
276 /* Create request url */
277 url = g_strdup_printf(HANDSHAKE, self->_priv->username, self->_priv->password_md5);
279 q = g_malloc0(sizeof(*q));
282 q->type = QUERY_TYPE_SESSION;
284 gmpc_easy_async_downloader(q->file,self_file_stream_read_done,q);
288 * Different play things
292 play_artist_radio(self, const gchar *artist)
296 if(self->_priv->sessionid == NULL) return;
297 temp = gmpc_easy_download_uri_escape(artist);
298 url = g_strdup_printf(REQURL, self->_priv->sessionid, "artist", temp,"");
299 self_do_playstream(self, url);
305 play_similar_artist_radio(self, const gchar *artist)
309 if(self->_priv->sessionid == NULL) return;
310 temp = gmpc_easy_download_uri_escape(artist);
311 url = g_strdup_printf(REQURL, self->_priv->sessionid, "artist", temp,"/similarartists");
312 self_do_playstream(self, url);
319 play_tag_radio(self, const gchar *artist)
323 if(self->_priv->sessionid == NULL) return;
324 temp = gmpc_easy_download_uri_escape(artist);
325 url = g_strdup_printf(REQURL, self->_priv->sessionid, "globaltags", temp,"");
326 self_do_playstream(self, url);
332 play_group_radio(self, const gchar *artist)
336 if(self->_priv->sessionid == NULL) return;
337 temp = gmpc_easy_download_uri_escape(artist);
338 url = g_strdup_printf(REQURL, self->_priv->sessionid, "group", temp,"");
339 self_do_playstream(self, url);
345 play_user_radio(self,const gchar *artist)
349 if(self->_priv->sessionid == NULL) return;
351 temp = gmpc_easy_download_uri_escape(artist);
353 temp = gmpc_easy_download_uri_escape(self->_priv->username);
354 url = g_strdup_printf(REQURL, self->_priv->sessionid, "user", temp,"/personal");
355 self_do_playstream(self, url);
361 play_neighbours_radio(self,const gchar *artist)
365 if(self->_priv->sessionid == NULL) return;
368 temp = gmpc_easy_download_uri_escape(artist);
370 temp = gmpc_easy_download_uri_escape(self->_priv->username);
371 url = g_strdup_printf(REQURL, self->_priv->sessionid, "user", temp,"/neighbours");
372 self_do_playstream(self, url);
378 play_recommendations (self)
382 if(self->_priv->sessionid == NULL) return;
383 temp = gmpc_easy_download_uri_escape(self->_priv->username);
384 url = g_strdup_printf(REQURL, self->_priv->sessionid, "user", temp,"/recommended");
385 self_do_playstream(self, url);
391 play_loved_radio (self)
395 if(self->_priv->sessionid == NULL) return;
396 temp = gmpc_easy_download_uri_escape(self->_priv->username);
397 url = g_strdup_printf(REQURL, self->_priv->sessionid, "user", temp,"/loved");
398 self_do_playstream(self, url);
406 get_current_song (self)
410 /* check requirments */
411 if(self->_priv->username == NULL || self->_priv->password_md5 == NULL) return;
412 self_processing(self, TRUE);
413 /* Create request url */
414 url = g_strdup_printf(NPURL, self->_priv->sessionid);
416 q = g_malloc0(sizeof(*q));
419 q->type = QUERY_TYPE_NP;
420 gmpc_easy_async_downloader(q->file,self_file_stream_read_done,q);