Update autogen.sh
[gmpc-lastfmradio.git] / src / last-fm.gob
blobd6ffb59a386ae2f60f696074a120edfeeed5b54a
1 /* gmpc-lastfmradio (GMPC plugin)
2  * Copyright (C) 2008-2009 Qball Cow <qball@sarine.nl>
3  * Project homepage: http://gmpcwiki.sarine.nl/
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.
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.
20 requires 2.0.10
22 %h{
23 #include <config.h>
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 
36 typedef enum {
37     QUERY_TYPE_SESSION,
38     QUERY_TYPE_PLAYSTREAM,
39     QUERY_TYPE_NP
40 }QueryType;
42 typedef struct _Query{
43     gchar       *file;
44     QueryType type;
45     LastFM      *self;
47     /* private */
48     char    buffer[BUFFER_SIZE];
49     char    *data;
50     gsize   data_size;
51 }Query;
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;
63     private
64     void
65     file_stream_read_done(GEADAsyncHandler *handle, GEADStatus status ,gpointer data)
66     {
67         Query *q = data;
68         Self *self = SELF(q->self);
69         if(status == GEAD_PROGRESS)
70         {
71             self_processing(self, TRUE);
72             return;
73         }
74         if(status == GEAD_FAILED || status == GEAD_CANCELLED) 
75         {
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);
79             g_free(msg);
80             g_free(q->file);
81             g_free(q);
82         }
83         if(status == GEAD_DONE)
84         {
85             goffset length;
86             q->data = (char *)gmpc_easy_handler_get_data(handle, &(length));
87             q->data_size = length;
88             if(q->type == QUERY_TYPE_SESSION)
89             {
90                 gchar **lines = g_strsplit(q->data, "\n", 0);
91                 int i;
92                 for(i=0; lines && lines[i];i++) {
93                     gchar **values = g_strsplit(lines[i], "=", 2);
94                     if(values) {
95                         if(strcmp(values[0], "session") == 0)
96                         {
97                             self->_priv->sessionid = g_strdup(values[1]);
98                         }
99                         else if (strcmp(values[0], "stream_url") == 0)
100                         {
101                             self->_priv->stream_url = g_strdup(values[1]);
102                         }
103                     }
104                     g_strfreev(values);
105                 }
106                 g_strfreev(lines);
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");
110                 }
111             }
112             else if (q->type == QUERY_TYPE_PLAYSTREAM)
113             {
114                 if(strncmp(q->data, "response=OK", strlen("response=OK")) == 0)
115                     self_play_stream(self, self->_priv->stream_url);
116                 else
117                     self_error_callback(self, FALSE,"Last.FM: Radio station is not playable");
119             }else if (q->type == QUERY_TYPE_NP)
120             {
121                 mpd_Song *song = mpd_newSong();
122                 gchar **lines = g_strsplit(q->data, "\n", 0);
123                 int i;
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)
128                         {
129                              song->artist = g_strdup(values[1]);
130                         }
131                         else if (strcmp(values[0], "album") == 0)
132                         {
133                             song->album = g_strdup(values[1]);
134                         }
135                         else if (strcmp(values[0], "track") == 0)
136                         {
137                             song->title = g_strdup(values[1]);
138                         }
139                     }
140                     g_strfreev(values);
141                 }
142                 g_strfreev(lines);
143                 if(song->artist && song->title)
144                 {
145                     self_song_info_available(self, song);
146                     }else{
147                         self_error_callback(self, FALSE,"Last.FM: Insufficient song information available");
148                         self_song_info_available(self, NULL);
149                     }
150                 mpd_freeSong(song);
151             }
153             g_free(q->file);
154             g_free(q);
155         }
157         self_processing(self, FALSE);
158         return;
159     }
162     private 
163     void
164     do_playstream(self, const gchar *url)
165     {
166         Query *q;
167         if(self->_priv->sessionid == NULL) return;
168         self_processing(self, TRUE);
169         q = g_malloc0(sizeof(*q)); 
170         q->self = self;
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);
175     }
179     /**
180      * Public stuff
181      */
182     public
183     Last:FM
184     *new (void)
185     {
186         return GET_NEW;
187     }
189     public
190     gboolean
191     is_connected(self)
192     {
193         return (self->_priv->sessionid != NULL && self->_priv->stream_url);
194     }
195     /**
196      * Signals
197      */
198     signal last NONE (BOOLEAN)
199     void
200     connection_changed(self, gboolean connected)
201     {
202     }
204     signal last NONE (STRING)
205     void
206     play_stream(self,gchar *stream)
207     {
208     }
210     signal last NONE (BOOLEAN)
211     void
212     processing(self, gboolean processing)
213     {
214     }
216     signal last NONE (POINTER)
217     void
218     song_info_available(self, mpd_Song *song)
219     {
221     }
222     /**
223      *
224      */
225     signal last NONE (BOOLEAN,STRING)
226     void
227     error_callback(self, gboolean fatal,const gchar *errormsg)
228     {
230     }
232     public 
233     const gchar *
234     get_username(self)
235     {
236         return self->_priv->username;
237     }
238     public
239     const gchar *
240     get_stream_url(self)
241     {
242         return self->_priv->stream_url;
243     }
245     public void
246     set_login(self, const gchar *username, const gchar *password)
247     {
248         self->_priv->username = g_strdup(username);
249         /* Calc checksum */
250         if(password) {
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);
255             if(chk)
256                 self->_priv->password_md5 = g_strdup(chk);
257             g_checksum_free(ck);
258         }
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);
261     }
263     public void
264     connect(self)
265     {
266         gchar *url;
267         Query *q;
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)); 
280         q->self = self;
281         q->file = url;
282         q->type = QUERY_TYPE_SESSION; 
284         gmpc_easy_async_downloader(q->file,self_file_stream_read_done,q);
285         
286     }
287     /* 
288      * Different play things
289      */
290     public
291     void
292     play_artist_radio(self, const gchar *artist)
293     {
294         gchar *url;
295         gchar *temp;
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);
300         g_free(temp);
301         g_free(url);
302     }
303     public
304     void
305     play_similar_artist_radio(self, const gchar *artist)
306     {
307         gchar *url;
308         gchar *temp;
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);
313         g_free(temp);
314         g_free(url);
315     }
317     public
318         void
319     play_tag_radio(self, const gchar *artist)
320     {
321         gchar *url;
322         gchar *temp;
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);
327         g_free(temp);
328         g_free(url);
329     }
330    public
331         void
332     play_group_radio(self, const gchar *artist)
333     {
334         gchar *url;
335         gchar *temp;
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);
340         g_free(temp);
341         g_free(url);
342     }
343     public
344     void
345     play_user_radio(self,const gchar *artist)
346     {
347         gchar *url;
348         gchar *temp;
349         if(self->_priv->sessionid == NULL) return;
350         if(artist)
351             temp = gmpc_easy_download_uri_escape(artist);
352         else
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);
356         g_free(temp);
357         g_free(url);
358     }
359     public
360     void
361     play_neighbours_radio(self,const gchar *artist)
362     {
363         gchar *url;
364         gchar *temp;
365         if(self->_priv->sessionid == NULL) return;
366     
367         if(artist)
368             temp = gmpc_easy_download_uri_escape(artist);
369         else
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);
373         g_free(temp);
374         g_free(url);
375     }
376     public
377     void
378     play_recommendations (self)
379     {
380         gchar *url;
381         gchar *temp;
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);
386         g_free(temp);
387         g_free(url);
388     }
389     public
390     void
391     play_loved_radio (self)
392     {
393         gchar *url;
394         gchar *temp;
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);
399         g_free(temp);
400         g_free(url);
401     }
404     public
405     void
406     get_current_song (self)
407     {
408         gchar *url;
409         Query *q;
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)); 
417         q->self = self;
418         q->file = url;
419         q->type = QUERY_TYPE_NP; 
420         gmpc_easy_async_downloader(q->file,self_file_stream_read_done,q);
421     }