Index: configure.ac
===================================================================
--- configure.ac	(revision 5862)
+++ configure.ac	(working copy)
@@ -953,6 +953,7 @@
 corelib/Makefile
 plugins/Makefile
 plugins/sample/Makefile
+plugins/goear/Makefile
 plugins/audiocd/Makefile
 plugins/coherence/Makefile
 plugins/coherence/upnp_coherence/Makefile
Index: plugins/goear/goear.rb-plugin.in
===================================================================
--- plugins/goear/goear.rb-plugin.in	(revision 0)
+++ plugins/goear/goear.rb-plugin.in	(revision 0)
@@ -0,0 +1,9 @@
+[RB Plugin]
+Module=goear
+IAge=1
+_Name=GoEar
+_Description=Plays GoEar audio streams
+Icon=goear.png
+Authors=Victor Manuel Jaquez Leal <vjaquez@igalia.com>
+Copyright=Copyright © 2008 Victor Manuel Jaquez Leal
+Website=http://blogs.igalia.com/vjaquez
Index: plugins/goear/rb-goear-http.h
===================================================================
--- plugins/goear/rb-goear-http.h	(revision 0)
+++ plugins/goear/rb-goear-http.h	(revision 0)
@@ -0,0 +1,79 @@
+/*
+ * rb-goear-http.h
+ * 
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_GOEAR_HTTP_H
+#define __RB_GOEAR_HTTP_H
+
+#include <glib-object.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_GOEAR_HTTP                              \
+        (rb_goear_http_get_type ())
+#define RB_GOEAR_HTTP(obj)                              \
+        (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_GOEAR_HTTP, RBGoearHttp))
+#define RB_GOEAR_HTTP_CLASS(klass)                      \
+        (G_TYPE_CHECK_CLASS_CAST ((klass), RB_TYPE_GOEAR_HTTP, RBGoearHttpClass))
+#define RB_IS_GOEAR_HTTP(obj)                           \
+        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_GOEAR_HTTP))
+#define RB_IS_GOEAR_HTTP_CLASS(klass)                   \
+        (G_TYPE_CHECK_CLASS_TYPE ((klass), RB_TYPE_GOEAR_HTTP))
+#define RB_GOEAR_HTTP_GET_CLASS(obj)                    \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj), RB_TYPE_GOEAR_HTTP, RBGoearHttpClass))
+
+typedef struct _RBGoearHttp RBGoearHttp;
+typedef struct _RBGoearHttpClass RBGoearHttpClass;
+
+struct _RBGoearHttp
+{
+        GObject parent;
+};
+
+struct _RBGoearHttpClass
+{
+        GObjectClass parent_class;
+
+        void (*response) (RBGoearHttp* self, const gchar* mimetype,
+                          const gchar* content, guint length);
+        void (*error) (RBGoearHttp* self, gchar* msg);
+};
+
+GType rb_goear_http_get_type (void);
+
+RBGoearHttp* rb_goear_http_new (SoupURI* proxyuri);
+gboolean rb_goear_http_get (RBGoearHttp *self, const gchar* uri);
+gboolean rb_goear_http_abort (RBGoearHttp *self);
+gboolean rb_goear_http_get_sync (RBGoearHttp* self, const gchar* uri,
+                                 const gchar** mimetype, const gchar** content,
+                                 guint* length);
+
+G_END_DECLS
+
+#endif /* __RB_GOEAR_HTTP_H */
Index: plugins/goear/rb-goear-source.h
===================================================================
--- plugins/goear/rb-goear-source.h	(revision 0)
+++ plugins/goear/rb-goear-source.h	(revision 0)
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 - *
+ * rb-goear-source.h
+ *
+ * Copyright (C) 2008 - Victor Manuel Jaquez	Leal <vjaquez@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Rhythmbox authors hereby grants permission for non-GPL compatible
+ * GStreamer plugins to be used and distributed together with GStreamer
+ * and Rhythmbox. This permission is above and beyond the permissions granted
+ * by the GPL license by which Rhythmbox is covered. If you modify this code
+ * you may extend this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301	USA.
+ *
+ */
+
+#ifndef __RB_GOEAR_SOURCE_H
+#define __RB_GOEAR_SOURCE_H
+
+#include "rb-shell.h"
+#include "rb-browser-source.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_GOEAR_SOURCE		\
+	(rb_goear_source_get_type ())
+#define RB_GOEAR_SOURCE(o)		\
+	(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_GOEAR_SOURCE, RBGoearSource))
+#define RB_GOEAR_SOURCE_CLASS(k)	\
+	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_GOEAR_SOURCE, RBGoearSourceClass))
+#define RB_IS_GOEAR_SOURCE(o)		\
+	(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_GOEAR_SOURCE))
+#define RB_IS_GOEAR_SOURCE_CLASS(k)	\
+	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_GOEAR_SOURCE))
+#define RB_GOEAR_SOURCE_GET_CLASS(o)	\
+	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_GOEAR_SOURCE, RBGoearSourceClass))
+
+typedef struct _RBGoearSource RBGoearSource;
+typedef struct _RBGoearSourceClass RBGoearSourceClass;
+
+struct _RBGoearSource
+{
+	RBSource parent;
+};
+
+struct _RBGoearSourceClass
+{
+	RBSourceClass parent;
+};
+
+GType rb_goear_source_get_type (void);
+GType rb_goear_source_register_type (GTypeModule *module);
+
+RBSource* rb_goear_source_new (RBShell *shell);
+
+G_END_DECLS
+
+#endif /* __RB_GOEAR_SOURCE_H */
Index: plugins/goear/rb-goear-utils.h
===================================================================
--- plugins/goear/rb-goear-utils.h	(revision 0)
+++ plugins/goear/rb-goear-utils.h	(revision 0)
@@ -0,0 +1,43 @@
+/*
+ * rb-goear-utils.h
+ * 
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef   	__RB_GOEAR_UTILS_H
+#define   	__RB_GOEAR_UTILS_H
+
+#include <glib.h>
+#include <libxml/tree.h>
+
+#define RB_GOEAR_LINK_CLASS "escuchar"
+
+gchar* get_stream_uri (xmlNode* node);
+gchar* parse_xml (const gchar* content, guint length);
+gboolean is_track_link (xmlNode* node);
+gchar* normalize_query (const gchar* text);
+
+#endif 	    /* !__RB_GOEAR_UTILS_H */
Index: plugins/goear/rb-goear-view.c
===================================================================
--- plugins/goear/rb-goear-view.c	(revision 0)
+++ plugins/goear/rb-goear-view.c	(revision 0)
@@ -0,0 +1,196 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * rb-goear-view.c
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Rhythmbox authors hereby grants permission for non-GPL compatible
+ * GStreamer plugins to be used and distributed together with GStreamer
+ * and Rhythmbox. This permission is above and beyond the permissions granted
+ * by the GPL license by which Rhythmbox is covered. If you modify this code
+ * you may extend this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "rb-goear-view.h"
+
+#include <gtk/gtk.h>
+
+#include "rb-entry-view.h"
+#include "libsexy/sexy-icon-entry.h"
+
+enum
+{
+	SEARCH,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct _RBGoearViewPrivate RBGoearViewPrivate;
+struct _RBGoearViewPrivate
+{
+	GtkWidget* search;
+};
+
+#define RB_GOEAR_VIEW_GET_PRIVATE(obj) \
+	G_TYPE_INSTANCE_GET_PRIVATE ((obj), RB_TYPE_GOEAR_VIEW,	 RBGoearViewPrivate);
+
+G_DEFINE_TYPE (RBGoearView, rb_goear_view, GTK_TYPE_VBOX);
+
+static void
+search_cb (GtkEntry* search, gpointer user_data)
+{
+	RBGoearView* self = RB_GOEAR_VIEW (user_data);
+	const gchar* text = gtk_entry_get_text (GTK_ENTRY (search));
+
+	if (g_utf8_strlen (text, -1) > 0)
+	{
+		g_signal_emit (G_OBJECT (self), signals[SEARCH], 0, text);
+	}
+
+	return;
+}
+
+static GtkWidget*
+build_search_box (RBGoearView* self)
+{
+	RBGoearViewPrivate* priv;
+	GtkWidget* search_box;
+	GtkWidget* label;
+	GtkWidget* align;
+	GtkWidget* ebox;
+	GtkTooltips* tooltips;
+	GtkWidget* ret;
+
+	priv = RB_GOEAR_VIEW_GET_PRIVATE (self);
+
+	search_box = gtk_hbox_new (FALSE, 5);
+
+	label = gtk_label_new_with_mnemonic ("_Search:");
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
+	gtk_box_pack_start (GTK_BOX (search_box), label, FALSE, TRUE, 0);
+
+	priv->search = sexy_icon_entry_new ();
+	sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (priv->search));
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->search);
+
+	gtk_box_pack_start (GTK_BOX (search_box), priv->search, TRUE, TRUE, 0);
+
+	ebox = gtk_event_box_new ();
+	tooltips = gtk_tooltips_new ();
+	gtk_tooltips_enable (tooltips);
+	gtk_tooltips_set_tip (tooltips, ebox,
+			      "Search by artists or title", NULL);
+
+	gtk_container_add (GTK_CONTAINER (ebox), search_box);
+
+	align = gtk_alignment_new (1.0, 0.5, 1.0, 1.0);
+	gtk_container_add (GTK_CONTAINER (align), ebox);
+
+	ret = gtk_hbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (ret), align, TRUE, TRUE, 5);
+
+	return ret;
+}
+
+static void
+build_ui (RBGoearView* self)
+{
+	gtk_box_pack_start (GTK_BOX (self), build_search_box (self),
+			    FALSE, FALSE, 5);
+
+	return;
+}
+
+static void
+connect_signals (RBGoearView* self)
+{
+	RBGoearViewPrivate* priv;
+
+	priv = RB_GOEAR_VIEW_GET_PRIVATE (self);
+
+	g_signal_connect (G_OBJECT (priv->search), "activate",
+			  G_CALLBACK (search_cb), self);
+
+	return;
+}
+
+static GObject*
+rb_goear_view_constructor (GType type, guint n_construct_properties,
+			     GObjectConstructParam* construct_properties)
+{
+	RBGoearView* self;
+
+	self = RB_GOEAR_VIEW (
+		G_OBJECT_CLASS (rb_goear_view_parent_class)->constructor (
+			type, n_construct_properties, construct_properties
+			)
+		);
+
+	build_ui (self);
+	connect_signals (self);
+
+	return G_OBJECT (self);
+}
+
+static void
+rb_goear_view_class_init (RBGoearViewClass* klass)
+{
+	GObjectClass* object_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->constructor = rb_goear_view_constructor;
+
+	signals[SEARCH] =
+		g_signal_new ("search",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBGoearViewClass, search),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_STRING);
+
+	g_type_class_add_private (klass, sizeof (RBGoearViewPrivate));
+
+	return;
+}
+
+static void
+rb_goear_view_init (RBGoearView* self)
+{
+	g_object_set (self, "homogeneous", FALSE, "spacing", 5, NULL);
+	return;
+}
+
+void
+rb_goear_view_add_browser (RBGoearView* self, GtkWidget* browser)
+{
+	gtk_box_pack_end (GTK_BOX (self), browser, TRUE, TRUE, 0);
+
+	return;
+}
+
+GtkWidget*
+rb_goear_view_new ()
+{
+	return GTK_WIDGET (g_object_new (RB_TYPE_GOEAR_VIEW, NULL));
+}
Index: plugins/goear/Makefile.am
===================================================================
--- plugins/goear/Makefile.am	(revision 0)
+++ plugins/goear/Makefile.am	(revision 0)
@@ -0,0 +1,98 @@
+NULL =
+
+plugindir = $(PLUGINDIR)/goear
+plugin_LTLIBRARIES = libgoear.la
+
+libgoear_la_SOURCES = 					\
+	rb-goear-plugin.c				\
+	rb-goear-source.h				\
+	rb-goear-source.c				\
+	rb-goear-view.h					\
+	rb-goear-view.c					\
+	rb-goear-marshal.h				\
+	rb-goear-marshal.c				\
+	rb-goear-http.h					\
+	rb-goear-http.c					\
+	rb-goear-utils.h				\
+	rb-goear-utils.c
+
+libgoear_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libgoear_la_LIBADD = 					\
+	$(top_builddir)/corelib/librhythmbox-core.la	\
+	$(SOUP_LIBS)					\
+	$(TOTEM_PLPARSER_LIBS)
+
+INCLUDES = 						\
+        -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DG_LOG_DOMAIN=\"Rhythmbox\"		 	\
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/lib                        	\
+	-I$(top_srcdir)/metadata                       	\
+	-I$(top_srcdir)/player                       	\
+	-I$(top_srcdir)/rhythmdb                       	\
+	-I$(top_srcdir)/widgets                    	\
+	-I$(top_srcdir)/sources                    	\
+	-I$(top_srcdir)/iradio                    	\
+	-I$(top_srcdir)/podcast                    	\
+	-I$(top_srcdir)/plugins				\
+	-I$(top_srcdir)/shell				\
+	-DPIXMAP_DIR=\""$(datadir)/pixmaps"\"		\
+	-DSHARE_DIR=\"$(pkgdatadir)\"                   \
+	-DDATADIR=\""$(datadir)"\"			\
+	$(SOUP_CFLAGS)					\
+	$(TOTEM_PLPARSER_CFLAGS)			\
+	$(RHYTHMBOX_CFLAGS)				\
+	-D_XOPEN_SOURCE -D_BSD_SOURCE
+
+gladedir = $(plugindir)
+glade_DATA =
+
+uixmldir = $(plugindir)
+uixml_DATA = 
+
+plugin_in_files = goear.rb-plugin.in
+
+%.rb-plugin: %.rb-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+rb-goear-marshal.h: rb-goear-marshal.list
+	@GLIB_GENMARSHAL@ 						\
+	        --prefix=rb_goear_cclosure_marshal			\
+		$(top_srcdir)/plugins/goear/rb-goear-marshal.list 	\
+		--header > xgen-gmc 					\
+	&& cp xgen-gmc $(@F) 						\
+	&& rm -f xgen-gmc
+
+rb-goear-marshal.c: rb-goear-marshal.h rb-goear-marshal.list
+	echo "#include \"rb-goear-marshal.h\"" > xgen-gmc		\
+	&& @GLIB_GENMARSHAL@ 						\
+	        --prefix=rb_goear_cclosure_marshal 			\
+		$(top_srcdir)/plugins/goear/rb-goear-marshal.list	\
+		--body >> xgen-gmc 					\
+	&& cp xgen-gmc $(@F) 						\
+	&& rm -f xgen-gmc
+
+BUILT_SOURCES =							\
+	$(plugin_in_files:.rb-plugin.in=.rb-plugin) 		\
+	rb-goear-marshal.c 					\
+	rb-goear-marshal.h					\
+	$(NULL)
+
+plugin_DATA = 							\
+	$(BUILT_SOURCES)					\
+	$(top_srcdir)/plugins/goear/goear.png			\
+	$(NULL)
+
+EXTRA_DIST = 							\
+	$(plugin_in_files)					\
+	$(uixml_DATA)						\
+	$(glade_DATA)						\
+	$(top_srcdir)/plugins/goear/goear.png			\
+	$(NULL)
+
+CLEANFILES = 			\
+	$(BUILT_SOURCES)	\
+	$(NULL)
+
+DISTCLEANFILES =		\
+	$(BUILT_SOURCES)	\
+	$(NULL)
Index: plugins/goear/rb-goear-plugin.c
===================================================================
--- plugins/goear/rb-goear-plugin.c	(revision 0)
+++ plugins/goear/rb-goear-plugin.c	(revision 0)
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * rb-goear-plugin.c
+ *
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The Rhythmbox authors hereby grants permission for non-GPL compatible
+ * GStreamer plugins to be used and distributed together with GStreamer
+ * and Rhythmbox. This permission is above and beyond the permissions granted
+ * by the GPL license by which Rhythmbox is covered. If you modify this code
+ * you may extend this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301	 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h> /* For strlen */
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "rb-plugin.h"
+#include "rb-debug.h"
+#include "rb-shell.h"
+#include "rb-dialog.h"
+
+#include "rb-goear-source.h"
+
+#define RB_TYPE_GOEAR_PLUGIN	      \
+	(rb_goear_plugin_get_type ())
+#define RB_GOEAR_PLUGIN(o)	      \
+	(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_GOEAR_PLUGIN, RBGoearPlugin))
+#define RB_GOEAR_PLUGIN_CLASS(k)      \
+	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_GOEAR_PLUGIN, RBGoearPluginClass))
+#define RB_IS_GOEAR_PLUGIN(o)	      \
+	(G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_GOEAR_PLUGIN))
+#define RB_IS_GOEAR_PLUGIN_CLASS(k)   \
+	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_GOEAR_PLUGIN))
+#define RB_GOEAR_PLUGIN_GET_CLASS(o)  \
+	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_GOEAR_PLUGIN, RBGoearPluginClass))
+
+typedef struct _RBGoearPluginClass RBGoearPluginClass;
+typedef struct _RBGoearPlugin RBGoearPlugin;
+typedef struct _RBGoearPluginPrivate RBGoearPluginPrivate;
+
+struct _RBGoearPluginPrivate
+{
+	RBSource* goear_source;
+};
+
+struct _RBGoearPlugin
+{
+	RBPlugin parent;
+};
+
+struct _RBGoearPluginClass
+{
+	RBPluginClass parent_class;
+};
+
+G_MODULE_EXPORT GType register_rb_plugin (GTypeModule *module);
+GType rb_goear_plugin_get_type (void) G_GNUC_CONST;
+
+static void rb_goear_plugin_init (RBGoearPlugin *plugin);
+static void rb_goear_plugin_finalize (GObject *object);
+static void impl_activate (RBPlugin *plugin, RBShell *shell);
+static void impl_deactivate (RBPlugin *plugin, RBShell *shell);
+
+static GdkPixbuf* get_source_icon (RBPlugin* plugin);
+
+RB_PLUGIN_REGISTER (RBGoearPlugin, rb_goear_plugin)
+
+#define RB_GOEAR_PLUGIN_GET_PRIVATE(object) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((object), RB_TYPE_GOEAR_PLUGIN, RBGoearPluginPrivate))
+
+#define RB_GOEAR_ICON "goear.png"
+
+static void
+rb_goear_plugin_class_init (RBGoearPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBPluginClass *plugin_class = RB_PLUGIN_CLASS (klass);
+
+	object_class->finalize = rb_goear_plugin_finalize;
+
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+
+	g_type_class_add_private (object_class, sizeof (RBGoearPluginPrivate));
+
+	return;
+}
+
+static void
+rb_goear_plugin_init (RBGoearPlugin *plugin)
+{
+	RBGoearPluginPrivate* priv;
+
+	priv = RB_GOEAR_PLUGIN_GET_PRIVATE (plugin);
+	priv->goear_source = NULL;
+
+	rb_debug ("RBGoearPlugin initialising");
+
+	return;
+}
+
+static void
+rb_goear_plugin_finalize (GObject *object)
+{
+	RBGoearPluginPrivate *priv;
+
+	rb_debug ("RBGoearPlugin finalising");
+
+	priv = RB_GOEAR_PLUGIN_GET_PRIVATE (object);
+
+	rb_source_delete_thyself (priv->goear_source);
+	priv->goear_source = NULL;
+
+	G_OBJECT_CLASS (rb_goear_plugin_parent_class)->finalize (object);
+
+	return;
+}
+
+static void
+impl_activate (RBPlugin *plugin, RBShell *shell)
+{
+	RBGoearPluginPrivate* priv;
+	GdkPixbuf* icon_pixbuf;
+
+	priv = RB_GOEAR_PLUGIN_GET_PRIVATE (plugin);
+
+	priv->goear_source = rb_goear_source_new (shell);
+
+	icon_pixbuf = get_source_icon (plugin);
+	if (icon_pixbuf != NULL)
+	{
+		g_object_set (G_OBJECT (priv->goear_source),
+			      "icon", icon_pixbuf, NULL);
+		g_object_unref (icon_pixbuf);
+	}
+
+	rb_shell_append_source (shell, priv->goear_source, NULL);
+
+	return;
+}
+
+static void
+impl_deactivate	(RBPlugin *plugin, RBShell *shell)
+{
+	RBGoearPluginPrivate* priv;
+
+	priv = RB_GOEAR_PLUGIN_GET_PRIVATE (plugin);
+
+	return;
+}
+
+static GdkPixbuf*
+get_source_icon (RBPlugin* plugin)
+{
+	gchar* filename;
+	gint size;
+	GdkPixbuf* pixbuf;
+
+	filename = rb_plugin_find_file (plugin, RB_GOEAR_ICON);
+
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
+	pixbuf = gdk_pixbuf_new_from_file_at_size (filename, size, size, NULL);
+	g_free (filename);
+
+	return pixbuf;
+}
Index: plugins/goear/rb-goear-http.c
===================================================================
--- plugins/goear/rb-goear-http.c	(revision 0)
+++ plugins/goear/rb-goear-http.c	(revision 0)
@@ -0,0 +1,387 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * rb-goear-http.c
+ *
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "rb-goear-http.h"
+#include "rb-goear-marshal.h"
+
+#include <config.h>
+
+#define USER_AGENT "Rhythmbox/" VERSION
+
+enum
+{
+	RESPONSE,
+	ERROR,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
+	PROP_0,
+	PROP_PROXY_URI
+};
+
+typedef struct _RBGoearHttpPriv RBGoearHttpPriv;
+struct _RBGoearHttpPriv
+{
+	SoupSession* session;
+	SoupURI* proxyuri;
+	guint timeoutid;
+};
+
+#define RB_GOEAR_HTTP_GET_PRIVATE(o) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_GOEAR_HTTP, RBGoearHttpPriv))
+
+static gboolean
+timeout_cb (gpointer data)
+{
+	RBGoearHttp *self;
+
+	self = RB_GOEAR_HTTP (data);
+
+	if (rb_goear_http_abort (self) == TRUE)
+	{
+		RBGoearHttpPriv* priv;
+		priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+		priv->timeoutid = 0;
+	}
+
+	return FALSE;
+}
+
+/* creates a HTTP session and set the proxy */
+static void
+create_session (RBGoearHttp* self, gboolean async)
+{
+	RBGoearHttpPriv* priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+
+	if (priv->session != NULL)
+	{
+		return; /* no need to have another */
+	}
+
+	if (async == TRUE)
+	{
+		priv->session = soup_session_async_new_with_options (
+			SOUP_SESSION_USER_AGENT, USER_AGENT, NULL
+			);
+	}
+	else
+	{
+		priv->session = soup_session_sync_new_with_options (
+			SOUP_SESSION_USER_AGENT, USER_AGENT, NULL
+			);
+	}
+
+	if (priv->proxyuri != NULL)
+	{
+		g_object_set (G_OBJECT (priv->session),
+			      SOUP_SESSION_PROXY_URI, priv->proxyuri, NULL);
+	}
+
+	return;
+}
+
+static void
+retrieval_done (SoupSession* session, SoupMessage* message, gpointer user_data)
+{
+	gchar* msg;
+	const gchar* mimetype;
+	RBGoearHttp* self;
+	RBGoearHttpPriv* priv;
+
+	g_assert (RB_IS_GOEAR_HTTP (user_data));
+
+	self = RB_GOEAR_HTTP (user_data);
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+
+	if (priv->timeoutid > 0)
+	{
+		g_source_remove (priv->timeoutid);
+	}
+
+	if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code))
+	{
+		if (message->status_code != SOUP_STATUS_CANCELLED)
+		{
+			msg = g_strdup_printf ("HTTP error - HTTP/1.%d %d %s",
+					       soup_message_get_http_version (message),
+					       message->status_code,
+					       message->reason_phrase);
+
+			g_signal_emit (self, signals[ERROR], 0, msg);
+		}
+		else
+		{
+			g_debug ("operation cancelled");
+		}
+
+		return;
+	}
+
+	mimetype = soup_message_headers_get (message->response_headers,
+					     "Content-Type");
+
+	g_signal_emit (self, signals[RESPONSE], 0,
+		       mimetype,
+		       message->response_body->data,
+		       (guint) message->response_body->length);
+
+	return;
+}
+
+G_DEFINE_TYPE (RBGoearHttp, rb_goear_http, G_TYPE_OBJECT)
+
+static void
+rb_goear_http_finalize (GObject *object)
+{
+	RBGoearHttpPriv* priv;
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (object);
+
+	if (priv->proxyuri != NULL)
+	{
+		soup_uri_free (priv->proxyuri);
+		priv->proxyuri = NULL;
+	}
+
+	if (priv->session != NULL)
+	{
+		soup_session_abort (priv->session);
+		g_object_unref (priv->session);
+		priv->session = NULL;
+	}
+
+	(*G_OBJECT_CLASS (rb_goear_http_parent_class)->finalize) (object);
+
+	return;
+}
+
+static void
+rb_goear_http_set_property (GObject* object, guint prop_id,
+			    const GValue* value, GParamSpec* pspec)
+{
+	RBGoearHttpPriv* priv;
+	SoupURI *uri;
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (object);
+
+	switch (prop_id)
+	{
+	case PROP_PROXY_URI:
+		uri = g_value_get_boxed (value);
+
+		if (priv->proxyuri != NULL)
+		{
+			soup_uri_free (priv->proxyuri);
+		}
+
+		priv->proxyuri = uri ? soup_uri_copy (uri) : NULL;
+
+		if (priv->session != NULL)
+		{
+			g_object_set (G_OBJECT (priv->session),
+				      SOUP_SESSION_PROXY_URI, priv->proxyuri,
+				      NULL);
+		}
+
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+
+	}
+
+	return;
+}
+
+static void
+rb_goear_http_class_init (RBGoearHttpClass* klass)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = rb_goear_http_finalize;
+	object_class->set_property = rb_goear_http_set_property;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PROXY_URI,
+		g_param_spec_boxed ("proxy-uri",
+				    "Proxy URI",
+				    "The HTTP Proxy to use for this session",
+				    SOUP_TYPE_URI, G_PARAM_WRITABLE)
+		);
+
+	signals[RESPONSE] =
+		g_signal_new ("response",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBGoearHttpClass, response),
+			      NULL, NULL,
+			      rb_goear_cclosure_marshal_VOID__STRING_STRING_UINT,
+			      G_TYPE_NONE,
+			      3,
+			      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
+
+	signals[ERROR] =
+		g_signal_new ("error",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBGoearHttpClass, error),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_STRING);
+
+
+	g_type_class_add_private (klass, sizeof (RBGoearHttpPriv));
+
+	return;
+}
+
+static void
+rb_goear_http_init (RBGoearHttp* self)
+{
+	RBGoearHttpPriv* priv;
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+	priv->session = NULL;
+	priv->proxyuri = NULL;
+
+	return;
+}
+
+gboolean
+rb_goear_http_get (RBGoearHttp* self, const gchar* uri)
+{
+	RBGoearHttpPriv* priv;
+	SoupMessage* message;
+
+	g_return_val_if_fail (RB_IS_GOEAR_HTTP (self), FALSE);
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+
+	create_session (self, TRUE);
+
+	message = soup_message_new (SOUP_METHOD_GET, uri);
+
+	if (message == NULL)
+	{
+		g_debug ("Couldn't parse the URI \"%s\"", uri);
+		return FALSE;
+	}
+
+	soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT);
+
+	soup_session_queue_message (priv->session, message,
+				    retrieval_done, self);
+
+	priv->timeoutid = g_timeout_add_seconds (30, timeout_cb, self);
+
+	return TRUE;
+}
+
+gboolean
+rb_goear_http_get_sync (RBGoearHttp* self, const gchar* uri,
+			const gchar** mimetype, const gchar** content,
+			guint* length)
+{
+	RBGoearHttpPriv* priv;
+	SoupMessage* message;
+	guint status_code;
+
+	g_return_val_if_fail (RB_IS_GOEAR_HTTP (self), FALSE);
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+
+	create_session (self, FALSE);
+
+	message = soup_message_new (SOUP_METHOD_GET, uri);
+
+	if (message == NULL)
+	{
+		g_debug ("Couldn't parse the URI \"%s\"", uri);
+		return FALSE;
+	}
+
+	soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT);
+
+	status_code = soup_session_send_message (priv->session, message);
+
+	if (!SOUP_STATUS_IS_SUCCESSFUL (status_code))
+	{
+		gchar *msg;
+
+		msg = g_strdup_printf ("HTTP error - HTTP/1.%d %d %s",
+				       soup_message_get_http_version (message),
+				       message->status_code,
+				       message->reason_phrase);
+
+		g_signal_emit (self, signals[ERROR], 0, msg);
+
+		return FALSE;
+	}
+
+	*mimetype = soup_message_headers_get (message->response_headers,
+					     "Content-Type");
+	*content = message->response_body->data;
+	*length = message->response_body->length;
+
+	return TRUE;
+}
+
+gboolean
+rb_goear_http_abort (RBGoearHttp *self)
+{
+	RBGoearHttpPriv* priv;
+
+	priv = RB_GOEAR_HTTP_GET_PRIVATE (self);
+
+	if (priv->session != NULL)
+	{
+		soup_session_abort (priv->session);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+RBGoearHttp*
+rb_goear_http_new (SoupURI* proxyuri)
+{
+	return RB_GOEAR_HTTP (
+		g_object_new (RB_TYPE_GOEAR_HTTP, "proxy-uri", proxyuri, NULL)
+		);
+}
Index: plugins/goear/rb-goear-view.h
===================================================================
--- plugins/goear/rb-goear-view.h	(revision 0)
+++ plugins/goear/rb-goear-view.h	(revision 0)
@@ -0,0 +1,73 @@
+/*
+ * rb-goear-view.h
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef   	__RB_GOEAR_VIEW_H
+#define   	__RB_GOEAR_VIEW_H
+
+#include <gtk/gtkvbox.h>
+
+#include "rb-entry-view.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_GOEAR_VIEW                    \
+        (rb_goear_view_get_type ())
+#define RB_GOEAR_VIEW(o)            \
+        (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_GOEAR_VIEW, RBGoearView))
+#define RB_GOEAR_VIEW_CLASS(k)      \
+        (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_GOEAR_VIEW, RBGoearViewClass))
+#define RB_IS_GOEAR_VIEW(o)         \
+        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_GOEAR_VIEW))
+#define RB_IS_GOEAR_VIEW_CLASS(k)   \
+        (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_GOEAR_VIEW))
+#define RB_GOEAR_VIEW_GET_CLASS(o)  \
+        (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_GOEAR_VIEW, RBGoearViewClass))
+
+typedef struct _RBGoearView RBGoearView;
+typedef struct _RBGoearViewClass RBGoearViewClass;
+
+struct _RBGoearView
+{
+        GtkVBox parent;
+};
+
+struct _RBGoearViewClass
+{
+        GtkVBoxClass parent;
+
+        void (*search) (RBGoearViewClass* view, const gchar* text);
+};
+
+GType rb_goear_view_get_type (void);
+GtkWidget* rb_goear_view_new (void);
+
+void rb_goear_view_add_browser (RBGoearView* self, GtkWidget* browser);
+
+G_END_DECLS
+
+#endif 	    /* !__RB_GOEAR_VIEW_H */
Index: plugins/goear/rb-goear-marshal.list
===================================================================
--- plugins/goear/rb-goear-marshal.list	(revision 0)
+++ plugins/goear/rb-goear-marshal.list	(revision 0)
@@ -0,0 +1,24 @@
+# see glib-genmarshal(1) for a detailed description of the file format,
+# possible parameter types are:
+#   VOID        indicates   no   return   type,  or  no  extra
+#               parameters. if VOID is used as  the  parameter
+#               list, no additional parameters may be present.
+#   BOOLEAN     for boolean types (gboolean)
+#   CHAR        for signed char types (gchar)
+#   UCHAR       for unsigned char types (guchar)
+#   INT         for signed integer types (gint)
+#   UINT        for unsigned integer types (guint)
+#   LONG        for signed long integer types (glong)
+#   ULONG       for unsigned long integer types (gulong)
+#   ENUM        for enumeration types (gint)
+#   FLAGS       for flag enumeration types (guint)
+#   FLOAT       for single-precision float types (gfloat)
+#   DOUBLE      for double-precision float types (gdouble)
+#   STRING      for string types (gchar*)
+#   BOXED       for boxed (anonymous but reference counted) types (GBoxed*)
+#   POINTER     for anonymous pointer types (gpointer)
+#   OBJECT      for GObject or derived types (GObject*)
+#   NONE        deprecated alias for VOID
+#   BOOL        deprecated alias for BOOLEAN
+
+VOID:STRING,STRING,UINT
Index: plugins/goear/rb-goear-source.c
===================================================================
--- plugins/goear/rb-goear-source.c	(revision 0)
+++ plugins/goear/rb-goear-source.c	(revision 0)
@@ -0,0 +1,927 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * rb-goear-source.c
+ *
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "rb-goear-source.h"
+#include "rb-goear-view.h"
+#include "rb-goear-http.h"
+#include "rb-goear-utils.h"
+
+#include "rb-util.h"
+#include "rb-proxy-config.h"
+#include "rb-dialog.h"
+#include "rb-debug.h"
+#include "rb-metadata.h"
+
+#include <glib.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <string.h>
+
+#define RB_GOEAR_SOURCE_NAME "GoEar"
+#define RB_GOEAR_BASE_URL "http://www.goear.com/"
+#define RB_GOEAR_XML_PATH "files/sst/secm%s.xml"
+#define RB_GOEAR_FEED_SIZE 5
+
+typedef struct _RBGoearSourcePrivate RBGoearSourcePrivate;
+struct _RBGoearSourcePrivate
+{
+	RBShell* shell;
+	RhythmDB* db;
+	RBEntryView* songs;
+	RhythmDBQueryModel *model;
+
+	GtkWidget* view;
+	RBGoearHttp* wget;
+
+	gint page;
+	gchar* query;
+};
+
+#define RB_GOEAR_SOURCE_GET_PRIVATE(obj) \
+	G_TYPE_INSTANCE_GET_PRIVATE ((obj), RB_TYPE_GOEAR_SOURCE,  RBGoearSourcePrivate);
+
+static void rb_goear_source_clean (RBGoearSource* self);
+static void rb_goear_source_search (RBGoearSource* self, const gchar* text);
+static void rb_goear_source_parse_html (RBGoearSource* self,
+					const gchar* content, guint length);
+
+
+G_DEFINE_TYPE (RBGoearSource, rb_goear_source, RB_TYPE_SOURCE);
+
+
+static void
+free_query (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	if (priv->query != NULL)
+	{
+		g_free (priv->query);
+		priv->query = NULL;
+	}
+
+	return;
+}
+
+static void
+error_cb (RBGoearSource* self, gchar* msg, gpointer user_data)
+{
+	rb_error_dialog (NULL, "HTTP error", msg);
+
+	g_free (msg);
+
+	return;
+}
+
+static void
+response_cb (RBGoearSource* self, const gchar* mimetype,
+	     const gchar* response, guint length, gpointer user_data)
+{
+	if (length <= 0 || response == NULL)
+	{
+		rb_error_dialog (NULL, "HTTP error", "Invalid server anwser");
+	}
+
+	if (g_strrstr (mimetype, "text/html") != NULL)
+	{
+		rb_goear_source_parse_html (self, response, length);
+	}
+	else
+	{
+		rb_error_dialog (NULL, "HTTP error", "Invalid server anwser");
+	}
+
+	return;
+}
+
+static void
+search_cb (RBGoearSource* self, const gchar* text, gpointer user_data)
+{
+	if (g_utf8_strlen (text, -1) > 0)
+	{
+		rb_goear_source_clean (self);
+		rb_goear_source_search (self, text);
+	}
+
+	return;
+}
+
+static void
+proxy_config_changed_cb (RBProxyConfig *config, gpointer user_data)
+{
+	RBGoearHttp* wget;
+	SoupURI* proxy_uri;
+
+	wget = RB_GOEAR_HTTP (user_data);
+
+	proxy_uri = rb_proxy_config_get_libsoup_uri (config);
+	g_object_set (wget, "proxy-uri", proxy_uri, NULL);
+
+	if (proxy_uri != NULL)
+	{
+		soup_uri_free (proxy_uri);
+	}
+
+	return;
+}
+
+static void
+songs_view_sort_order_changed_cb (RBEntryView *view, RBGoearSource *source)
+{
+	rb_debug ("sort order changed");
+	rb_entry_view_resort_model (view);
+
+	return;
+}
+
+static void
+impl_delete_thyself (RBSource* source)
+{
+	rb_goear_source_clean (RB_GOEAR_SOURCE (source));
+
+	return;
+}
+
+static RBEntryView *
+impl_get_entry_view (RBSource *source)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (source);
+
+	return priv->songs;
+}
+
+static RBSourceEOFType
+impl_handle_eos (RBSource *source)
+{
+	return RB_SOURCE_EOF_NEXT;
+}
+
+static RBGoearHttp*
+instanciate_goear_http (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+	RBProxyConfig* proxy_config;
+	SoupURI* proxy_uri;
+	RBGoearHttp* wget;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	g_return_val_if_fail (priv->shell != NULL, NULL);
+
+	g_object_get (G_OBJECT (priv->shell),
+		      "proxy-config", &proxy_config, NULL);
+
+	proxy_uri = rb_proxy_config_get_libsoup_uri (proxy_config);
+	wget = rb_goear_http_new (proxy_uri);
+
+	if (proxy_uri != NULL)
+	{
+		soup_uri_free (proxy_uri);
+	}
+
+	if (proxy_config != NULL)
+	{
+		g_signal_connect (proxy_config, "config-changed",
+				  G_CALLBACK (proxy_config_changed_cb), wget);
+
+		g_object_unref (proxy_config);
+	}
+
+	return wget;
+}
+
+
+static gchar*
+fetch_playback_uri (RBGoearSource* self, const gchar* id)
+{
+	RBGoearHttp* wget;
+	gchar* mp3uri;
+	gchar* xmluri;
+	const gchar* mimetype;
+	const gchar* content;
+	guint length;
+
+	mp3uri = NULL;
+
+	wget = instanciate_goear_http (self);
+
+	xmluri = g_strdup_printf (RB_GOEAR_BASE_URL RB_GOEAR_XML_PATH, id);
+	rb_debug ("URI to fetch = \"%s\"\n", xmluri);
+
+	rb_goear_http_get_sync (wget, xmluri, &mimetype, &content, &length);
+	g_free (xmluri);
+
+	if (g_strrstr (mimetype, "application/xml") != NULL)
+	{
+		mp3uri = parse_xml (content, length);
+	}
+
+	g_object_unref (wget);
+
+	return mp3uri;
+}
+
+static void
+set_metadata_string_default (RhythmDB *db,
+				     RBMetaData *metadata,
+				     RhythmDBEntry *entry,
+				     RBMetaDataField field,
+				     RhythmDBPropType prop)
+{
+	GValue val = { 0, };
+
+	if ((rb_metadata_get (metadata, field, &val)))
+	{
+		rhythmdb_entry_set (db, entry, prop, &val);
+		g_value_unset (&val);
+	}
+	
+	return;
+}
+
+static void
+set_metadata_string_default_unknown (RhythmDB *db,
+				     RBMetaData *metadata,
+				     RhythmDBEntry *entry,
+				     RBMetaDataField field,
+				     RhythmDBPropType prop)
+{
+	const char *unknown = "Unknown";
+	GValue val = { 0, };
+
+	if (!(rb_metadata_get (metadata, field, &val)))
+	{
+		g_value_init (&val, G_TYPE_STRING);
+		g_value_set_static_string (&val, unknown);
+	}
+	else
+	{
+                const gchar *str = g_value_get_string (&val);
+                if (str == NULL || str[0] == '\0')
+		{
+	        	g_value_set_static_string (&val, unknown);
+		}
+        }
+	rhythmdb_entry_set (db, entry, prop, &val);
+	g_value_unset (&val);
+
+	return;
+}
+
+static void
+load_metadata (RBGoearSource* self, RhythmDBEntry *entry, gchar* uri)
+{
+	RBMetaData* metadata;
+	RBGoearSourcePrivate* priv;
+	GValue val = { 0, };
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+	
+	metadata = rb_metadata_new ();
+	rb_metadata_load (metadata, uri, NULL);
+
+	/* track number */
+	if (!rb_metadata_get (metadata, RB_METADATA_FIELD_TRACK_NUMBER, &val))
+	{
+		g_value_init (&val, G_TYPE_ULONG);
+		g_value_set_ulong (&val, 0);
+	}
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_TRACK_NUMBER, &val);
+	g_value_unset (&val);
+
+	/* disc number */
+	if (!rb_metadata_get (metadata, RB_METADATA_FIELD_DISC_NUMBER, &val))
+	{
+		g_value_init (&val, G_TYPE_ULONG);
+		g_value_set_ulong (&val, 0);
+	}
+	rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_DISC_NUMBER, &val);
+	g_value_unset (&val);
+
+	/* duration */
+	if (rb_metadata_get (metadata, RB_METADATA_FIELD_DURATION, &val))
+	{
+		rhythmdb_entry_set (priv->db,
+				    entry, RHYTHMDB_PROP_DURATION, &val);
+		g_value_unset (&val);
+	}
+
+	/* bitrate */
+	if (rb_metadata_get (metadata, RB_METADATA_FIELD_BITRATE, &val))
+	{
+		rhythmdb_entry_set (priv->db, entry,
+				    RHYTHMDB_PROP_BITRATE, &val);
+		g_value_unset (&val);
+	}
+
+	/* date */
+	if (rb_metadata_get (metadata, RB_METADATA_FIELD_DATE, &val))
+	{
+		rhythmdb_entry_set (priv->db, entry, RHYTHMDB_PROP_DATE, &val);
+		g_value_unset (&val);
+	}
+
+	/* genre */
+	set_metadata_string_default_unknown (priv->db, metadata, entry,
+					     RB_METADATA_FIELD_GENRE,
+					     RHYTHMDB_PROP_GENRE);
+
+	/* artist */
+	set_metadata_string_default (priv->db, metadata, entry,
+				     RB_METADATA_FIELD_ARTIST,
+				     RHYTHMDB_PROP_ARTIST);
+	/* album */
+	set_metadata_string_default_unknown (priv->db, metadata, entry,
+					     RB_METADATA_FIELD_ALBUM,
+					     RHYTHMDB_PROP_ALBUM);
+
+	/* title */
+	set_metadata_string_default (priv->db, metadata, entry,
+				     RB_METADATA_FIELD_TITLE,
+				     RHYTHMDB_PROP_TITLE);
+
+	
+	rhythmdb_commit (priv->db);
+	
+	g_object_unref (metadata);
+	
+	return;
+}
+
+static gchar*
+get_playback_uri (RhythmDBEntry *entry, gpointer data)
+{
+	RBGoearSource* self;
+	const gchar* id;
+	gchar* mp3uri;
+
+	self = RB_GOEAR_SOURCE (data);
+
+	id = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
+	g_assert (id != NULL);
+
+	mp3uri = fetch_playback_uri (self, id);
+
+	load_metadata (self, entry, mp3uri);
+	
+	return mp3uri;
+}
+
+static RhythmDBEntryType
+get_goear_entry_type (RBShell* shell)
+{
+	RhythmDB* db;
+	RhythmDBEntryType entry_type;
+
+	g_object_get (G_OBJECT (shell), "db", &db, NULL);
+
+	entry_type = rhythmdb_entry_type_get_by_name (db, "goear-track");
+	if (entry_type == RHYTHMDB_ENTRY_TYPE_INVALID)
+	{
+		entry_type = rhythmdb_entry_register_type (db, "goear-track");
+		entry_type->save_to_disk     = FALSE;
+		entry_type->has_playlists    = FALSE;
+		entry_type->category	     = RHYTHMDB_ENTRY_NORMAL;
+		entry_type->get_playback_uri = get_playback_uri;
+	}
+
+	g_object_unref (db);
+
+	return entry_type;
+}
+
+static gboolean
+populate_browser (RBGoearSource* self,
+		  gchar* artist, gchar* title, gchar* id)
+{
+	gboolean retval;
+
+	retval = FALSE;
+	
+	if (id != NULL && artist != NULL && title != NULL)
+	{
+		RBGoearSourcePrivate* priv;
+		RhythmDBEntry *entry;
+		RhythmDBEntryType entry_type;
+		GValue value = { 0, };
+
+		priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+		g_object_get (self, "entry-type", &entry_type, NULL);
+		entry = rhythmdb_entry_new (priv->db, entry_type, id);
+		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+		if (entry != NULL)
+		{
+			/* artist */
+			g_value_init (&value, G_TYPE_STRING);
+			g_value_take_string (&value, artist);
+			rhythmdb_entry_set (priv->db, entry,
+					    RHYTHMDB_PROP_ARTIST, &value);
+			g_value_unset (&value);
+
+			/* title */
+			g_value_init (&value, G_TYPE_STRING);
+			g_value_take_string (&value, title);
+			rhythmdb_entry_set (priv->db, entry,
+					    RHYTHMDB_PROP_TITLE, &value);
+			g_value_unset (&value);
+
+			rhythmdb_query_model_add_entry (priv->model, entry, -1);
+			rhythmdb_commit (priv->db);
+
+			retval = TRUE;
+		}
+	}
+	else
+	{
+		if (artist != NULL)
+		{
+			g_free (artist);
+		}
+
+		if (artist != NULL)
+		{
+			g_free (title);
+		}
+	}
+
+	if (id != NULL)
+	{
+		g_free (id);
+	}
+
+	return retval;
+}
+
+static gboolean
+process_track_link (RBGoearSource* self, xmlNode* node)
+{
+	xmlAttrPtr attr;
+	gchar* id;
+	gchar* title;
+	gchar* artist;
+
+	id = NULL;
+	title = NULL;
+	artist = NULL;
+
+	for (attr = node->properties; attr != NULL; attr = attr->next)
+	{
+		if (xmlStrncmp (attr->name, (xmlChar*) "title", 5) == 0)
+		{
+			gchar** t;
+
+			t = g_strsplit ((gchar *) attr->children->content,
+					"-", 0);
+			if (t[0] != NULL)
+			{
+				title = g_strstrip (
+					g_utf8_normalize (t[0], -1,
+							  G_NORMALIZE_DEFAULT)
+					);
+			}
+
+			if (t[1] != NULL)
+			{
+				artist = g_strstrip (
+					g_utf8_normalize (t[1], -1,
+							  G_NORMALIZE_DEFAULT)
+					);
+			}
+
+			g_strfreev (t);
+		}
+		else if (xmlStrncmp (attr->name, (xmlChar*) "href", 4) == 0)
+		{
+			gchar *p;
+			gchar *c;
+
+			c = (gchar *) attr->children->content;
+			p = strstr (c, "=");
+
+			if (++p != NULL)
+			{
+				id = g_strstrip (g_strdup (p));
+			}
+
+			break;
+		}
+	}
+
+	return populate_browser (self, artist, title, id);
+}
+
+static gint
+rb_goear_source_get_tracks (RBGoearSource* self, xmlNode* node)
+{
+	xmlNodePtr cur;
+	gint retval;
+
+	retval = 0;
+	for (cur = node; cur != NULL; cur = cur->next)
+	{
+		if (is_track_link (cur))
+		{
+			if (process_track_link (self, cur) == TRUE)
+			{
+				retval++;
+			}
+		}
+
+		retval += rb_goear_source_get_tracks (self, cur->children);
+	}
+
+	return retval;
+}
+
+static void
+rb_goear_source_request_page (RBGoearSource* self)
+{
+	gchar* page;
+	gchar* uri;
+	RBGoearSourcePrivate* priv;
+	
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	g_return_if_fail (priv->query != NULL);
+	
+	uri = g_strconcat (RB_GOEAR_BASE_URL,
+			   "search.php?q=", priv->query, NULL);
+	page = g_strdup_printf ("%s&p=%d", uri, priv->page);
+	rb_debug ("URI to fetch = \"%s\"\n", page);
+	rb_goear_http_get (priv->wget, page);
+
+	g_free (page);
+	g_free (uri);
+
+	return;
+}
+
+static void
+rb_goear_source_parse_html (RBGoearSource* self,
+			    const gchar* content, guint length)
+{
+	xmlDocPtr doc;
+	xmlNodePtr root;
+	gint opt;
+	gint count;
+
+	opt = XML_PARSE_RECOVER |     \
+		XML_PARSE_NOERROR |   \
+		XML_PARSE_NOWARNING | \
+		XML_PARSE_NOBLANKS;
+
+	doc = xmlReadMemory (content, (int) length,
+			     "goear.html", "ISO-8859-1", opt);
+
+	if (doc == NULL)
+	{
+		rb_error_dialog (NULL, "HTML error", "Empty HTML page");
+		goto beach;
+	}
+
+	root = xmlDocGetRootElement (doc);
+
+	count = rb_goear_source_get_tracks (self, root);
+
+	if (count >= RB_GOEAR_FEED_SIZE)
+	{
+		RBGoearSourcePrivate* priv;
+	
+		priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+		priv->page++;
+		rb_goear_source_request_page (self);
+	}
+
+beach:
+	xmlFreeDoc (doc);
+	xmlCleanupParser();
+
+	return;
+}
+
+static void
+rb_goear_source_search (RBGoearSource *self, const gchar* text)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	g_return_if_fail (text != NULL);
+
+	free_query (self);
+	priv->query = normalize_query (text);
+
+	priv->page = 0;
+
+	rb_goear_source_request_page (self);
+
+	rb_source_notify_status_changed (RB_SOURCE(self));
+
+	return;
+}
+
+static void
+rb_goear_source_clean (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+	RhythmDBEntryType entry_type;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	rb_goear_http_abort (priv->wget);
+	g_object_get (self, "entry-type", &entry_type, NULL);
+	rhythmdb_entry_delete_by_type (priv->db, entry_type);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+	rhythmdb_commit (priv->db);
+
+	return;
+}
+
+static void
+rb_goear_source_set_params (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+	RhythmDBEntryType entry_type;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	/* obtain the params from shel */
+	g_object_get (self, "shell", &priv->shell, NULL);
+	g_assert (priv->shell != NULL);
+
+	g_object_get (G_OBJECT (priv->shell), "db", &priv->db, NULL);
+	g_assert (priv->db != NULL);
+
+	/* web fetcher */
+	priv->wget = instanciate_goear_http (self);
+	g_signal_connect_swapped (priv->wget, "error",
+				  G_CALLBACK (error_cb), self);
+	g_signal_connect_swapped (priv->wget, "response",
+				  G_CALLBACK (response_cb), self);
+
+	/* add the source to the entry_type */
+	entry_type = rhythmdb_entry_type_get_by_name (priv->db, "goear-track");
+	if (entry_type != RHYTHMDB_ENTRY_TYPE_INVALID)
+	{
+		entry_type->get_playback_uri_data = self;
+	}
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+	return;
+}
+
+static void
+rb_goear_source_build_browser (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+	RhythmDBEntryType entry_type;
+	GObject *player;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	g_object_get (self, "entry-type", &entry_type, NULL);
+
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+	/* songs tree view */
+	player = rb_shell_get_player (priv->shell);
+	priv->songs = rb_entry_view_new (priv->db, player, NULL, TRUE, FALSE);
+
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_TITLE, TRUE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_GENRE, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_ARTIST, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_ALBUM, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_YEAR, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_DURATION, FALSE);
+ 	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_QUALITY, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
+	rb_entry_view_append_column (priv->songs,
+				     RB_ENTRY_VIEW_COL_LOCATION, FALSE);
+
+/* 	g_signal_connect (priv->songs, "show_popup", */
+/* 			  G_CALLBACK (songs_show_popup_cb), self); */
+
+	g_signal_connect (priv->songs, "sort-order-changed",
+			  G_CALLBACK (songs_view_sort_order_changed_cb), self);
+
+	rb_goear_view_add_browser (RB_GOEAR_VIEW (priv->view),
+				   GTK_WIDGET (priv->songs));
+
+	
+	/* model */
+	priv->model = rhythmdb_query_model_new_empty (priv->db);
+	rhythmdb_do_full_query_async (priv->db,
+				      RHYTHMDB_QUERY_RESULTS (priv->model),
+				      RHYTHMDB_QUERY_PROP_EQUALS,
+				      RHYTHMDB_PROP_TYPE, entry_type,
+				      RHYTHMDB_QUERY_END);
+	
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+	rb_entry_view_set_model (priv->songs, priv->model);
+	g_object_set (self, "query-model", priv->model, NULL);
+	
+	return;
+}
+
+static void
+rb_goear_source_build_ui (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+
+	priv->view = rb_goear_view_new ();
+
+	g_signal_connect_swapped (G_OBJECT (priv->view), "search",
+				  G_CALLBACK (search_cb), self);
+
+	gtk_container_add (GTK_CONTAINER (self), priv->view);
+}
+
+static void
+rb_goear_source_dispose (GObject* object)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (object);
+
+	(*G_OBJECT_CLASS (rb_goear_source_parent_class)->dispose) (object);
+		
+	if (priv->wget != NULL)
+	{
+		g_object_unref (priv->wget);
+		priv->wget = NULL;
+	}
+
+	if (priv->songs != NULL)
+	{
+		g_object_unref (priv->songs);
+		priv->songs = NULL;
+	}
+
+	if (priv->model != NULL)
+	{
+		g_object_unref (priv->model);
+		priv->model = NULL;
+	}
+	
+	if (priv->db != NULL)
+	{
+		g_object_unref (priv->db);
+		priv->db = NULL;
+	}
+
+	if (priv->shell != NULL)
+	{
+		g_object_unref (priv->shell);
+		priv->shell = NULL;
+	}
+	
+	return;
+}
+
+static void
+rb_goear_source_finalize (GObject *object)
+{
+	free_query (RB_GOEAR_SOURCE (object));
+
+	(*G_OBJECT_CLASS (rb_goear_source_parent_class)->finalize) (object);
+
+	return;
+}
+
+static GObject*
+rb_goear_source_constructor (GType type, guint n_construct_properties,
+			     GObjectConstructParam* construct_properties)
+{
+	RBGoearSource* self;
+
+	self = RB_GOEAR_SOURCE (
+		G_OBJECT_CLASS (rb_goear_source_parent_class)->constructor (
+			type, n_construct_properties, construct_properties
+			)
+		);
+
+	rb_goear_source_set_params (self);
+	rb_goear_source_build_ui (self);
+	rb_goear_source_build_browser (self);
+
+	gtk_widget_show_all (GTK_WIDGET (self));
+
+	return G_OBJECT (self);
+}
+
+static void
+rb_goear_source_class_init (RBGoearSourceClass* klass)
+{
+	GObjectClass* object_class;
+	RBSourceClass* source_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->dispose = rb_goear_source_dispose;
+	object_class->finalize = rb_goear_source_finalize;
+	object_class->constructor = rb_goear_source_constructor;
+
+	source_class = RB_SOURCE_CLASS (klass);
+	source_class->impl_can_search = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_pause = (RBSourceFeatureFunc) rb_true_function;
+	/* source_class->impl_show_popup = impl_show_popup; */
+	source_class->impl_delete_thyself = impl_delete_thyself;
+	source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_handle_eos = impl_handle_eos;
+	source_class->impl_get_entry_view = impl_get_entry_view;
+
+	g_type_class_add_private (klass, sizeof (RBGoearSourcePrivate));
+
+	return;
+}
+
+static void
+rb_goear_source_init (RBGoearSource* self)
+{
+	RBGoearSourcePrivate* priv;
+
+	priv = RB_GOEAR_SOURCE_GET_PRIVATE (self);
+	priv->shell = NULL;
+	priv->db = NULL;
+	priv->model = NULL;
+	priv->view = NULL;
+	priv->wget = NULL;
+
+	priv->page = 0;
+	priv->query = NULL;
+
+	g_object_set (self, "name", RB_GOEAR_SOURCE_NAME, NULL);
+
+	return;
+}
+
+RBSource*
+rb_goear_source_new (RBShell* shell)
+{
+	RBSource* source;
+	RhythmDBEntryType entry_type;
+
+	entry_type = get_goear_entry_type (shell);
+
+	source = RB_SOURCE (
+		g_object_new (RB_TYPE_GOEAR_SOURCE, "shell", shell,
+			      "source-group", RB_SOURCE_GROUP_LIBRARY,
+			      "entry-type", entry_type, NULL)
+		);
+
+	rb_shell_register_entry_type_for_source (shell, source, entry_type);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+	return source;
+}
Index: plugins/goear/rb-goear-utils.c
===================================================================
--- plugins/goear/rb-goear-utils.c	(revision 0)
+++ plugins/goear/rb-goear-utils.c	(revision 0)
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * rb-goear-utils.c
+ *
+ * Copyright (C) 2008 - Victor Manuel Jaquez  Leal <vjaquez@igalia.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "rb-goear-utils.h"
+
+#include <libxml/parser.h>
+#include <libsoup/soup.h>
+
+gchar*
+get_stream_uri (xmlNode* node)
+{
+	xmlNodePtr cur;
+	gchar* uri = NULL;
+
+	for (cur = node; cur != NULL; cur = cur->next)
+	{
+		if ((cur->type == XML_ELEMENT_NODE) &&
+		    (xmlStrncmp (cur->name, (xmlChar*) "song", 5) == 0))
+		{
+			xmlAttrPtr attr;
+
+			for (attr = node->properties;
+			     attr != NULL; attr = attr->next)
+			{
+				if (xmlStrncmp (attr->name,
+						(xmlChar*) "path", 4) == 0)
+				{
+					gchar *c;
+
+					c = (gchar*) attr->children->content;
+					uri = g_strstrip (g_strdup (c));
+
+					return uri;
+				}
+			}
+		}
+
+		uri = get_stream_uri (cur->children);
+
+		if (uri != NULL)
+		{
+			return uri;
+		}
+	}
+
+	return NULL;
+}
+
+gchar*
+parse_xml (const gchar* content, guint length)
+{
+	xmlDocPtr doc;
+	xmlNodePtr root;
+	gint opt;
+	gchar* mp3uri;
+
+	mp3uri = NULL;
+
+	opt = XML_PARSE_NOENT |	      \
+		XML_PARSE_RECOVER |   \
+		XML_PARSE_NOERROR |   \
+		XML_PARSE_NOWARNING | \
+		XML_PARSE_NOBLANKS;
+
+	doc = xmlReadMemory (content, (int) length, "goear.xml", NULL, opt);
+
+	if (doc != NULL)
+	{
+		root = xmlDocGetRootElement (doc);
+		mp3uri = get_stream_uri (root);
+	}
+
+	xmlFreeDoc (doc);
+	xmlCleanupParser();
+
+	return mp3uri;
+}
+
+gboolean
+is_track_link (xmlNode* node)
+{
+	xmlAttrPtr attr;
+
+	if (node->type != XML_ELEMENT_NODE)
+	{
+		goto beach;
+	}
+
+	if (xmlStrncmp (node->name, (xmlChar*) "a", 1) != 0)
+	{
+		goto beach;
+	}
+
+	for (attr = node->properties; attr != NULL; attr = attr->next)
+	{
+		if ((xmlStrncmp (attr->name, (xmlChar*) "class", 5) == 0) &&
+		    (xmlStrncmp (attr->children->content,
+				 (xmlChar*) RB_GOEAR_LINK_CLASS, 8) == 0))
+		{
+			return TRUE;
+		}
+	}
+
+beach:
+	return FALSE;
+}
+
+gchar*
+normalize_query (const gchar* text)
+{
+	GRegex* regex;
+	gchar* query;
+	gchar* q;
+	gchar* retval;
+
+	q = g_strstrip (g_strdup (text));
+
+	regex = g_regex_new ("\\s+", 0, 0, NULL);
+	if (regex != NULL)
+	{
+		query = g_regex_replace (regex, q, -1, 0, "+", 0, NULL);
+
+		if (query == NULL)
+		{
+			query = q;
+		}
+		else
+		{
+			g_free (q);
+		}
+
+		g_regex_unref (regex);
+	}
+	else
+	{
+		query = q; /* good luck my friend */
+	}
+
+	retval = soup_uri_encode (query, NULL);
+	g_free (query);
+
+	return retval;
+}
Index: plugins/Makefile.am
===================================================================
--- plugins/Makefile.am	(revision 5862)
+++ plugins/Makefile.am	(working copy)
@@ -10,7 +10,9 @@
 	visualizer
 
 if WITH_AUDIOSCROBBLER
-SUBDIRS += audioscrobbler
+SUBDIRS +=					\ 
+	audioscrobbler				\
+	goear
 endif
 
 if WITH_LIRC
