changeset 1217:d4efe4889489

rendered the lastfm transport plugin stable again, preparing it for its GUI
author Cristi Magherusan <majeru@atheme-project.org>
date Mon, 09 Jul 2007 05:01:16 +0300
parents cc04ccffaa8d
children cc4e03df48a3
files src/lastfm/lastfm.c src/lastfm/lastfm.h
diffstat 2 files changed, 263 insertions(+), 351 deletions(-) [+]
line wrap: on
line diff
--- a/src/lastfm/lastfm.c	Sun Jul 08 22:26:25 2007 +0300
+++ b/src/lastfm/lastfm.c	Mon Jul 09 05:01:16 2007 +0300
@@ -28,6 +28,17 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+  Current status and known issues:
+   - Works fine ant is relatively stable unless DEBUG is enabled (read below)
+   - The adjust fails when having 2 or more opened streams at the same time.
+        * It will randomly adjust to any one of them, because the playlist keeps 
+        pulling metadata
+   - When the network is disconnected opening a new track freezes the player 
+        * This seems to recover after the connection is restablished
+        * Ordinary mp3 streams seem to share this behavior. Didnt tested if others do.
+*/
+
 #include <audacious/vfs.h>
 #include <audacious/plugin.h>
 #include <audacious/configdb.h>
@@ -36,7 +47,10 @@
 #include <glib.h>
 #include "lastfm.h"
 
-#define DEBUG 1 
+#define DEBUG 0  
+/*Caution!!! setting DEBUG to 1 is very likely to crash the player because the g_print-ed values
+aren't checked of being !=NULL
+*/
 
 size_t lastfm_store_res(void *ptr, size_t size, size_t nmemb, void *udata)
 {
@@ -49,7 +63,7 @@
 {
         CURL *curl = curl_easy_init();
         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
-        curl_easy_setopt(curl, CURLOPT_USERAGENT, "mplayer");
+        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Audacious");
         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, lastfm_store_res);
         curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
@@ -61,503 +75,399 @@
         return status;
 }
 
-gchar* lastfm_get_login_uri()
-{
-#if DEBUG
-        g_print("Getting login data from config\n");
-#endif
-
-        ConfigDb *cfgfile = NULL;
+gchar* lastfm_get_login_uri()  /* reads the audioscrobbler login data from the config */
+{                              /* and then uses them to create a login URL*/
+        ConfigDb *cfg = NULL;
         gchar   *buf=NULL,
                 *username = NULL, 
                 *password = NULL;
-        if ((cfgfile = bmp_cfg_db_open()) != NULL)
+        if ((cfg = bmp_cfg_db_open()) != NULL)
         {
-                bmp_cfg_db_get_string(cfgfile, "audioscrobbler","username",
+                bmp_cfg_db_get_string(cfg, "audioscrobbler","username",
                                 &username);
-                bmp_cfg_db_get_string(cfgfile, "audioscrobbler","password",
+                bmp_cfg_db_get_string(cfg, "audioscrobbler","password",
                                 &password);
-                g_free(cfgfile);
+                g_free(cfg);
         }
         if (username != NULL && password != NULL)
         {
-#if DEBUG
-        g_print("Creating the login URI\n");
-#endif
-
                 buf=g_strdup_printf(LASTFM_HANDSHAKE_URL, username, password);
                 g_free(password);
                 g_free(username);
-#if DEBUG
-                g_print("Succesfully created the login uri\n");
-#endif
                 return buf;
         }
-        else {
+        else 
+        {
 #if DEBUG
                 g_print("Couldn't find the login data. Use the scrobbler plugin to set it up.\n");
 #endif
-
-        return NULL;
+                return NULL;
         }
 }
 
-void lastfm_store(gchar *var_name,gchar* var){
-if (mowgli_global_storage_get(var_name))
-                mowgli_global_storage_free(var_name);
+        void lastfm_store(gchar *var_name,gchar* var){  /*mowgli storage wrapper*/
+                if (mowgli_global_storage_get(var_name))
+                        mowgli_global_storage_free(var_name);
+                mowgli_global_storage_put(var_name,var);
+        }
 
-        mowgli_global_storage_put(var_name,var);
-#if DEBUG
-        g_print("Storing into '%s' the value '%s'\n",var_name,var);
-#endif
-}
-
-int lastfm_login(void)
+int lastfm_login(void)  /*gets the session ID and the mp3 stream URL and stores them*/
 {
-        /*gets the session ID in the URL to be played and stores them using 
-         * mowgli_global_storage
-         * read http://gabistapler.de/blog/index.php?/archives/268-Play-last.fm-streams-without-the-player.html for more info
-         */
-      
-        gint status, i;
-        gchar   *lastfm_session_id=NULL, 
-                *lastfm_stream_uri=NULL,
-                *login_uri=NULL,
+        gint    status, i,
+                ret=LASTFM_LOGIN_OK; /*suppose everything goes fine*/
+        gchar   *login_uri=NULL,
                 **split = NULL;
-        GString *res = g_string_new(NULL);
-g_print("Logging in\n");
+        GString *res;
         login_uri=lastfm_get_login_uri();
-        if(login_uri==NULL){
+        if(login_uri==NULL)
+        {
                 g_free(login_uri);
                 return LASTFM_MISSING_LOGIN_DATA;
-                }
+        }
+        res = g_string_new(NULL);
         status = lastfm_get_data_from_uri(login_uri, res);
 #if DEBUG
         g_print("Opened login URI: '%s'\n", login_uri);
         g_print("Got following data: '%s'\n", res->str);
 #endif
-
         if (status == CURLE_OK)
         {
                 split = g_strsplit(res->str, "\n", 7);
-
                 for (i = 0; split && split[i]; i++)
                 {
                         if (g_str_has_prefix(split[i], "session="))
-                        {
-                                lastfm_session_id = g_strndup(split[i] + 8, 32);
-#if DEBUG
-                                g_print("Got session ID:'%s'\n",lastfm_session_id);
-#endif
-                        }
+                                lastfm_store("lastfm_session_id",g_strndup(split[i] + 8, 32));
                         else if (g_str_has_prefix(split[i], "stream_url="))
-                                lastfm_stream_uri = g_strdup(split[i] + 11);
+                                lastfm_store("lastfm_stream_uri" ,g_strdup(split[i] + 11));
                 }
         }
         else
-                {
-                g_strfreev(split);
-                g_string_erase(res, 0, -1);
-                g_free(lastfm_session_id);
-                g_free(lastfm_stream_uri);
-                g_free(login_uri);
-                return LASTFM_LOGIN_ERROR;
-                }
-        lastfm_store("lastfm_session_id",lastfm_session_id);
-        lastfm_store("lastfm_stream_uri",lastfm_stream_uri);
-
-#if DEBUG
-        g_print("Login finished succesfully\n");
-#endif
+                ret = LASTFM_LOGIN_ERROR;
         g_strfreev(split);
         g_string_erase(res, 0, -1);
         g_free(login_uri);
- return LASTFM_LOGIN_OK ;
+        return ret;
+}
+
+gint lastfm_adjust(const gchar * uri)  /*tunes into a channel*/
+{
+        gint status, i,ret = LASTFM_ADJUST_FAILED;
+        gchar *fetch_url=NULL,
+              *session_id,
+              **split = NULL;
+        GString *res;        
+        session_id=mowgli_global_storage_get("lastfm_session_id");
+        if (!session_id)
+        {
+#if DEBUG
+                g_print("Adjust failed! Session ID not set.\n");
+#endif
+                return LASTFM_SESSION_MISSING;
+        }
+        fetch_url=g_strdup_printf(LASTFM_ADJUST_URL, session_id, uri);
+        res= g_string_new(NULL);
+        status = lastfm_get_data_from_uri(fetch_url, res);
+#if 0
+        g_print("\nAdjusting: \nSession ID:%s\n",session_id);
+        g_print("Fetch URL:%s\n",fetch_url);
+        g_print("Adjust OK, \nReceived data:\n%s\n", res->str);
+#endif
+        if (status == CURLE_OK)
+        {
+                split = g_strsplit(res->str, "\n", 3);
+                for (i = 0; split && split[i]; i++)
+                {
+                        if (g_str_has_prefix(split[i], "response=OK"))
+                                ret = LASTFM_ADJUST_OK;
+                        if (g_str_has_prefix(split[i], "url="))
+                                lastfm_store("lastfm_tuned_to_url", g_strdup(split[i] + 4));
+                }
+        }
+        g_string_erase(res, 0, -1);
+        g_strfreev(split);
+        return ret;
+}
+
+gchar* parse(gchar* input_string,gchar* token)
+{
+        return g_strdup(g_strstr_len(input_string,20,"=")+1);
 }
 
-gint lastfm_adjust(const gchar * uri)
+gboolean parse_metadata(LastFM * handle,GString * metadata_strings)
 {
-        int status, i;
-        gchar tmp[4096], **split = NULL;
-        gboolean ret = FALSE;
-        GString *res = g_string_new(NULL);
-        gchar* session_id=mowgli_global_storage_get("lastfm_session_id");
-
+        int i;
 
-        if (!session_id)
-		return LASTFM_SESSION_MISSING;
+        if(metadata_strings == NULL)
+                return FALSE;
+        gchar **split = g_strsplit(metadata_strings->str, "\n", 20);
+        if(g_str_has_prefix(split[0],"streaming=false"))
+                return FALSE;
+        handle->lastfm_duration=0;
+        handle->lastfm_progress=0;
+        g_free(handle->lastfm_artist);
+        g_free(handle->lastfm_title);
+        g_free(handle->lastfm_album);
+        g_free(handle->lastfm_cover);
+        g_free(handle->lastfm_station_name);
+        for (i = 0; split && split[i]; i++)
+        {
+                if(g_str_has_prefix(split[i],"artist="))
+                        handle->lastfm_artist = parse(split[i],"artist=");
+                if(g_str_has_prefix(split[i],"track=" ))  
+                        handle->lastfm_title  = parse(split[i],"track=" );
+                if(g_str_has_prefix(split[i],"album=" )) 
+                        handle->lastfm_album  = parse(split[i],"album=" );
+                if(g_str_has_prefix(split[i],"albumcover_medium="))  
+                        handle->lastfm_cover  = parse(split[i],"albumcover_medium=");
+                if(g_str_has_prefix(split[i],"station="))  
+                        handle->lastfm_station_name = parse(split[i],"station=");
+                if(g_str_has_prefix(split[i], "trackduration="))
+                        handle->lastfm_duration = g_ascii_strtoull(g_strdup(split[i] + 14), NULL, 10);
+                if (g_str_has_prefix(split[i], "trackprogress="))
+                        handle->lastfm_progress = g_ascii_strtoull(g_strdup(split[i] + 14), NULL, 10);
+        }
 #if DEBUG
-        g_print("Session ID: '%s'\n",session_id);
-#endif
-
-        snprintf(tmp, sizeof(tmp), LASTFM_ADJUST_URL, session_id, uri);
-
-	status = lastfm_get_data_from_uri(tmp, res);
-
-#if DEBUG
-	g_print("Adjust received data:%s\n", res->str);
+        g_print("\nDuration:%d\n", handle->lastfm_duration);
+        if(handle->lastfm_station_name!=NULL)
+                g_print("Station Name: %s\n", handle->lastfm_station_name);
 #endif
-	if (status == CURLE_OK)
-	{
-		split = g_strsplit(res->str, "\n", 3);
-
-		for (i = 0; split && split[i]; i++)
-		{
-			if (g_str_has_prefix(split[i], "response=OK"))
-				ret = LASTFM_ADJUST_OK;
-			if (g_str_has_prefix(split[i], "stationname="))
-			{
-				mowgli_global_storage_put("lastfm_station_name", g_strdup(split[i] + 12));
-#if DEBUG
-				g_print ("Setting station name: '%s'\n", 
-                                        (gchar*)mowgli_global_storage_get("lastfm_station_name"));
-#endif
-			}
-		}
-		g_strfreev(split);
-	}
-	g_string_erase(res, 0, -1);
-       
-	return ret;
+        g_strfreev(split);
+        g_string_erase(metadata_strings, 0, -1);
+        return TRUE;
 }
 
-void parse( gchar **split , gchar* field, gchar* data){
-
-
-}
-
-void parse_metadata(LastFM * handle,GString * metadata)
+int fetch_metadata(LastFM * handle)
 {
-        gchar **split = g_strsplit(metadata->str, "\n", 20);
-        int i;
-        handle->lastfm_duration=0;
-        
-        for (i = 0; split && split[i]; i++)
+        gchar *uri=NULL;
+        gint status,res=METADATA_FETCH_FAILED;
+        handle->lastfm_session_id=mowgli_global_storage_get("lastfm_session_id");
+        if (handle->lastfm_session_id == NULL)
+                return res;  
+        uri=g_strdup_printf(LASTFM_METADATA_URL, handle->lastfm_session_id);
+        GString *fetched_metadata = g_string_new(NULL);
+        status = lastfm_get_data_from_uri(uri, fetched_metadata);
+        if (status == CURLE_OK)
         {
-                if (g_str_has_prefix(split[i], "artist="))
+#if DEBUG
+                g_print("Received metadata:'%s'\n", fetched_metadata->str);
+#endif
+                if(parse_metadata( handle,fetched_metadata))
                 {
-                        if (handle->lastfm_artist) 
-                                g_free(handle->lastfm_artist);
-
-                        handle->lastfm_artist = g_strdup(split[i] + 7);
+                        res=METADATA_FETCH_SUCCEEDED;
 #if DEBUG
-                        g_print("Artist: %s\n", handle->lastfm_artist);
-#endif
-                }
-                if (g_str_has_prefix(split[i], "track="))
-                {
-                        if (handle->lastfm_title) 
-                                g_free(handle->lastfm_title);
-
-                        handle->lastfm_title = g_strdup(split[i] + 6);
-#if DEBUG
-                        g_print("Title: %s\n", handle->lastfm_title);
+                        g_print("metadata was parsed ok\n");
 #endif
                 }
 
-                if (g_str_has_prefix(split[i], "album="))
-                        handle->lastfm_album = g_strdup(split[i] + 6);
-
-                if (g_str_has_prefix(split[i], "albumcover_medium="))
-                        handle->lastfm_cover = g_strdup(split[i] + 18);
-
-                if (g_str_has_prefix(split[i], "trackduration="))
-                {
-                        handle->lastfm_duration = g_ascii_strtoull(g_strdup(split[i] + 14), NULL, 10);
-#if DEBUG
-                        g_print("Duration:%d\n", handle->lastfm_duration);
-#endif
-                }
-                if (g_str_has_prefix(split[i], "trackprogress="))
-                        handle->lastfm_progress = g_ascii_strtoull(g_strdup(split[i] + 14), NULL, 10);
-
-                if (g_str_has_prefix(split[i], "station="))
-                {
-                        handle->lastfm_station_name = g_strdup(split[i] + 8);
-#if DEBUG
-                        g_print("Station Name: %s\n", handle->lastfm_station_name);
-#endif
-                }
         }
-
-        g_strfreev(split);
-return;
+        return res;
 }
 
-
-gpointer lastfm_get_metadata(gpointer arg)
-{     
+gpointer lastfm_metadata_thread_func(gpointer arg)
+{    
         gint    err=0,
-                delay=-2,
                 sleep_duration=1,
+                previous_track_duration=-1,
                 count=0,
-                status;
-        gchar uri[4096];
-        GString *res = g_string_new(NULL);
-        gboolean track_end=FALSE;
+                status=0;
+        gboolean track_end_expected=FALSE;
+        gchar* previous_track_title=NULL;
         LastFM *handle = (LastFM *)arg;
-        handle->lastfm_session_id =g_strdup(mowgli_global_storage_get("lastfm_session_id"));
+        // metadata is fetched 1 second after the stream is opened.
+        // if it's fetched ok i'm waiting for track_length-10 seconds
+        // then start polling for new metadata each 2 seconds, until
+        // the track gets changed from the previous iteration
+        do
+        {
+                sleep(1);
+                count++;
+                if(count%sleep_duration==0)
+                {               
+                        status=fetch_metadata(handle);
+                        if(status==METADATA_FETCH_SUCCEEDED)
+                        {        
+                                if(!track_end_expected)
+                                {               
+                                        sleep_duration=handle->lastfm_duration-10; 
+                                        previous_track_duration=handle->lastfm_duration;
+                                        previous_track_title=g_strdup(handle->lastfm_title);
+                                        track_end_expected=TRUE; /*then the track_end will follow*/
+                                        count=err=0;
+                                }
+                                else
+                                {       //two tracks are considered identical if they have the same length and the same title
+                                        if((handle->lastfm_duration == previous_track_duration)&&
+                                                        g_str_has_prefix(handle->lastfm_title, previous_track_title))
+                                        {
+                                                sleep_duration=2;
+                                                err++;
+                                        }
+                                        else //the tracks are different so i'm at the beginning of a new one
+                                        {
+                                                track_end_expected=FALSE;
+                                                g_free(previous_track_title);
+                                        }
+                                }
 #if DEBUG
-                        g_print("Session ID: %s\n", handle->lastfm_session_id);
-#endif
-
-        if (handle->lastfm_session_id == NULL)
-                return NULL;
-        snprintf(uri, sizeof(uri), LASTFM_METADATA_URL, handle->lastfm_session_id);
-#if DEBUG
-                        g_print("Download URI: %s\n", uri);
+                                g_print("Current thread, ID = %p\n", (void *)g_thread_self());
 #endif
-
-
-        while ( (handle!= NULL)  && (err<5))
-                //exit after 5 failed retries or after metadata_thread changes
-        {       
-                count++;
-                if (count==sleep_duration)
-                {
-                        handle->lastfm_duration = 0;
-                        handle->lastfm_progress = 0;
-                        status = lastfm_get_data_from_uri(uri, res);
-                        if (status == CURLE_OK)
-                        {
-#if DEBUG
-                                g_print("Successfully got Metadata\n");
-                                g_print("Received metadata:'%s'\nParsing...", res->str);
-#endif
-                                parse_metadata( handle,res);
-                        }
-                        g_string_erase(res, 0, -1);
-
-
-                        if ((!track_end) && (handle->lastfm_duration >0))
-                        {       //refresh metadata 2 sec before track's end and 2 sec after the next track starts
-                                sleep_duration = handle->lastfm_duration - handle->lastfm_progress  - delay -4;
-                                track_end=TRUE;
-                                err=delay=count=0;
                         }
                         else
-                        {
-                                err++;
-                                track_end=FALSE;
-                                sleep_duration=4;
-                                count=0;
-                        }       
-
-                        if(handle->lastfm_duration ==0)  //polling every 2 seconds until I get first data
-                        {
-                        sleep_duration=2;
-                        count=0;
-                        delay+=2;               //time until I get first data 
-                                                //starts from -2 to have uniform handling for in first iteration
-                                                //when calculating sleep_time
-                        }
-
+                                err+=5;
+                }
 #if DEBUG
-		g_print("Sleeping for %d seconds\n", sleep_duration);
+                g_print("Thread_count: %d\n",thread_count);
 #endif
-	        }
-                sleep(1);
         }
+        while (err<=7 && (g_thread_self()==metadata_thread ));
 
 #if DEBUG
         g_print("Exiting thread, ID = %p\n", (void *)g_thread_self());
 #endif
-        handle->metadata_thread = NULL;
-	return NULL;
+        thread_count--;
+        return NULL;
 }
 
 VFSFile *lastfm_vfs_fopen_impl(const gchar * path, const gchar * mode)
 {
-//	static GThread *th;
-	VFSFile *file;
-	LastFM *handle;
-	file = g_new0(VFSFile, 1);
-	handle = g_new0(LastFM, 1);
+        VFSFile *file = g_new0(VFSFile, 1);
+        LastFM  *handle = g_new0(LastFM, 1);
+        gchar* lastfm_uri=NULL;
         int login_count = 0;
-        while( ! mowgli_global_storage_get("lastfm_stream_uri")&&(login_count <= 3))
-	{
-		printf("Login try count: %d\n", login_count++);
-		lastfm_login();
-		if (!mowgli_global_storage_get("lastfm_stream_uri"))
-			sleep(5);
-	}
-
-        if (!mowgli_global_storage_get("lastfm_stream_uri"))
-		return NULL;
+        while((login_count++ <= 3)&&(lastfm_login()!= LASTFM_LOGIN_OK))
+                sleep(5);
 
-	handle->lastfm_session_id = g_strdup(mowgli_global_storage_get("lastfm_session_id"));
-	handle->lastfm_mp3_stream_url = g_strdup(mowgli_global_storage_get("lastfm_stream_uri"));
-	
-        if (!mowgli_global_storage_get("lastfm_station_name"))
-                {
-                        if(lastfm_adjust(path)==LASTFM_ADJUST_OK)
-                        {	                                
-#if DEBUG
-        		g_print("Tuning was successfully completed into the channel\n");
-#endif
-		        }
-                        else
-                        {
-#if DEBUG            
-        		g_print("Cannot tune to given channel\n");
-#endif
-                        }
-                }
-        
-        if ((handle->metadata_thread = g_thread_create(lastfm_get_metadata, handle, FALSE, NULL)) == NULL)
-		            {
-#if DEBUG
-                                        g_print("Error creating metadata thread!!!\n");
-#endif
-			             return NULL;
-		            }
-		        else
-                            {
-#if DEBUG
-                                        g_print("A metadata thread has just been created, ID = %p \n", (void *)handle->metadata_thread);
-#endif
-                            }
+        handle->lastfm_session_id = mowgli_global_storage_get("lastfm_session_id");
+        handle->lastfm_mp3_stream_url = mowgli_global_storage_get("lastfm_stream_uri");
+        lastfm_uri=mowgli_global_storage_get("lastfm_tuned_to_url");
+        //only tune in if the existinfg uri is NULL or != our new one(from path)
+        //adjust doesnt work as it should when having more than one lastfm stream opened at a time
+        if (!lastfm_uri || (!g_str_has_prefix(path,lastfm_uri)) ) 
+                if(!lastfm_adjust(path)==LASTFM_ADJUST_OK)
+                        return NULL;
 
+        metadata_thread = g_thread_create(lastfm_metadata_thread_func, handle, FALSE, NULL);
+        thread_count++;
         handle->proxy_fd = vfs_fopen(handle->lastfm_mp3_stream_url, mode);
-	file->handle = handle;
-
-	return file;
+        file->handle = handle;
+        return file;
 }
 
 gint lastfm_vfs_fclose_impl(VFSFile * file)
 {
-	gint ret = 0;
+        gint ret = 0;
 
-	if (file == NULL)
-		return -1;
+        if (file == NULL)
+                return -1;
         LastFM *handle = file->handle;
-	ret = vfs_fclose(handle->proxy_fd);
-	if (!ret)
-		{
-                        handle->proxy_fd = NULL;
-                        handle->metadata_thread=NULL;
-                }
+        ret = vfs_fclose(handle->proxy_fd);
+        if (!ret)
+                handle->proxy_fd = NULL;
         g_free(handle);
         handle=NULL;
-  	return ret;
+        return ret;
 }
 
 size_t lastfm_vfs_fread_impl(gpointer ptr, size_t size, size_t nmemb, VFSFile * file)
 {
-	LastFM *handle = file->handle;
-	size_t ret = vfs_fread(ptr, size, nmemb, handle->proxy_fd);
-	return ret;
+        LastFM *handle = file->handle;
+        size_t ret = vfs_fread(ptr, size, nmemb, handle->proxy_fd);
+        return ret;
 }
 
 size_t lastfm_vfs_fwrite_impl(gconstpointer ptr, size_t size, size_t nmemb, VFSFile * file)
 {
-	return -1;
+        return -1;
 }
 
 gint lastfm_vfs_getc_impl(VFSFile * stream)
 {
-	LastFM *handle = stream->handle;
-	return vfs_getc(handle->proxy_fd);
+        LastFM *handle = stream->handle;
+        return vfs_getc(handle->proxy_fd);
 }
 
 gint lastfm_vfs_ungetc_impl(gint c, VFSFile * stream)
 {
-	LastFM *handle = stream->handle;
+        LastFM *handle = stream->handle;
 
-	return vfs_ungetc(c, handle->proxy_fd);
+        return vfs_ungetc(c, handle->proxy_fd);
 }
 
 gint lastfm_vfs_fseek_impl(VFSFile * file, glong offset, gint whence)
 {
-	return -1;
+        return -1;
 }
 
 void lastfm_vfs_rewind_impl(VFSFile * file)
 {
-	return;
+        return;
 }
 
 glong lastfm_vfs_ftell_impl(VFSFile * file)
 {
-	LastFM *handle = file->handle;
+        LastFM *handle = file->handle;
 
-	return vfs_ftell(handle->proxy_fd);
+        return vfs_ftell(handle->proxy_fd);
 }
 
 gboolean lastfm_vfs_feof_impl(VFSFile * file)
 {
-	LastFM *handle = file->handle;
+        LastFM *handle = file->handle;
 
-	return vfs_feof(handle->proxy_fd);
+        return vfs_feof(handle->proxy_fd);
 }
 
 gint lastfm_vfs_truncate_impl(VFSFile * file, glong size)
 {
-	return -1;
+        return -1;
 }
 
 off_t lastfm_vfs_fsize_impl(VFSFile * file)
 {
-	return 0;
+        return 0;
 }
 
 gchar *lastfm_vfs_metadata_impl(VFSFile * file, const gchar * field)
 {
-	LastFM *handle = file->handle;
-
-#if 0
-        g_print("Interesting metadata (want: %s):\n", field);
-
-	if (handle->lastfm_station_name != NULL)
-		g_print("%s\n", handle->lastfm_station_name);
-
-	if (handle->lastfm_artist != NULL)
-		g_print("%s\n", handle->lastfm_artist);
-
+        LastFM *handle = file->handle;
 
-	if (handle->lastfm_title != NULL)
-		g_print("%s\n", handle->lastfm_title);
-
-	g_print("%u\n\n", handle->lastfm_duration);
-#endif
+        if (!g_ascii_strncasecmp(field, "stream-name", 11) && (handle->lastfm_station_name != NULL))
+                return g_strdup(handle->lastfm_station_name);
+        if (!g_ascii_strncasecmp(field, "track-name", 10) && (handle->lastfm_title != NULL) && (handle->lastfm_artist != NULL))
+                return g_strdup_printf("%s - %s", handle->lastfm_artist, handle->lastfm_title);
 
-	if (!g_ascii_strncasecmp(field, "stream-name", 11) && (handle->lastfm_station_name != NULL))
-		return g_strdup(handle->lastfm_station_name);
-	if (!g_ascii_strncasecmp(field, "track-name", 10) && (handle->lastfm_title != NULL) && (handle->lastfm_artist != NULL))
-		return g_strdup_printf("%s - %s", handle->lastfm_artist, handle->lastfm_title);
-
-	return NULL;
+        return NULL;
 }
 
 VFSConstructor lastfm_const = {
-	"lastfm://",
-	lastfm_vfs_fopen_impl,
-	lastfm_vfs_fclose_impl,
-	lastfm_vfs_fread_impl,
-	lastfm_vfs_fwrite_impl,
-	lastfm_vfs_getc_impl,
-	lastfm_vfs_ungetc_impl,
-	lastfm_vfs_fseek_impl,
-	lastfm_vfs_rewind_impl,
-	lastfm_vfs_ftell_impl,
-	lastfm_vfs_feof_impl,
-	lastfm_vfs_truncate_impl,
-	lastfm_vfs_fsize_impl,
-	lastfm_vfs_metadata_impl
+        "lastfm://",
+        lastfm_vfs_fopen_impl,
+        lastfm_vfs_fclose_impl,
+        lastfm_vfs_fread_impl,
+        lastfm_vfs_fwrite_impl,
+        lastfm_vfs_getc_impl,
+        lastfm_vfs_ungetc_impl,
+        lastfm_vfs_fseek_impl,
+        lastfm_vfs_rewind_impl,
+        lastfm_vfs_ftell_impl,
+        lastfm_vfs_feof_impl,
+        lastfm_vfs_truncate_impl,
+        lastfm_vfs_fsize_impl,
+        lastfm_vfs_metadata_impl
 };
 
 static void init(void)
 {       
-	vfs_register_transport(&lastfm_const);
+        vfs_register_transport(&lastfm_const);
 }
 
 static void cleanup(void)
 {
 
-mowgli_global_storage_free("lastfm_session_id");
-mowgli_global_storage_free("lastfm_stream_uri");
+        mowgli_global_storage_free("lastfm_session_id");
+        mowgli_global_storage_free("lastfm_stream_uri");
 #if DEBUG
-g_print ("Cleanup finished\n");
+        g_print ("Cleanup finished\n");
 #endif
 }
 
--- a/src/lastfm/lastfm.h	Sun Jul 08 22:26:25 2007 +0300
+++ b/src/lastfm/lastfm.h	Mon Jul 09 05:01:16 2007 +0300
@@ -9,9 +9,10 @@
 #define LASTFM_LOGIN_ERROR              1
 #define LASTFM_MISSING_LOGIN_DATA       2
 #define LASTFM_SESSION_MISSING          4
-#define LASTFM_ADJUST_OK                0
-
-
+#define LASTFM_ADJUST_OK                8
+#define LASTFM_ADJUST_FAILED           16
+#define METADATA_FETCH_FAILED          64
+#define METADATA_FETCH_SUCCEEDED      128
 typedef struct
 {
 	VFSFile *proxy_fd;
@@ -24,10 +25,11 @@
 	gchar *lastfm_cover;
 	unsigned int lastfm_duration;
 	unsigned int lastfm_progress;
-        GThread *metadata_thread;
-	int login_count;
 } LastFM;
 
+GThread* metadata_thread=NULL;
+gint thread_count=0;
+
 VFSFile *lastfm_vfs_fopen_impl(const gchar * path, const gchar * mode);
 
 size_t lastfm_vfs_fread_impl(gpointer ptr, size_t size, size_t nmemb, VFSFile * file);
@@ -54,9 +56,9 @@
 
 gchar *lastfm_vfs_metadata_impl(VFSFile * file, const gchar * field);
 
-static void parse_metadata(LastFM * handle,GString * res);
+gboolean parse_metadata(LastFM * handle,GString * res);
 
-static gpointer lastfm_get_metadata(gpointer arg);
+static gpointer lastfm_metadata_thread_func(gpointer arg);
 
 static gboolean lastfm_login(void);