changeset 2570:28498c0bde64

Initial commit for the streambrowser plugin
author Calin Crisan ccrisan@gmail.com
date Sat, 17 May 2008 02:50:10 +0300
parents 049f212e7e00
children 3a59f3d578f1
files src/cdaudio-ng/cdaudio-ng.h src/neon/Makefile src/neon/neon.c src/streambrowser/Makefile src/streambrowser/shoutcast.c src/streambrowser/shoutcast.h src/streambrowser/shoutcast.xml src/streambrowser/streambrowser.c src/streambrowser/streambrowser.h src/streambrowser/streamdir.c src/streambrowser/streamdir.h
diffstat 11 files changed, 456 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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}
--- 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;
 
--- /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}
--- /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 <string.h>
+#include <glib.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#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);
+}
+
--- /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
+
--- /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 @@
+<?xml version="1.0" encoding='UTF-8' standalone="yes"?>
+<genrelist>
+<genre name="24h"></genre>
+<genre name="Acid"></genre>
+<genre name="Adult"></genre>
+<genre name="Adulto"></genre>
+<genre name="African"></genre>
+<genre name="Afrikaans"></genre>
+<genre name="Afro"></genre>
+<genre name="Zouk"></genre>
+</genrelist>
+
--- /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 <stdlib.h>
+#include <gtk/gtk.h>
+#include <audacious/plugin.h>
+#include <audacious/ui_plugin_menu.h>
+
+#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);
+	*/
+}
+
--- /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
+
--- /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 <string.h>
+#include <glib.h>
+
+#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);
+}
+
--- /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 <glib.h>
+
+#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
+