# HG changeset patch # User Calin Crisan ccrisan@gmail.com # Date 1210981810 -10800 # Node ID 28498c0bde64e6dffec6abd14a4ed8144fd34d33 # Parent 049f212e7e002b821d1bfc89284810d2dd7f6bb3 Initial commit for the streambrowser plugin diff -r 049f212e7e00 -r 28498c0bde64 src/cdaudio-ng/cdaudio-ng.h --- a/src/cdaudio-ng/cdaudio-ng.h Fri May 16 16:01:18 2008 +0200 +++ b/src/cdaudio-ng/cdaudio-ng.h Sat May 17 02:50:10 2008 +0300 @@ -21,10 +21,10 @@ #define CDAUDIO_NG_H -#define DEF_STRING_LEN 256 -#define CDDA_DUMMYPATH "cdda://" -#define CDDA_DAE_FRAMES 8 -#define CDDA_DEFAULT_LIMIT_SPEED 1 +#define DEF_STRING_LEN 256 +#define CDDA_DUMMYPATH "cdda://" +#define CDDA_DAE_FRAMES 8 +#define CDDA_DEFAULT_LIMIT_SPEED 1 #define CDDA_DEFAULT_CDDB_SERVER "freedb.org" #define CDDA_DEFAULT_CDDB_PORT 8880 #define CDDA_DEFAULT_PROXY_PORT 8080 @@ -46,7 +46,7 @@ lsn_t endlsn; lsn_t currlsn; lsn_t seektime; /* in miliseconds */ - InputPlayback *pplayback; + InputPlayback *pplayback; GThread *thread; } dae_params_t; diff -r 049f212e7e00 -r 28498c0bde64 src/neon/Makefile --- a/src/neon/Makefile Fri May 16 16:01:18 2008 +0200 +++ b/src/neon/Makefile Sat May 17 02:50:10 2008 +0300 @@ -8,6 +8,6 @@ plugindir := ${plugindir}/${TRANSPORT_PLUGIN_DIR} -CFLAGS += ${PLUGIN_CFLAGS} +CFLAGS += ${PLUGIN_CFLAGS} -DNEON_DEBUG CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${ARCH_DEFINES} ${XML_CPPFLAGS} ${NEON_CFLAGS} -I../.. -D_RB_USE_GLIB LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${XML_LIBS} ${NEON_LIBS} diff -r 049f212e7e00 -r 28498c0bde64 src/neon/neon.c --- a/src/neon/neon.c Fri May 16 16:01:18 2008 +0200 +++ b/src/neon/neon.c Sat May 17 02:50:10 2008 +0300 @@ -862,7 +862,6 @@ */ VFSFile* neon_aud_vfs_fopen_impl(const gchar* path, const gchar* mode) { - VFSFile* file; struct neon_handle* handle; diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/Makefile Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,14 @@ +PLUGIN = streambrowser${PLUGIN_SUFFIX} + +SRCS = streambrowser.c \ + streamdir.c \ + shoutcast.c + +include ../../buildsys.mk +include ../../extra.mk + +plugindir := ${plugindir}/${INPUT_PLUGIN_DIR} + +CFLAGS += ${PLUGIN_CFLAGS} +CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${XML_CPPFLAGS} ${ARCH_DEFINES} -I../.. +LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${MOWGLI_LIBS} ${XML_LIBS} diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/shoutcast.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.c Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,101 @@ + +#include +#include +#include +#include + +#include "streambrowser.h" +#include "shoutcast.h" + + +static streaminfo_t* shoutcast_streaminfo_fetch(gchar *station_name, gchar *station_id); +static category_t* shoutcast_category_fetch(gchar *category_name); + + +static streaminfo_t *shoutcast_streaminfo_fetch(gchar *station_name, gchar *station_id) +{ + gchar url[DEF_STRING_LEN]; + g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, station_id); + + streaminfo_t *streaminfo = streaminfo_new(station_name, url); + + // todo: read the .pls file fetched from the above url + + return streaminfo; +} + +static category_t *shoutcast_category_fetch(gchar *category_name) +{ + category_t *category = category_new(category_name); + + gchar url[DEF_STRING_LEN]; + g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_CATEGORY_URL, category_name); + + xmlDoc *doc = xmlReadFile(url, NULL, 0); + if (doc == NULL) { + error(" shoutcast: failed to read \"%s\" category file\n", category_name); + return NULL; + } + + debug(" shoutcast: category file fetched\n"); + + 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 *station_name = (gchar*) xmlGetProp(node, (xmlChar *) "name"); + gchar *station_id = (gchar*) xmlGetProp(node, (xmlChar *) "id"); + + debug(" shoutcast: fetching stream info for name = \"%s\" and id = %s\n", station_name, station_id); + + streaminfo_t *streaminfo = shoutcast_streaminfo_fetch(station_name, station_id); + streaminfo_add(category, streaminfo); + + // todo: debug - print info about streaminfon urls + debug(" shoutcast: stream info added for name = \"%s\" and id = %s\n", station_name, station_id); + } + } + + return category; +} + + +streamdir_t* shoutcast_streamdir_fetch() +{ + streamdir_t *streamdir = streamdir_new("Shoutcast"); + + debug("shoutcast: fetching streaming directory file\n"); + + // todo: replace dummy filename with SHOUTCAST_DIRECTORY_URL + xmlDoc *doc = xmlReadFile("shoutcast.xml", NULL, 0); + if (doc == NULL) { + error("shoutcast: failed to read stream directory file\n"); + return NULL; + } + + debug("shoutcast: streaming directory file fetched\n"); + + 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) { + gchar *category_name = (gchar*) xmlGetProp(node, (xmlChar *) "name"); + + debug(" shoutcast: fetching category \"%s\"\n", category_name); + + category_t *category = shoutcast_category_fetch(category_name); + category_add(streamdir, category); + + debug(" shoutcast: added category \"%s\"\n", category_name); + } + } + + exit(0); +} + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/shoutcast.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.h Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,17 @@ + +#ifndef SHOUTCAST_H +#define SHOUTCAST_H + +#include "streambrowser.h" +#include "streamdir.h" + +#define SHOUTCAST_STREAMDIR_URL "http://www.shoutcast.com/sbin/newxml.phtml" +#define SHOUTCAST_CATEGORY_URL "http://www.shoutcast.com/sbin/newxml.phtml?genre=%s" +#define SHOUTCAST_STREAMINFO_URL "http://www.shoutcast.com/sbin/shoutcast-playlist.pls?rn=%s&file=filename.pls" + + +streamdir_t* shoutcast_streamdir_fetch(); + + +#endif // SHOUTCAST_H + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/shoutcast.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/shoutcast.xml Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/streambrowser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streambrowser.c Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,100 @@ + +#include +#include +#include +#include + +#include "streambrowser.h" +#include "streamdir.h" +#include "shoutcast.h" + + +static void sb_init(); +static void sb_about(); +static void sb_configure(); +static void sb_cleanup(); + +static void menu_click(); +static void add_plugin_services_menu_item(); + + +static GeneralPlugin sb_plugin = +{ + .description = "Stream Browser", + .init = sb_init, + .about = sb_about, + .configure = sb_configure, + .cleanup = sb_cleanup +}; + +GeneralPlugin *sb_gplist[] = +{ + &sb_plugin, + NULL +}; + +SIMPLE_GENERAL_PLUGIN(streambrowser, sb_gplist); + + +void debug(const char *fmt, ...) +{ + // todo: replace with config->debug + if (TRUE) { + va_list ap; + fprintf(stderr, "* streambrowser: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +void error(const char *fmt, ...) +{ + va_list ap; + fprintf(stderr, "! streambrowser: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +static void sb_init() +{ + debug("sb_init()\n"); + + //shoutcast_streamdir_fetch(); +} + +static void sb_about() +{ + debug("sb_about()\n"); +} + +static void sb_configure() +{ + debug("sb_configure()\n"); +} + +static void sb_cleanup() +{ + debug("sb_cleanup()\n"); +} + +static void menu_click() +{ + debug("menu_click()\n"); +} + +static void add_plugin_services_menu_item() +{ + /* + GtkWidget *menu_item; + + 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); + */ +} + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/streambrowser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streambrowser.h Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,13 @@ + +#ifndef STREAMBROWSER_H +#define STREAMBROWSER_H + +#define DEF_STRING_LEN 256 + + +void debug(const char *fmt, ...); +void error(const char *fmt, ...); + + +#endif // STREAMBROWSER_H + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/streamdir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streamdir.c Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,138 @@ + +#include +#include + +#include "streambrowser.h" +#include "streamdir.h" + + +streamdir_t* streamdir_new(gchar *name) +{ + streamdir_t *streamdir = (streamdir_t*) g_malloc(sizeof(streamdir_t)); + strncpy(streamdir->name, name, DEF_STRING_LEN); + streamdir->category_list = NULL; + + return streamdir; +} + +void streamdir_delete(streamdir_t *streamdir) +{ + GList *iterator; + category_t *category; + + for (iterator = g_list_first(streamdir->category_list); iterator != NULL; iterator = g_list_next(streamdir->category_list)) { + category = iterator->data; + category_delete(category); + } + + g_list_free(streamdir->category_list); + g_free(streamdir); +} + + +category_t* category_new(gchar *name) +{ + category_t *category = (category_t*) g_malloc(sizeof(category_t)); + strncpy(category->name, name, DEF_STRING_LEN); + category->streaminfo_list = NULL; + + return category; +} + +void category_delete(category_t *category) +{ + GList *iterator; + streaminfo_t *streaminfo; + + for (iterator = g_list_first(category->streaminfo_list); iterator != NULL; iterator = g_list_next(category->streaminfo_list)) { + streaminfo = iterator->data; + streaminfo_delete(streaminfo); + } + + g_list_free(category->streaminfo_list); + g_free(category); +} + +void category_add(streamdir_t *streamdir, category_t *category) +{ + streamdir->category_list = g_list_append(streamdir->category_list, category); +} + +void category_remove(streamdir_t *streamdir, category_t *category) +{ + streamdir->category_list = g_list_remove(streamdir->category_list, category); +} + +category_t* category_get_by_index(streamdir_t *streamdir, gint index) +{ + return (category_t*) g_list_nth_data(streamdir->category_list, index); +} + +category_t* category_get_by_name(streamdir_t *streamdir, gchar *name) +{ + GList *iterator; + category_t *category; + + for (iterator = g_list_first(streamdir->category_list); iterator != NULL; iterator = g_list_next(streamdir->category_list)) { + category = iterator->data; + if (!strncasecmp(category->name, name, DEF_STRING_LEN)) + return category; + } + + return NULL; +} + +gint category_get_count(streamdir_t *streamdir) +{ + return g_list_length(streamdir->category_list); +} + + +streaminfo_t* streaminfo_new(gchar *name, gchar *url) +{ + streaminfo_t *streaminfo = (streaminfo_t*) g_malloc(sizeof(streaminfo_t)); + strncpy(streaminfo->name, name, DEF_STRING_LEN); + strncpy(streaminfo->url, url, DEF_STRING_LEN); + + return streaminfo; +} + +void streaminfo_delete(streaminfo_t *streaminfo) +{ + g_free(streaminfo); +} + +void streaminfo_add(category_t *category, streaminfo_t *streaminfo) +{ + category->streaminfo_list = g_list_append(category->streaminfo_list, streaminfo); +} + +void streaminfo_remove(category_t *category, streaminfo_t *streaminfo) +{ + category->streaminfo_list = g_list_remove(category->streaminfo_list, streaminfo); +} + +streaminfo_t* streaminfo_get_by_index(category_t *category, gint index) +{ + return (streaminfo_t*) g_list_nth_data(category->streaminfo_list, index); +} + +streaminfo_t* streaminfo_get_by_name(category_t *category, gchar *name) +{ + GList *iterator; + streaminfo_t *streaminfo; + + for (iterator = g_list_first(category->streaminfo_list); iterator != NULL; iterator = g_list_next(category->streaminfo_list)) { + streaminfo = iterator->data; + if (!strncasecmp(streaminfo->name, name, DEF_STRING_LEN)) + return streaminfo; + } + + return NULL; +} + +gint streaminfo_get_count(category_t *category) +{ + return g_list_length(category->streaminfo_list); +} + diff -r 049f212e7e00 -r 28498c0bde64 src/streambrowser/streamdir.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/streambrowser/streamdir.h Sat May 17 02:50:10 2008 +0300 @@ -0,0 +1,55 @@ + +#ifndef STREAMDIR_H +#define STREAMDIR_H + + +#include + +#include "streambrowser.h" + + +typedef struct { + + gchar name[DEF_STRING_LEN]; + gchar url[DEF_STRING_LEN]; + +} streaminfo_t; + +typedef struct { + + gchar name[DEF_STRING_LEN]; + GList* streaminfo_list; + +} category_t; + +typedef struct { + + gchar name[DEF_STRING_LEN]; + GList* category_list; + +} streamdir_t; + + +streamdir_t* streamdir_new(gchar *name); +void streamdir_delete(streamdir_t *streamdir); + +category_t* category_new(gchar *name); +void category_delete(category_t *category); +void category_add(streamdir_t *streamdir, category_t *category); +void category_remove(streamdir_t *streamdir, category_t *category); +category_t* category_get_by_index(streamdir_t *streamdir, gint index); +category_t* category_get_by_name(streamdir_t *streamdir, gchar *name); +gint category_get_count(streamdir_t *streamdir); + +streaminfo_t* streaminfo_new(gchar *name, gchar *url); +void streaminfo_delete(streaminfo_t *streaminfo); +void streaminfo_free(streaminfo_t *streaminfo); +void streaminfo_add(category_t *category, streaminfo_t *streaminfo); +void streaminfo_remove(category_t *category, streaminfo_t *streaminfo); +streaminfo_t* streaminfo_get_by_index(category_t *category, gint index); +streaminfo_t* streaminfo_get_by_name(category_t *category, gchar *name); +gint streaminfo_get_count(category_t *category); + + +#endif // STREAMDIR_H +