Mercurial > audlegacy-plugins
diff src/streambrowser/streambrowser.c @ 2735:6d6a3eb67510
some work on the streambrowser
| author | Calin Crisan ccrisan@gmail.com |
|---|---|
| date | Tue, 01 Jul 2008 02:05:25 +0300 |
| parents | 28498c0bde64 |
| children | 4ec0e13208de |
line wrap: on
line diff
--- a/src/streambrowser/streambrowser.c Mon Jun 23 12:15:36 2008 +0300 +++ b/src/streambrowser/streambrowser.c Tue Jul 01 02:05:25 2008 +0300 @@ -7,6 +7,17 @@ #include "streambrowser.h" #include "streamdir.h" #include "shoutcast.h" +#include "gui/streambrowser_win.h" +#include "gui/about_win.h" + + +typedef struct { + + streamdir_t* streamdir; + category_t* category; + streaminfo_t* streaminfo; + +} update_thread_data_t; static void sb_init(); @@ -14,9 +25,24 @@ static void sb_configure(); static void sb_cleanup(); -static void menu_click(); -static void add_plugin_services_menu_item(); +static void gui_init(); +static void gui_done(); +static void config_load(); +static void config_save(); +static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo); +static gpointer update_thread_core(update_thread_data_t *data); +static void streaminfo_add_to_playlist(streaminfo_t *streaminfo); +static void on_plugin_services_menu_item_click(); + +static GtkWidget* playlist_menu_item; +static GtkWidget* main_menu_item; +static update_thread_data_t update_thread_data_queue[MAX_UPDATE_THREADS]; +static gint update_thread_count = 0; +static GMutex* update_thread_mutex; + + +streambrowser_cfg_t streambrowser_cfg; static GeneralPlugin sb_plugin = { @@ -38,8 +64,7 @@ void debug(const char *fmt, ...) { - // todo: replace with config->debug - if (TRUE) { + if (streambrowser_cfg.debug) { va_list ap; fprintf(stderr, "* streambrowser: "); va_start(ap, fmt); @@ -48,7 +73,7 @@ } } -void error(const char *fmt, ...) +void failure(const char *fmt, ...) { va_list ap; fprintf(stderr, "! streambrowser: "); @@ -57,12 +82,58 @@ va_end(ap); } +gboolean fetch_remote_to_local_file(gchar *remote_url, gchar *local_url) +{ + VFSFile *remote_file = aud_vfs_fopen(remote_url, "r"); + if (remote_file == NULL) { + failure("failed to fetch file '%s'\n", remote_url); + return FALSE; + } + + VFSFile *local_file = aud_vfs_fopen(local_url, "w"); + if (local_file == NULL) { + aud_vfs_fclose(remote_file); + + failure("failed to create local file '%s'\n", local_file); + return FALSE; + } + + unsigned char buff[DEF_BUFFER_SIZE]; + int size; + while (!aud_vfs_feof(remote_file)) { + size = aud_vfs_fread(buff, 1, DEF_BUFFER_SIZE, remote_file); + + // i don't know why aud_vfs_feof() doesn't ever return TRUE + // so this is a workaround to properly end the loop + if (size == 0) + break; + + size = aud_vfs_fwrite(buff, 1, size, local_file); + if (size == 0) { + aud_vfs_fclose(local_file); + aud_vfs_fclose(remote_file); + + failure("failed to write to local file '%s'\n", local_file); + return FALSE; + } + } + + aud_vfs_fclose(local_file); + aud_vfs_fclose(remote_file); + + return TRUE; +} + static void sb_init() { + /* workaround to print sb_init() */ + streambrowser_cfg.debug = TRUE; debug("sb_init()\n"); + streambrowser_cfg.debug = FALSE; - //shoutcast_streamdir_fetch(); + config_load(); + gui_init(); } static void sb_about() @@ -78,23 +149,199 @@ static void sb_cleanup() { debug("sb_cleanup()\n"); + + gui_done(); + config_save(); +} + +static void gui_init() +{ + /* the plugin services menu */ + playlist_menu_item = gtk_image_menu_item_new_with_label("Streambrowser"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(playlist_menu_item), gtk_image_new_from_stock(GTK_STOCK_CDROM, GTK_ICON_SIZE_MENU)); + gtk_widget_show(playlist_menu_item); + g_signal_connect(G_OBJECT(playlist_menu_item), "activate", G_CALLBACK(on_plugin_services_menu_item_click), NULL); + audacious_menu_plugin_item_add(AUDACIOUS_MENU_PLAYLIST_RCLICK, playlist_menu_item); + + main_menu_item = gtk_image_menu_item_new_with_label("Streambrowser"); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(main_menu_item), gtk_image_new_from_stock(GTK_STOCK_CDROM, GTK_ICON_SIZE_MENU)); + gtk_widget_show(main_menu_item); + g_signal_connect(G_OBJECT(main_menu_item), "activate", G_CALLBACK(on_plugin_services_menu_item_click), NULL); + audacious_menu_plugin_item_add(AUDACIOUS_MENU_MAIN, main_menu_item); + + /* main streambrowser window */ + streambrowser_win_init(); + streambrowser_win_set_update_function(streamdir_update); + update_thread_mutex = g_mutex_new(); + + debug("gui initialized\n"); } -static void menu_click() +static void gui_done() +{ + /* the plugin services menu */ + audacious_menu_plugin_item_remove(AUDACIOUS_MENU_PLAYLIST_RCLICK, playlist_menu_item); + audacious_menu_plugin_item_remove(AUDACIOUS_MENU_MAIN, main_menu_item); + + /* main streambrowser window */ + streambrowser_win_hide(); + streambrowser_win_done(); + + debug("gui destroied\n"); +} + +static void config_load() { - debug("menu_click()\n"); + streambrowser_cfg.debug = FALSE; + + mcs_handle_t *db; + if ((db = aud_cfg_db_open()) == NULL) { + failure("failed to load configuration\n"); + return; + } + + aud_cfg_db_get_bool(db, "streambrowser", "debug", &streambrowser_cfg.debug); + + aud_cfg_db_close(db); + + debug("configuration loaded\n"); + debug("debug = %d\n", streambrowser_cfg.debug); +} + +static void config_save() +{ + mcs_handle_t *db; + if ((db = aud_cfg_db_open()) == NULL) { + failure("failed to save configuration\n"); + return; + } + + aud_cfg_db_set_bool(db, "streambrowser", "debug", streambrowser_cfg.debug); + + aud_cfg_db_close(db); + + debug("configuration saved\n"); } -static void add_plugin_services_menu_item() +static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo) { - /* - GtkWidget *menu_item; + debug("requested streamdir update (streamdir = '%s', category = '%s', streaminfo = '%s')\n", + streamdir == NULL ? "" : streamdir->name, + category == NULL ? "" : category->name, + streaminfo == NULL ? "" : streaminfo->name); - menu_item = gtk_image_menu_item_new_with_label("SB Test"); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_CDROM, GTK_ICON_SIZE_MENU)); - gtk_widget_show(menu_item); - audacious_menu_plugin_item_add(AUDACIOUS_MENU_PLAYLIST_RCLICK, menu_item); - g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_click), NULL); - */ + if (update_thread_count >= MAX_UPDATE_THREADS) { + debug("another %d streamdir updates are pending, this request will be dropped\n", update_thread_count); + } + else + if (update_thread_count > 0) { + debug("another %d streamdir updates are pending, this request will be queued\n", update_thread_count); + + g_mutex_lock(update_thread_mutex); + update_thread_data_queue[update_thread_count].streamdir = streamdir; + update_thread_data_queue[update_thread_count].category = category; + update_thread_data_queue[update_thread_count].streaminfo = streaminfo; + + update_thread_count++; + g_mutex_unlock(update_thread_mutex); + } + else { + update_thread_data_t *data = g_malloc(sizeof(update_thread_data_t)); + + data->streamdir = streamdir; + data->category = category; + data->streaminfo = streaminfo; + + g_thread_create((GThreadFunc) update_thread_core, data, TRUE, NULL); + } } +static gpointer update_thread_core(update_thread_data_t *data) +{ + /* update a streaminfo - that is - add this streaminfo to playlist */ + if (data->streaminfo != NULL) { + streaminfo_add_to_playlist(data->streaminfo); + } + /* update a category */ + else if (data->category != NULL) { + /* shoutcast */ + if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) { + shoutcast_category_fetch(data->category); + + gdk_threads_enter(); + streambrowser_win_set_category(data->streamdir, data->category); + gdk_threads_leave(); + } + } + /* update a streamdir */ + else if (data->streamdir != NULL) { + /* shoutcast */ + if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) { + streamdir_t *streamdir = shoutcast_streamdir_fetch(); + if (streamdir != NULL) { + gdk_threads_enter(); + streambrowser_win_set_streamdir(streamdir, SHOUTCAST_ICON); + gdk_threads_leave(); + } + } + } + /* update all streamdirs */ + else { + /* shoutcast */ + streamdir_t *shoutcast_streamdir = shoutcast_streamdir_fetch(); + if (shoutcast_streamdir != NULL) { + gdk_threads_enter(); + streambrowser_win_set_streamdir(shoutcast_streamdir, SHOUTCAST_ICON); + gdk_threads_leave(); + } + } + + g_free(data); + + /* check to see if there are pending update requests */ + + data = NULL; + g_mutex_lock(update_thread_mutex); + if (update_thread_count > 0) { + data = g_malloc(sizeof(update_thread_data_t)); + data->streamdir = update_thread_data_queue[0].streamdir; + data->category = update_thread_data_queue[0].category; + data->streaminfo = update_thread_data_queue[0].streaminfo; + + int i; + for (i = 0; i < update_thread_count; i++) { + update_thread_data_queue[i].streamdir = update_thread_data_queue[i + 1].streamdir; + update_thread_data_queue[i].category = update_thread_data_queue[i + 1].category; + update_thread_data_queue[i].streaminfo = update_thread_data_queue[i + 1].streaminfo; + } + + update_thread_count--; + } + g_mutex_unlock(update_thread_mutex); + + if (data != NULL) + update_thread_core(data); + + return NULL; +} + +static void streaminfo_add_to_playlist(streaminfo_t *streaminfo) +{ + debug("fetching stream playlist for station '%s' from '%s'\n", streaminfo->name, streaminfo->playlist_url); + if (!fetch_remote_to_local_file(streaminfo->playlist_url, PLAYLIST_TEMP_FILE)) { + failure("shoutcast: stream playlist '%s' could not be downloaded to '%s'\n", streaminfo->playlist_url, PLAYLIST_TEMP_FILE); + return; + } + debug("stream playlist '%s' successfuly downloaded to '%s'\n", streaminfo->playlist_url, PLAYLIST_TEMP_FILE); + + aud_playlist_add(aud_playlist_get_active(), PLAYLIST_TEMP_FILE); +} + +static void on_plugin_services_menu_item_click() +{ + debug("on_plugin_services_menu_item_click()\n"); + + streambrowser_win_show(); + streamdir_update(NULL, NULL, NULL); +} +
