changeset 2889:6c53f9fa9029

Backed out changeset 59ff744e1e23
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 12 Aug 2008 20:29:49 +0300
parents 59ff744e1e23
children 5e97b55f87cf
files src/alsa/configure.c src/bluetooth/bluetooth.c src/bluetooth/bluetooth.h src/bluetooth/scan_gui.c src/bluetooth/scan_gui.h src/streambrowser/gui/streambrowser_win.c src/streambrowser/gui/streambrowser_win.h src/streambrowser/shoutcast.c src/streambrowser/shoutcast.h src/streambrowser/streambrowser.c src/streambrowser/xiph.c src/streambrowser/xiph.h
diffstat 12 files changed, 277 insertions(+), 195 deletions(-) [+]
line wrap: on
line diff
--- a/src/alsa/configure.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/alsa/configure.c	Tue Aug 12 20:29:49 2008 +0300
@@ -40,19 +40,24 @@
 	alsa_cfg.mixer_card = current_mixer_card;
 	alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
 
+	gtk_widget_destroy(configure_win);
+
+	/* Save configuration */
+	mcs_handle_t *cfgfile = aud_cfg_db_open();
+	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "buffer_time", alsa_cfg.buffer_time);
+	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "period_time", alsa_cfg.period_time);
+	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"pcm_device", alsa_cfg.pcm_device);
+	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "mixer_card", alsa_cfg.mixer_card);
+	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"mixer_device", alsa_cfg.mixer_device);
+	aud_cfg_db_close(cfgfile);
+	
+	/* Save volumes */
 	alsa_save_config();
-	gtk_widget_destroy(configure_win);
 }
 
 void alsa_save_config(void)
 {
 	mcs_handle_t *cfgfile = aud_cfg_db_open();
-
-	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "buffer_time", alsa_cfg.buffer_time);
-	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "period_time", alsa_cfg.period_time);
-	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"pcm_device", alsa_cfg.pcm_device);
-	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "mixer_card", alsa_cfg.mixer_card);
-	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"mixer_device", alsa_cfg.mixer_device);
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_left", alsa_cfg.vol.left);
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_right", alsa_cfg.vol.right);
 	aud_cfg_db_close(cfgfile);
--- a/src/bluetooth/bluetooth.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/bluetooth/bluetooth.c	Tue Aug 12 20:29:49 2008 +0300
@@ -16,9 +16,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses>.
  */
 
-#include <glib/gstdio.h>
-#include <errno.h>
-#include <string.h>
 #include "bluetooth.h"
 #include "marshal.h"
 #include "gui.h"
@@ -30,7 +27,6 @@
 gint config = 0;
 gint devices_no = 0;
 GStaticMutex mutex = G_STATIC_MUTEX_INIT;
-static gchar *current_address=NULL;
 static GThread *connect_th;
 void bluetooth_init ( void );
 void bluetooth_cleanup ( void );
@@ -67,8 +63,7 @@
 void bluetooth_cleanup ( void )
 {
     printf("bluetooth: exit\n");
-    if (config ==1 )
-    {
+    if (config ==1 ){
         close_window();
         config =0;
     }
@@ -110,8 +105,7 @@
 
 }
 
-void clean_devices_list()
-{
+void clean_devices_list(){
     g_list_free(audio_devices);
     dbus_g_connection_flush (bus);
     dbus_g_connection_unref(bus);
@@ -142,78 +136,15 @@
 
     dbus_g_object_register_marshaller(marshal_VOID__STRING_UINT_INT, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID);
     run_agents();
-    dbus_g_proxy_call(obj,"CreateBonding",NULL,G_TYPE_STRING,current_address,G_TYPE_INVALID,G_TYPE_INVALID); 
-
+    dbus_g_proxy_call(obj,"CreateBonding",NULL,G_TYPE_STRING,((DeviceData*)(selected_dev->data))->address,G_TYPE_INVALID,G_TYPE_INVALID); 
+     
 }
 void connect_call(void)
 {
-    current_address = g_strdup(((DeviceData*)(selected_dev->data))->address);
-    connect_th = g_thread_create((GThreadFunc)connect_call_th,NULL,TRUE,NULL) ; 
-    close_call();
-    close_window();
-    show_scan(1);
-}
-
-
-void play_call()
-{
-
-    FILE *file;
-    FILE *temp_file;
-    gint prev=0;
-    char line[128];
-    gchar *home;
-    gchar *device_line;
-    gchar *file_name="";
-    gchar *temp_file_name;
-    int ret = EOF+1;
-    home = g_get_home_dir();
-    file_name = g_strconcat(home,"/.asoundrc",NULL);
-    temp_file_name = g_strconcat(home,"/temp_bt",NULL);
-    file = fopen(file_name,"r");
-    temp_file = fopen(temp_file_name,"w");
-    /* hardcoded address TO REMOVE after testing */
-    //   current_address = "00:0D:3C:B1:1C:7A";
-    device_line = g_strdup_printf("device %s\n",current_address);
-    if ( file != NULL )
-    {
-        while ( fgets ( line, sizeof line, file ) != NULL )
-        {
-            if(!(strcmp(line,"pcm.audacious_bt {\n"))){
-                fputs(line,temp_file);
-                fgets ( line, sizeof line, file ); /* type bluetooth */
-                fputs(line,temp_file);
-                fgets ( line, sizeof line, file ); /* device MAC */
-                fputs(device_line,temp_file);
-                prev = 1;
-            } else 
-                fputs(line,temp_file);
-        }
-
-        fclose (file);
-    }
-    if(!prev){
-        fputs("pcm.audacious_bt{\n",temp_file);
-        fputs("type bluetooth\n",temp_file);
-        fputs(device_line,temp_file);
-        fputs("}\n",temp_file);
-        prev = 0;
-    }
-
-    fclose(temp_file);
-    int err = rename(temp_file_name,file_name);
-    printf("rename error : %d",err);
-    perror("zz");
-    g_free(device_line);
-    g_free(file_name);
-    g_free(temp_file_name);
-    mcs_handle_t *cfgfile = aud_cfg_db_open();
-    aud_cfg_db_set_string(cfgfile,"ALSA","pcm_device", "audacious_bt");
-    aud_cfg_db_close(cfgfile);
-
-    printf("play callback\n");
-
-
+ connect_th = g_thread_create((GThreadFunc)connect_call_th,NULL,TRUE,NULL) ; 
+ close_call();
+ close_window();
+ show_scan(1);
 }
 
 
--- a/src/bluetooth/bluetooth.h	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/bluetooth/bluetooth.h	Tue Aug 12 20:29:49 2008 +0300
@@ -40,7 +40,6 @@
 
 void refresh_call(void);
 void connect_call(void);
-void play_call(void);
 GList * audio_devices;
 gint discover_finish ;
 DBusGConnection * bus;
--- a/src/bluetooth/scan_gui.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/bluetooth/scan_gui.c	Tue Aug 12 20:29:49 2008 +0300
@@ -31,58 +31,56 @@
 static GtkWidget *close_button;
 static gint usage=0;
 
-gpointer progress()
-{
+gpointer progress() {
 
     for(;;){
         if(window){
             gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress_bar));
         }
         sleep(1);
-        if(usage == 0){
-            if(discover_finish == 2 ) {            
-                if(window){
-                    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
-                }
-                return 0;
+       if(usage == 0){
+       if(discover_finish == 2 ) {            
+            if(window){
+                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
             }
-        }else 
-        {
-            if(bonding_finish == 1 ) {            
-                if(window){
-                    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
-                    show_pairing_ok();
+            return 0;
+        }
+       }else 
+           {
+                if(bonding_finish == 1 ) {            
+                    if(window){
+                        gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
+                        show_pairing_ok();
+                    }
+                return 0;
                 }
-                return 0;
-            }
-        }
+           }
     }
     return 0;
 }
 
 void show_pairing_ok()
 {
-    if(window ){
+ if(window ){
         gtk_label_set_text(GTK_LABEL(scan_label),_("Bonding finish!"));
     }
 }
 
-void show_no_devices()
-{
+void show_no_devices(){
     if(window ){
         gtk_label_set_text(GTK_LABEL(scan_label),_("No devices found!"));
     }
 }
-void destroy_scan_window()
-{
+void destroy_scan_window(){
     gtk_widget_hide(window);
 }
-void close_window(void)
-{
+void close_window(void){
     printf("scan_gui close callback \n");
     gtk_widget_destroy (window);
     window = NULL;
 }
+
+
 void show_scan(gint use)
 {
     GThread *th1;
@@ -115,9 +113,9 @@
         if(usage == 0){
             scan_label = gtk_label_new_with_mnemonic(_("Scanning..."));
         }else
-        {
-            scan_label = gtk_label_new_with_mnemonic(_("Pairing..."));
-        }
+            {
+                scan_label = gtk_label_new_with_mnemonic(_("Pairing..."));
+            }
 
         gtk_container_add(GTK_CONTAINER(scanbox),scan_label);
 
@@ -131,15 +129,8 @@
         /* I have to modify the rescan button with a play one 
          * and treat the case when the bounding is not ok
          */
-        if(usage == 0){
-            rescan_buttton = gtk_button_new_with_mnemonic(_("Rescan"));
-            g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (refresh_call),NULL);
-        }else{
-            rescan_buttton = gtk_button_new_with_mnemonic(_("Play"));
-            g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (play_call),NULL);
-        }
-
-
+        rescan_buttton = gtk_button_new_with_mnemonic(_("Rescan"));
+        g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (refresh_call),NULL);
 
         close_button = gtk_button_new_with_mnemonic(_("Close"));
         gtk_container_add(GTK_CONTAINER(buttonsbox),rescan_buttton);
--- a/src/bluetooth/scan_gui.h	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/bluetooth/scan_gui.h	Tue Aug 12 20:29:49 2008 +0300
@@ -18,12 +18,6 @@
 
 #include <gtk/gtk.h>
 #include <glib.h>
-#include <alsa/asoundlib.h>
-#include <alsa/pcm_plugin.h>
-#include <audacious/plugin.h>
-#include <audacious/i18n.h>
-
-
 void show_scan(gint use);
 void show_no_devices();
 void destroy_scan_window();
--- a/src/streambrowser/gui/streambrowser_win.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/gui/streambrowser_win.c	Tue Aug 12 20:29:49 2008 +0300
@@ -19,7 +19,7 @@
 } streamdir_gui_t;
 
 
-void					(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
+void					(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist);
 
 static GtkWidget*		gtk_label_new_with_icon(gchar *icon_filename, gchar *label_text);
 static GtkWidget*		gtk_streamdir_tree_view_new();
@@ -33,7 +33,7 @@
 static gboolean			on_tree_view_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer data);
 
 static streamdir_gui_t*	find_streamdir_gui_by_name(gchar *name);
-static streamdir_gui_t*	find_streamdir_gui_by_tree_view(GtkTreeView *tree_view);
+//static streamdir_gui_t*	find_streamdir_gui_by_tree_view(GtkTreeView *tree_view); todo: remove this
 static streamdir_gui_t*	find_streamdir_gui_by_table(GtkTable *table);
 static streamdir_gui_t*	find_streamdir_gui_by_streamdir(streamdir_t *streamdir);
 static gboolean			tree_view_search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer data);
@@ -46,6 +46,9 @@
 static GtkCellRenderer*	cell_renderer_pixbuf;
 static GtkCellRenderer*	cell_renderer_text;
 
+static gboolean			tree_view_button_pressed = FALSE;
+
+
 
 void streambrowser_win_init()
 {
@@ -186,13 +189,37 @@
 		streaminfo = streaminfo_get_by_index(category, i);
 
 		gtk_tree_store_append(store, &new_iter, &iter);
-		gtk_tree_store_set(store, &new_iter, 0, "gtk-directory", 1, streaminfo->name, 2, streaminfo->current_track, -1);
+		gtk_tree_store_set(store, &new_iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
 	}
 	
 	gtk_tree_path_free(path);
 }
 
-void streambrowser_win_set_update_function(void (*function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo))
+void streambrowser_win_set_streaminfo(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo)
+{
+	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_name(streamdir->name);
+	if (streamdir_gui == NULL) {
+		failure("gui: streambrowser_win_set_category() called with non-existent streamdir\n");
+		return;
+	}
+	
+	GtkTreeView *tree_view = GTK_TREE_VIEW(streamdir_gui->tree_view);
+	GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
+	GtkTreePath *path;
+	GtkTreeIter iter, new_iter;
+	
+	/* find the corresponding streaminfo tree iter */
+	path = gtk_tree_path_new_from_indices(category_get_index(streamdir, category), streaminfo_get_index(category, streaminfo), -1);
+	if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
+		return;
+	
+	/* update the streaminfo*/
+	gtk_tree_store_set(store, &new_iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
+	
+	gtk_tree_path_free(path);
+}
+
+void streambrowser_win_set_update_function(void (*function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist))
 {
 	update_function = function;
 }
@@ -240,7 +267,7 @@
 		gtk_tree_store_set(store, &iter, 0, "gtk-refresh", 1, temp, 2, streaminfo->current_track, -1);
 	}
 	else {
-		gtk_tree_store_set(store, &iter, 0, "gtk-directory", 1, streaminfo->name, 2, streaminfo->current_track, -1);
+		gtk_tree_store_set(store, &iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
 	}
 }
 
@@ -330,53 +357,72 @@
 	return TRUE;
 }
 
+
 static gboolean on_tree_view_cursor_changed(GtkTreeView *tree_view, gpointer data)
 {
+	/* only do the refresh if this cursor change occured due to a mouse click */
+	if (!tree_view_button_pressed)
+		return FALSE;
+
+	tree_view_button_pressed = FALSE;
+
 	GtkTreePath *path;
-	GtkTreeIter iter;
-	GtkTreeModel *model;
+	GtkTreeViewColumn *focus_column;
+
+	/* get the currently selected tree view */
+	GtkWidget *table = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
+	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_table(GTK_TABLE(table));
+	if (streamdir_gui == NULL)
+		return FALSE;
+
+	/* get the currently selected path in the tree */
+	gtk_tree_view_get_cursor(tree_view, &path, &focus_column);
+
+	if (path == NULL || gtk_tree_path_get_depth(path) == 0)
+		return FALSE;
 
-	/* obtain the current category */
-	gtk_tree_view_get_cursor(tree_view, &path, NULL);
-	
-	if (path == NULL)
-		return TRUE;
-	
 	gint *indices = gtk_tree_path_get_indices(path);
-	if (gtk_tree_path_get_depth(path) != 1) {
+	int category_index = indices[0];
+	streamdir_t *streamdir = streamdir_gui->streamdir;
+	category_t *category = category_get_by_index(streamdir_gui->streamdir, category_index);
+
+	/* if the selected item is a category */
+	if (gtk_tree_path_get_depth(path) == 1) {
+		if (!gtk_tree_view_row_expanded(tree_view, path)) {
+			gtk_entry_set_text(GTK_ENTRY(search_entry), "");
+			update_function(streamdir, category, NULL, FALSE);
+		}
+
 		gtk_tree_path_free(path);
-		return TRUE;
+	}
+	/* if the selected item is a streaminfo */
+	else {
+		int streaminfo_index = indices[1];
+
+		gtk_tree_path_free(path);
+
+		/* get the currently selected stream (info) */
+		streaminfo_t *streaminfo = streaminfo_get_by_index(category, streaminfo_index);
+		
+		gtk_entry_set_text(GTK_ENTRY(search_entry), "");
+		update_function(streamdir, category, streaminfo, FALSE);
 	}
 	
-	model = gtk_tree_view_get_model(tree_view);
-	gtk_tree_model_get_iter(model, &iter, path);
-	
-	/* don't fetch a category that has been already fetched */
-	if (gtk_tree_model_iter_has_child(model, &iter)) {
-		gtk_tree_path_free(path);
-		return TRUE;
-	}
-	
-	int category_index = indices[0];
-	
-	gtk_tree_path_free(path);
-	
-	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_tree_view(tree_view);
-	if (streamdir_gui == NULL)
-		return TRUE;
-	
-	/* issue an update on the current category */	
-	update_function(streamdir_gui->streamdir, category_get_by_index(streamdir_gui->streamdir, category_index), NULL);
-	
-	return TRUE;
+	return FALSE;
 }
 
 static gboolean on_tree_view_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
 	/* double click adds the currently selected stream to the playlist */
 	if (event->type == GDK_2BUTTON_PRESS) {
+		tree_view_button_pressed = FALSE;
 		on_add_button_clicked(NULL, NULL);
 	}
+	/* single click triggers a refresh of the selected item */
+	else {
+		// todo: separate single from double click somehow
+		tree_view_button_pressed = TRUE;
+	}	
 	
 	return FALSE;
 }
@@ -386,6 +432,7 @@
 	GtkTreePath *path;
 	GtkTreeViewColumn *focus_column;
 
+	/* get the currently selected tree view */
 	GtkWidget *table = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
 	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_table(GTK_TABLE(table));
 	if (streamdir_gui == NULL)
@@ -393,6 +440,7 @@
 
 	GtkTreeView *tree_view = GTK_TREE_VIEW(streamdir_gui->tree_view);
 	
+	/* get the currently selected path in the tree */
 	gtk_tree_view_get_cursor(tree_view, &path, &focus_column);
 	
 	if (path == NULL)
@@ -414,12 +462,13 @@
 	
 	gtk_tree_path_free(path);
 	
+	/* get the currently selected stream (info) */
 	streamdir_t *streamdir = streamdir_gui->streamdir;
 	category_t *category = category_get_by_index(streamdir_gui->streamdir, category_index);
 	streaminfo_t *streaminfo = streaminfo_get_by_index(category, streaminfo_index);
 	
 	gtk_entry_set_text(GTK_ENTRY(search_entry), "");
-	update_function(streamdir, category, streaminfo);
+	update_function(streamdir, category, streaminfo, TRUE);
 
 	return TRUE;
 }
@@ -470,6 +519,7 @@
 	return NULL;
 }
 
+/* todo: remove this
 static streamdir_gui_t *find_streamdir_gui_by_tree_view(GtkTreeView *tree_view)
 {
 	GList *iterator;
@@ -484,6 +534,7 @@
 	
 	return NULL;
 }
+*/
 
 static streamdir_gui_t *find_streamdir_gui_by_table(GtkTable *table)
 {
--- a/src/streambrowser/gui/streambrowser_win.h	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/gui/streambrowser_win.h	Tue Aug 12 20:29:49 2008 +0300
@@ -12,7 +12,9 @@
 
 void			streambrowser_win_set_streamdir(streamdir_t *streamdir, gchar *icon_filename);
 void			streambrowser_win_set_category(streamdir_t *streamdir, category_t *category);
-void			streambrowser_win_set_update_function(void (* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo));
+void			streambrowser_win_set_streaminfo(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
+
+void			streambrowser_win_set_update_function(void (* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist));
 void			streambrowser_win_set_category_state(streamdir_t *streamdir, category_t *category, gboolean fetching);
 void			streambrowser_win_set_streaminfo_state(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean fetching);
 
--- a/src/streambrowser/shoutcast.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/shoutcast.c	Tue Aug 12 20:29:49 2008 +0300
@@ -27,6 +27,78 @@
 #include "shoutcast.h"
 
 
+gboolean shoutcast_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo)
+{
+	gchar url[DEF_STRING_LEN];
+	g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_CATEGORY_URL, category->name);
+
+	/* generate a valid, temporary filename */
+	char *temp_filename = tempnam(NULL, "aud_sb");
+	if (temp_filename == NULL) {
+		failure("shoutcast: failed to create a temporary file\n");
+		return FALSE;
+	}
+
+	char temp_pathname[DEF_STRING_LEN];
+	sprintf(temp_pathname, "file://%s", temp_filename);
+
+	debug("shoutcast: fetching category file '%s'\n", url);
+	if (!fetch_remote_to_local_file(url, temp_pathname))  {
+		failure("shoutcast: category file '%s' could not be downloaded to '%s'\n", url, temp_pathname);
+		free(temp_filename);
+		return FALSE;
+	}
+	debug("shoutcast: category file '%s' successfuly downloaded to '%s'\n", url, temp_pathname);
+
+	xmlDoc *doc = xmlReadFile(temp_pathname, NULL, 0);
+	if (doc == NULL) {
+		failure("shoutcast: failed to read '%s' category file\n", category->name);
+		free(temp_filename);
+		return FALSE;
+	}
+	
+	xmlNode *root_node = xmlDocGetRootElement(doc);
+	xmlNode *node;
+	
+	root_node = root_node->children;
+
+	for (node = root_node; node != NULL; node = node->next) {
+		if (node->type == XML_ELEMENT_NODE && !strcmp((char *) node->name, "station")) {
+			gchar *streaminfo_name = (gchar*) xmlGetProp(node, (xmlChar *) "name");
+			gchar *streaminfo_id = (gchar*) xmlGetProp(node, (xmlChar *) "id");
+			gchar streaminfo_playlist_url[DEF_STRING_LEN];
+			gchar *streaminfo_current_track = (gchar*) xmlGetProp(node, (xmlChar *) "ct");
+			
+			g_snprintf(streaminfo_playlist_url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, streaminfo_id);
+			
+			if (strncmp(streaminfo_playlist_url, streaminfo->playlist_url, DEF_STRING_LEN) == 0) {
+				debug("shoutcast: updating stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
+
+				strcpy(streaminfo->name, streaminfo_name);
+				strcpy(streaminfo->playlist_url, streaminfo_playlist_url);
+				strcpy(streaminfo->current_track, streaminfo_current_track);
+			
+				xmlFree(streaminfo_name);
+				xmlFree(streaminfo_id);
+				xmlFree(streaminfo_current_track);
+
+				debug("shoutcast: stream info added\n");
+			
+				break;
+			}
+		}
+	}
+	
+	xmlFreeDoc(doc);
+	
+	if (remove(temp_filename) != 0) {
+		failure("shoutcast: cannot remove the temporary file: %s\n", strerror(errno));
+	}
+	free(temp_filename);
+
+	return TRUE;
+}
+
 gboolean shoutcast_category_fetch(category_t *category)
 {
 	gchar url[DEF_STRING_LEN];
@@ -75,7 +147,7 @@
 			
 			g_snprintf(streaminfo_playlist_url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, streaminfo_id);
 
-			debug("shoutcast: fetching stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
+			debug("shoutcast: adding stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
 
 			streaminfo_t *streaminfo = streaminfo_new(streaminfo_name, streaminfo_playlist_url, "", streaminfo_current_track);
 			streaminfo_add(category, streaminfo);
--- a/src/streambrowser/shoutcast.h	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/shoutcast.h	Tue Aug 12 20:29:49 2008 +0300
@@ -30,6 +30,7 @@
 #define SHOUTCAST_STREAMINFO_URL	"http://www.shoutcast.com/sbin/shoutcast-playlist.pls?rn=%s&file=filename.pls"
 
 
+gboolean							shoutcast_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo);
 gboolean							shoutcast_category_fetch(category_t *category);
 streamdir_t*						shoutcast_streamdir_fetch();
 
--- a/src/streambrowser/streambrowser.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/streambrowser.c	Tue Aug 12 20:29:49 2008 +0300
@@ -34,6 +34,7 @@
     streamdir_t *streamdir;
     category_t *category;
     streaminfo_t *streaminfo;
+    gboolean add_to_playlist;
 } update_thread_data_t;
 
 
@@ -47,7 +48,7 @@
 static void config_load();
 static void config_save();
 
-static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
+static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist);
 static gpointer update_thread_core(gpointer user_data);
 static void streaminfo_add_to_playlist(streaminfo_t *streaminfo);
 static void on_plugin_services_menu_item_click();
@@ -271,12 +272,13 @@
     debug("configuration saved\n");
 }
 
-static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo)
+static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist)
 {
-    debug("requested streamdir update (streamdir = '%s', category = '%s', streaminfo = '%s')\n", 
+    debug("requested streamdir update (streamdir = '%s', category = '%s', streaminfo = '%s', add_to_playlist = %d)\n", 
           streamdir == NULL ? "" : streamdir->name, 
           category == NULL ? "" : category->name,
-          streaminfo == NULL ? "" : streaminfo->name);
+          streaminfo == NULL ? "" : streaminfo->name,
+          add_to_playlist);
 
     if (g_queue_get_length(update_thread_data_queue) >= MAX_UPDATE_THREADS) {
         debug("another %d streamdir updates are pending, this request will be dropped\n", g_queue_get_length(update_thread_data_queue));
@@ -295,7 +297,8 @@
                 update_thread_data = g_queue_peek_nth(update_thread_data_queue, i);
                 if (update_thread_data->streamdir == streamdir &&
                     update_thread_data->category == category &&
-                    update_thread_data->streaminfo == streaminfo) {
+                    update_thread_data->streaminfo == streaminfo &&
+                    update_thread_data->add_to_playlist == add_to_playlist) {
                     exists = TRUE;
                     break;
                 }
@@ -310,6 +313,7 @@
                 update_thread_data->streamdir = streamdir;
                 update_thread_data->category = category;
                 update_thread_data->streaminfo = streaminfo;
+                update_thread_data->add_to_playlist = add_to_playlist;
  
                 g_queue_push_tail(update_thread_data_queue, update_thread_data);
             }
@@ -326,6 +330,7 @@
             data->streamdir = streamdir;
             data->category = category;
             data->streaminfo = streaminfo;
+            data->add_to_playlist = add_to_playlist;
  
             g_queue_push_tail(update_thread_data_queue, data);
 
@@ -350,46 +355,50 @@
 
 	/* repetitively process the queue elements, until queue is empty */
 	while (data != NULL && g_queue_get_length(update_thread_data_queue) > 0) {
-	    /* update a streaminfo - that is - add this streaminfo to playlist */
+	    /* update a streaminfo */
 		if (data->streaminfo != NULL) {
 	    	gdk_threads_enter();
 			streambrowser_win_set_streaminfo_state(data->streamdir, data->category, data->streaminfo, TRUE);
 	    	gdk_threads_leave();
 
-		    streaminfo_add_to_playlist(data->streaminfo);
+			if (data->add_to_playlist)
+			    streaminfo_add_to_playlist(data->streaminfo);
+			else {
+				/* shoutcast */
+				if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
+				    shoutcast_streaminfo_fetch(data->category, data->streaminfo);
+				}
+				/* xiph */
+				else if (strncmp(data->streamdir->name, XIPH_NAME, strlen(XIPH_NAME)) == 0) {
+					xiph_streaminfo_fetch(data->category, data->streaminfo);
+				}
+			}
 
 	        gdk_threads_enter();
+	        if (!data->add_to_playlist)
+		        streambrowser_win_set_streaminfo(data->streamdir, data->category, data->streaminfo);
 			streambrowser_win_set_streaminfo_state(data->streamdir, data->category, data->streaminfo, FALSE);
 	        gdk_threads_leave();
 		}
 		/* update a category */
 		else if (data->category != NULL) {
+	    	gdk_threads_enter();
+			streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
+	    	gdk_threads_leave();
+	    	
 		    /* shoutcast */
 		    if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
-		    	gdk_threads_enter();
-				streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
-		    	gdk_threads_leave();
-		    	
 		        shoutcast_category_fetch(data->category);
-
-		        gdk_threads_enter();
-		        streambrowser_win_set_category(data->streamdir, data->category);
-				streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
-		        gdk_threads_leave();
 		    }
 		    /* xiph */
 		    else if (strncmp(data->streamdir->name, XIPH_NAME, strlen(XIPH_NAME)) == 0) {
-		    	gdk_threads_enter();
-				streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
-		    	gdk_threads_leave();
-		    	
 		        xiph_category_fetch(data->category);
+		    }
 
-		        gdk_threads_enter();
-		        streambrowser_win_set_category(data->streamdir, data->category);
-				streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
-		        gdk_threads_leave();
-		    }
+	        gdk_threads_enter();
+	        streambrowser_win_set_category(data->streamdir, data->category);
+			streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
+	        gdk_threads_leave();
 		}
 		/* update a streamdir */
 		else if (data->streamdir != NULL) {
@@ -466,7 +475,7 @@
 	}
 
 	if (strlen(streaminfo->url) > 0) {
-	   	aud_playlist_add(aud_playlist_get_active(), streaminfo->url);
+		aud_playlist_add(aud_playlist_get_active(), streaminfo->url);
 		debug("stream '%s' added\n", streaminfo->url);
 	}
 }
@@ -476,6 +485,6 @@
     debug("on_plugin_services_menu_item_click()\n");
 
     streambrowser_win_show();
-    streamdir_update(NULL, NULL, NULL);
+    streamdir_update(NULL, NULL, NULL, FALSE);
 }
 
--- a/src/streambrowser/xiph.c	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/xiph.c	Tue Aug 12 20:29:49 2008 +0300
@@ -28,10 +28,12 @@
 
 
 typedef struct {
+
 	gchar name[DEF_STRING_LEN];
 	gchar url[DEF_STRING_LEN];
 	gchar current_song[DEF_STRING_LEN];
 	gchar genre[DEF_STRING_LEN];
+
 } xiph_entry_t;
 
 
@@ -39,8 +41,10 @@
 static int xiph_entry_count = 0;
 
 typedef struct {
+
 	gchar *name;
 	gchar *match_string;
+	
 } xiph_category_t;
 
 /* inspired from streamtuner's xiph plugin */
@@ -62,14 +66,34 @@
 };
 
 
-// todo: call refresh_streamdir() more often to refresh the current track
 static void refresh_streamdir();
 	/* returns true if any of the words in string1 is present in string2 */
 static gboolean genre_match(gchar *string1, gchar *string2);
 
+gboolean xiph_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo)
+{
+	int entryno;
+	
+	refresh_streamdir();
+	
+	/* find the corresponding xiph entry */
+	for (entryno = 0; entryno < xiph_entry_count; entryno++) {
+		if (strcmp(xiph_entries[entryno].name, streaminfo->name) == 0) {
+			strcpy(streaminfo->name, xiph_entries[entryno].name);
+			strcpy(streaminfo->url, xiph_entries[entryno].url);
+			strcpy(streaminfo->current_track, xiph_entries[entryno].current_song);
+
+			break;
+		}
+	}
+	
+	return TRUE;
+}
 
 gboolean xiph_category_fetch(category_t *category)
 {
+	refresh_streamdir();
+
 	int entryno, categoryno;
 	int xiph_category_count = sizeof(xiph_categories) / sizeof(xiph_category_t);
 	xiph_category_t *xiph_category = NULL;
@@ -139,8 +163,10 @@
 static void refresh_streamdir()
 {
 	/* free any previously fetched streamdir data */
-	if (xiph_entries != NULL)
+	if (xiph_entries != NULL) {
 		free(xiph_entries);
+		xiph_entries = NULL;
+	}
 	xiph_entry_count = 0;
 
 	debug("xiph: fetching streaming directory file '%s'\n", XIPH_STREAMDIR_URL);
--- a/src/streambrowser/xiph.h	Fri Aug 01 22:55:49 2008 +0300
+++ b/src/streambrowser/xiph.h	Tue Aug 12 20:29:49 2008 +0300
@@ -29,6 +29,7 @@
 #define XIPH_TEMP_FILENAME		"file:///tmp/xiph_yp.xml"
 
 
+gboolean							xiph_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo);
 gboolean							xiph_category_fetch(category_t *category);
 streamdir_t*						xiph_streamdir_fetch();