[grilo-plugins] shoutcast: Move SHOUTCast 2.0 API



commit dd4235a93abb26f240317e381d563bd6d7a2adda
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Tue Dec 13 15:19:38 2011 +0000

    shoutcast: Move SHOUTCast 2.0 API
    
    Previous API was unavailable, so we have moved to use the new API 2.0.
    
    In order to use this plugin, a "dev-key" must be provided.
    
    See SHOUTCast webpage for more details.
    
    Signed-off-by: Juan A. Suarez Romero <jasuarez igalia com>

 src/media/shoutcast/grl-shoutcast.c |  172 ++++++++++++++++++++++++++---------
 src/media/shoutcast/grl-shoutcast.h |    3 +-
 2 files changed, 130 insertions(+), 45 deletions(-)
---
diff --git a/src/media/shoutcast/grl-shoutcast.c b/src/media/shoutcast/grl-shoutcast.c
index 57b2240..35776e2 100644
--- a/src/media/shoutcast/grl-shoutcast.c
+++ b/src/media/shoutcast/grl-shoutcast.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2010, 2011 Igalia S.L.
  *
  * Contact: Iago Toral Quiroga <itoral igalia com>
  *
@@ -33,8 +33,15 @@
 
 #include "grl-shoutcast.h"
 
+#define GRL_SHOUTCAST_SOURCE_GET_PRIVATE(object)            \
+  (G_TYPE_INSTANCE_GET_PRIVATE((object),                    \
+                               GRL_SHOUTCAST_SOURCE_TYPE,   \
+                               GrlShoutcastSourcePriv))
+
 #define EXPIRE_CACHE_TIMEOUT 300
 
+#define SHOUTCAST_DEV_KEY "dev-key"
+
 /* --------- Logging  -------- */
 
 #define GRL_LOG_DOMAIN_DEFAULT shoutcast_log_domain
@@ -42,12 +49,13 @@ GRL_LOG_DOMAIN_STATIC(shoutcast_log_domain);
 
 /* ------ SHOUTcast API ------ */
 
-#define SHOUTCAST_BASE_ENTRY "http://yp.shoutcast.com";
+#define SHOUTCAST_API_BASE_ENTRY "http://api.shoutcast.com/legacy/";
+#define SHOUTCAST_YP_BASE_ENTRY  "http://yp.shoutcast.com/sbin/";
 
-#define SHOUTCAST_GET_GENRES    SHOUTCAST_BASE_ENTRY "/sbin/newxml.phtml"
-#define SHOUTCAST_GET_RADIOS    SHOUTCAST_GET_GENRES "?genre=%s&limit=%u"
-#define SHOUTCAST_SEARCH_RADIOS SHOUTCAST_GET_GENRES "?search=%s&limit=%u"
-#define SHOUTCAST_TUNE          SHOUTCAST_BASE_ENTRY "/sbin/tunein-station.pls?id=%s"
+#define SHOUTCAST_GET_GENRES    SHOUTCAST_API_BASE_ENTRY "genrelist?k=%s"
+#define SHOUTCAST_GET_RADIOS    SHOUTCAST_API_BASE_ENTRY "genresearch?k=%s&genre=%s&limit=%u"
+#define SHOUTCAST_SEARCH_RADIOS SHOUTCAST_API_BASE_ENTRY "stationsearch?k=%s&search=%s&limit=%u"
+#define SHOUTCAST_TUNE          SHOUTCAST_YP_BASE_ENTRY  "tunein-station.pls?id=%s"
 
 /* --- Plugin information --- */
 
@@ -57,6 +65,14 @@ GRL_LOG_DOMAIN_STATIC(shoutcast_log_domain);
 #define SOURCE_NAME "SHOUTcast"
 #define SOURCE_DESC "A source for browsing SHOUTcast radios"
 
+struct _GrlShoutcastSourcePriv {
+  gchar *dev_key;
+  GrlNetWc *wc;
+  GCancellable *cancellable;
+  gchar *cached_page;
+  gboolean cached_page_expired;
+};
+
 typedef struct {
   GrlMedia *media;
   GrlMediaSource *source;
@@ -76,12 +92,7 @@ typedef struct {
   xmlNodePtr xml_entries;
 } OperationData;
 
-static GrlNetWc *wc = NULL;
-static GCancellable *cancellable;
-static gchar *cached_page = NULL;
-static gboolean cached_page_expired = TRUE;
-
-static GrlShoutcastSource *grl_shoutcast_source_new (void);
+static GrlShoutcastSource *grl_shoutcast_source_new (const gchar *dev_key);
 
 gboolean grl_shoutcast_plugin_init (GrlPluginRegistry *registry,
                                     const GrlPluginInfo *plugin,
@@ -101,7 +112,9 @@ static void grl_shoutcast_source_search (GrlMediaSource *source,
 static void grl_shoutcast_source_cancel (GrlMetadataSource *source,
                                          guint operation_id);
 
-static void read_url_async (const gchar *url, OperationData *op_data);
+static void read_url_async (GrlShoutcastSource *source,
+                            const gchar *url,
+                            OperationData *op_data);
 
 static void grl_shoutcast_source_finalize (GObject *object);
 
@@ -112,15 +125,40 @@ grl_shoutcast_plugin_init (GrlPluginRegistry *registry,
                            const GrlPluginInfo *plugin,
                            GList *configs)
 {
+  gchar *dev_key;
+  GrlConfig *config;
+  gint config_count;
+  GrlShoutcastSource *source;
+
   GRL_LOG_DOMAIN_INIT (shoutcast_log_domain, "shoutcast");
 
   GRL_DEBUG ("shoutcast_plugin_init");
 
-  GrlShoutcastSource *source = grl_shoutcast_source_new ();
+  if (!configs) {
+    GRL_INFO ("Configuration not provided! Plugin not loaded");
+    return FALSE;
+  }
+
+  config_count = g_list_length (configs);
+  if (config_count > 1) {
+    GRL_INFO ("Provided %d configs, but will only use one", config_count);
+  }
+
+  config = GRL_CONFIG (configs->data);
+  dev_key = grl_config_get_string (config, SHOUTCAST_DEV_KEY);
+  if (!dev_key) {
+    GRL_INFO ("Missin API Dev Key, cannot load plugin");
+    return FALSE;
+  }
+
+  source = grl_shoutcast_source_new (dev_key);
   grl_plugin_registry_register_source (registry,
                                        plugin,
                                        GRL_MEDIA_PLUGIN (source),
                                        NULL);
+
+  g_free (dev_key);
+
   return TRUE;
 }
 
@@ -131,14 +169,21 @@ GRL_PLUGIN_REGISTER (grl_shoutcast_plugin_init,
 /* ================== SHOUTcast GObject ================ */
 
 static GrlShoutcastSource *
-grl_shoutcast_source_new (void)
+grl_shoutcast_source_new (const gchar *dev_key)
 {
+  GrlShoutcastSource *source;
+
   GRL_DEBUG ("grl_shoutcast_source_new");
-  return g_object_new (GRL_SHOUTCAST_SOURCE_TYPE,
-		       "source-id", SOURCE_ID,
-		       "source-name", SOURCE_NAME,
-		       "source-desc", SOURCE_DESC,
-		       NULL);
+
+  source =  g_object_new (GRL_SHOUTCAST_SOURCE_TYPE,
+                          "source-id", SOURCE_ID,
+                          "source-name", SOURCE_NAME,
+                          "source-desc", SOURCE_DESC,
+                          NULL);
+
+  source->priv->dev_key = g_strdup (dev_key);
+
+  return source;
 }
 
 static void
@@ -147,17 +192,24 @@ grl_shoutcast_source_class_init (GrlShoutcastSourceClass * klass)
   GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass);
   GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
   source_class->metadata = grl_shoutcast_source_metadata;
   source_class->browse = grl_shoutcast_source_browse;
   source_class->search = grl_shoutcast_source_search;
+
   metadata_class->cancel = grl_shoutcast_source_cancel;
   metadata_class->supported_keys = grl_shoutcast_source_supported_keys;
+
   gobject_class->finalize = grl_shoutcast_source_finalize;
+
+  g_type_class_add_private (klass, sizeof (GrlShoutcastSourcePriv));
 }
 
 static void
 grl_shoutcast_source_init (GrlShoutcastSource *source)
 {
+  source->priv = GRL_SHOUTCAST_SOURCE_GET_PRIVATE (source);
+  source->priv->cached_page_expired = TRUE;
 }
 
 G_DEFINE_TYPE (GrlShoutcastSource, grl_shoutcast_source, GRL_TYPE_MEDIA_SOURCE);
@@ -165,11 +217,22 @@ G_DEFINE_TYPE (GrlShoutcastSource, grl_shoutcast_source, GRL_TYPE_MEDIA_SOURCE);
 static void
 grl_shoutcast_source_finalize (GObject *object)
 {
-  if (wc && GRL_IS_NET_WC (wc))
-    g_object_unref (wc);
+  GrlShoutcastSource *self = GRL_SHOUTCAST_SOURCE (object);
+
+  if (self->priv->wc && GRL_IS_NET_WC (self->priv->wc))
+    g_object_unref (self->priv->wc);
 
-  if (cancellable && G_IS_CANCELLABLE (cancellable))
-    g_cancellable_cancel (cancellable);
+  if (self->priv->cancellable && G_IS_CANCELLABLE (self->priv->cancellable))
+    g_cancellable_cancel (self->priv->cancellable);
+
+  if (self->priv->cached_page) {
+    g_free (self->priv->cached_page);
+    self->priv->cached_page = NULL;
+  }
+
+  if (self->priv->dev_key) {
+    g_free (self->priv->dev_key);
+  }
 
   G_OBJECT_CLASS (grl_shoutcast_source_parent_class)->finalize (object);
 }
@@ -469,8 +532,10 @@ xml_parse_result (const gchar *str, OperationData *op_data)
 static gboolean
 expire_cache (gpointer user_data)
 {
+  GrlShoutcastSource *source = GRL_SHOUTCAST_SOURCE (user_data);
+
   GRL_DEBUG ("Cached page expired");
-  cached_page_expired = TRUE;
+  source->priv->cached_page_expired = TRUE;
   return FALSE;
 }
 
@@ -482,6 +547,7 @@ read_done_cb (GObject *source_object,
   GError *error = NULL;
   GError *wc_error = NULL;
   OperationData *op_data = (OperationData *) user_data;
+  GrlShoutcastSource *source = GRL_SHOUTCAST_SOURCE (op_data->source);
   gboolean cache;
   gchar *content = NULL;
 
@@ -509,34 +575,39 @@ read_done_cb (GObject *source_object,
 
   cache = op_data->cache;
   xml_parse_result (content, op_data);
-  if (cache && cached_page_expired) {
+  if (cache && source->priv->cached_page_expired) {
     GRL_DEBUG ("Caching page");
-    g_free (cached_page);
-    cached_page = g_strdup (content);
-    cached_page_expired = FALSE;
-    g_timeout_add_seconds (EXPIRE_CACHE_TIMEOUT, expire_cache, NULL);
+    g_free (source->priv->cached_page);
+    source->priv->cached_page = g_strdup (content);
+    source->priv->cached_page_expired = FALSE;
+    g_timeout_add_seconds (EXPIRE_CACHE_TIMEOUT, expire_cache, source);
   }
 }
 
 static gboolean
 read_cached_page (OperationData *op_data)
 {
+  gchar *cached_page = GRL_SHOUTCAST_SOURCE (op_data->source)->priv->cached_page;
   xml_parse_result (cached_page, op_data);
   return FALSE;
 }
 
 static void
-read_url_async (const gchar *url, OperationData *op_data)
+read_url_async (GrlShoutcastSource *source,
+                const gchar *url,
+                OperationData *op_data)
 {
-  if (op_data->cache && !cached_page_expired) {
+  if (op_data->cache && !source->priv->cached_page_expired) {
     GRL_DEBUG ("Using cached page");
     g_idle_add ((GSourceFunc) read_cached_page, op_data);
   } else {
-    if (!wc)
-      wc = grl_net_wc_new ();
+    if (!source->priv->wc)
+      source->priv->wc = grl_net_wc_new ();
 
-    cancellable = g_cancellable_new ();
-    grl_net_wc_request_async (wc, url, cancellable, read_done_cb, op_data);
+    source->priv->cancellable = g_cancellable_new ();
+    grl_net_wc_request_async (source->priv->wc, url,
+                              source->priv->cancellable,
+                              read_done_cb, op_data);
   }
 }
 
@@ -566,6 +637,7 @@ grl_shoutcast_source_metadata (GrlMediaSource *source,
   gchar **id_tokens;
   gchar *url = NULL;
   OperationData *data = NULL;
+  GrlShoutcastSource *shoutcast_source = GRL_SHOUTCAST_SOURCE (source);
 
   /* Unfortunately, shoutcast does not have an API to get information about a
      station.  Thus, steps done to obtain the Content must be repeated. For
@@ -598,24 +670,27 @@ grl_shoutcast_source_metadata (GrlMediaSource *source,
       /* Check if result is from a previous search */
       if (id_tokens[0][0] == '?') {
         url = g_strdup_printf (SHOUTCAST_SEARCH_RADIOS,
+                               shoutcast_source->priv->dev_key,
                                id_tokens[0]+1,
                                G_MAXINT);
       } else {
         url = g_strdup_printf (SHOUTCAST_GET_RADIOS,
+                               shoutcast_source->priv->dev_key,
                                id_tokens[0],
                                G_MAXINT);
       }
     } else {
       data->filter_entry = g_strdup (id_tokens[0]);
       data->cache = TRUE;
-      url = g_strdup (SHOUTCAST_GET_GENRES);
+      url = g_strdup_printf (SHOUTCAST_GET_GENRES,
+                             shoutcast_source->priv->dev_key);
     }
 
     g_strfreev (id_tokens);
   }
 
   if (url) {
-    read_url_async (url, data);
+    read_url_async (shoutcast_source, url, data);
     g_free (url);
   } else {
     ms->callback (ms->source, ms->metadata_id, ms->media, ms->user_data, NULL);
@@ -629,6 +704,7 @@ grl_shoutcast_source_browse (GrlMediaSource *source,
   OperationData *data;
   const gchar *container_id;
   gchar *url;
+  GrlShoutcastSource *shoutcast_source = GRL_SHOUTCAST_SOURCE (source);
 
   GRL_DEBUG ("grl_shoutcast_source_browse");
 
@@ -646,9 +722,11 @@ grl_shoutcast_source_browse (GrlMediaSource *source,
   /* If it's root category send list of genres; else send list of radios */
   if (!container_id) {
     data->cache = TRUE;
-    url = g_strdup (SHOUTCAST_GET_GENRES);
+    url = g_strdup_printf (SHOUTCAST_GET_GENRES,
+                           shoutcast_source->priv->dev_key);
   } else {
     url = g_strdup_printf (SHOUTCAST_GET_RADIOS,
+                           shoutcast_source->priv->dev_key,
                            container_id,
                            bs->skip + bs->count);
     data->genre = g_strdup (container_id);
@@ -656,7 +734,7 @@ grl_shoutcast_source_browse (GrlMediaSource *source,
 
   grl_operation_set_data (bs->browse_id, data);
 
-  read_url_async (url, data);
+  read_url_async (shoutcast_source, url, data);
 
   g_free (url);
 }
@@ -668,6 +746,7 @@ grl_shoutcast_source_search (GrlMediaSource *source,
   GError *error;
   OperationData *data;
   gchar *url;
+  GrlShoutcastSource *shoutcast_source = GRL_SHOUTCAST_SOURCE (source);
 
   /* Check if there is text to search */
   if (!ss->text || ss->text[0] == '\0') {
@@ -697,10 +776,11 @@ grl_shoutcast_source_search (GrlMediaSource *source,
   grl_operation_set_data (ss->search_id, data);
 
   url = g_strdup_printf (SHOUTCAST_SEARCH_RADIOS,
+                         shoutcast_source->priv->dev_key,
                          ss->text,
                          ss->skip + ss->count);
 
-  read_url_async (url, data);
+  read_url_async (GRL_SHOUTCAST_SOURCE (source), url, data);
 
   g_free (url);
 }
@@ -709,12 +789,16 @@ static void
 grl_shoutcast_source_cancel (GrlMetadataSource *source, guint operation_id)
 {
   OperationData *op_data;
+  GrlShoutcastSourcePriv *priv;
 
   GRL_DEBUG ("grl_shoutcast_source_cancel");
 
-  if (cancellable && G_IS_CANCELLABLE (cancellable))
-    g_cancellable_cancel (cancellable);
-  cancellable = NULL;
+  priv = GRL_SHOUTCAST_SOURCE_GET_PRIVATE (source);
+
+  if (priv->cancellable && G_IS_CANCELLABLE (priv->cancellable)) {
+    g_cancellable_cancel (priv->cancellable);
+  }
+  priv->cancellable = NULL;
 
   op_data = (OperationData *) grl_operation_get_data (operation_id);
 
diff --git a/src/media/shoutcast/grl-shoutcast.h b/src/media/shoutcast/grl-shoutcast.h
index 741fac0..0672fa0 100644
--- a/src/media/shoutcast/grl-shoutcast.h
+++ b/src/media/shoutcast/grl-shoutcast.h
@@ -54,11 +54,12 @@
                               GrlShoutcastSourceClass))
 
 typedef struct _GrlShoutcastSource GrlShoutcastSource;
+typedef struct _GrlShoutcastSourcePriv GrlShoutcastSourcePriv;
 
 struct _GrlShoutcastSource {
 
   GrlMediaSource parent;
-
+  GrlShoutcastSourcePriv *priv;
 };
 
 typedef struct _GrlShoutcastSourceClass GrlShoutcastSourceClass;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]