[grilo-plugins] [youtube] Started development of a new version based on libgdata.



commit 393be8335686da48000fbadf78e5a5e9129c11da
Author: Iago Toral Quiroga <itoral igalia com>
Date:   Tue Apr 13 15:48:31 2010 +0200

    [youtube] Started development of a new version based on libgdata.

 src/youtube/grl-youtube.c | 1296 +++++++--------------------------------------
 src/youtube/grl-youtube.h |    2 +
 2 files changed, 182 insertions(+), 1116 deletions(-)
---
diff --git a/src/youtube/grl-youtube.c b/src/youtube/grl-youtube.c
index b8f27f0..d2f9548 100644
--- a/src/youtube/grl-youtube.c
+++ b/src/youtube/grl-youtube.c
@@ -26,10 +26,8 @@
 
 #include <grilo.h>
 #include <gio/gio.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
+#include <gdata/gdata.h>
 #include <string.h>
-#include <stdlib.h>
 
 #include "grl-youtube.h"
 
@@ -44,7 +42,6 @@
 
 #define YOUTUBE_FEEDS_ID        "standard-feeds"
 #define YOUTUBE_FEEDS_NAME      "Standard feeds"
-#define YOUTUBE_FEEDS_URL       NULL
 
 #define YOUTUBE_CATEGORIES_ID   "categories"
 #define YOUTUBE_CATEGORIES_NAME "Categories"
@@ -54,47 +51,32 @@
 
 #define YOUTUBE_VIEWED_ID       (YOUTUBE_FEEDS_ID "/most-viewed")
 #define YOUTUBE_VIEWED_NAME     "Most viewed"
-#define YOUTUBE_VIEWED_URL      "http://gdata.youtube.com/feeds/standardfeeds/most_viewed?start-index=%d&max-results=%d";
 
 #define YOUTUBE_RATED_ID        (YOUTUBE_FEEDS_ID "/most-rated")
 #define YOUTUBE_RATED_NAME      "Most rated"
-#define YOUTUBE_RATED_URL       "http://gdata.youtube.com/feeds/standardfeeds/top_rated?start-index=%d&max-results=%d";
 
 #define YOUTUBE_FAVS_ID         (YOUTUBE_FEEDS_ID "/top-favs")
 #define YOUTUBE_FAVS_NAME       "Top favorites"
-#define YOUTUBE_FAVS_URL        "http://gdata.youtube.com/feeds/standardfeeds/top_favorites?start-index=%d&max-results=%d";
 
 #define YOUTUBE_RECENT_ID       (YOUTUBE_FEEDS_ID "/most-recent")
 #define YOUTUBE_RECENT_NAME     "Most recent"
-#define YOUTUBE_RECENT_URL      "http://gdata.youtube.com/feeds/standardfeeds/most_recent?start-index=%d&max-results=%d";
 
 #define YOUTUBE_DISCUSSED_ID    (YOUTUBE_FEEDS_ID "/most-discussed")
 #define YOUTUBE_DISCUSSED_NAME  "Most discussed"
-#define YOUTUBE_DISCUSSED_URL   "http://gdata.youtube.com/feeds/standardfeeds/most_discussed?start-index=%d&max-results=%d";
 
 #define YOUTUBE_FEATURED_ID     (YOUTUBE_FEEDS_ID "/featured")
 #define YOUTUBE_FEATURED_NAME   "Featured"
-#define YOUTUBE_FEATURED_URL    "http://gdata.youtube.com/feeds/standardfeeds/recently_featured?start-index=%d&max-results=%d";
 
 #define YOUTUBE_MOBILE_ID       (YOUTUBE_FEEDS_ID "/mobile")
 #define YOUTUBE_MOBILE_NAME     "Watch on mobile"
-#define YOUTUBE_MOBILE_URL      "http://gdata.youtube.com/feeds/standardfeeds/watch_on_mobile?start-index=%d&max-results=%d";
 
-/* ----- Other Youtube URLs ---- */
+/* --- Other --- */
+
+#define YOUTUBE_MAX_CHUNK   50
 
 #define YOUTUBE_VIDEO_INFO_URL  "http://www.youtube.com/get_video_info?video_id=%s";
 #define YOUTUBE_VIDEO_URL       "http://www.youtube.com/get_video?video_id=%s&t=%s";
-#define YOUTUBE_SEARCH_URL      "http://gdata.youtube.com/feeds/api/videos?vq=%s&start-index=%s&max-results=%s";
-#define YOUTUBE_CATEGORY_URL    "http://gdata.youtube.com/feeds/api/videos/-/%s?&start-index=%s&max-results=%s";
-
-/* --- Youtube parsing hints ---- */
-
-#define YOUTUBE_TOTAL_RESULTS_START "<openSearch:totalResults>"
-#define YOUTUBE_TOTAL_RESULTS_END   "</openSearch:totalResults>"
-
-/* --- Other --- */
 
-#define YOUTUBE_MAX_CHUNK   50
 #define YOUTUBE_VIDEO_MIME  "application/x-shockwave-flash"
 #define YOUTUBE_SITE_URL    "www.youtube.com"
 
@@ -117,18 +99,6 @@
 typedef void (*AsyncReadCbFunc) (gchar *data, gpointer user_data);
 
 typedef struct {
-  gchar *id;
-  gchar *title;
-  gchar *published;
-  gchar *author;
-  gchar *thumbnail;
-  gchar *description;
-  gchar *duration;
-  gchar *rating;
-  gboolean restricted;
-} Entry;
-
-typedef struct {
   GrlMediaSource *source;
   guint operation_id;
   const gchar *container_id;
@@ -136,47 +106,13 @@ typedef struct {
   GrlMetadataResolutionFlags flags;
   guint skip;
   guint count;
-  gboolean chained_chunk;
-  gchar *query_url;
-  gboolean cancelled;
   GrlMediaSourceResultCb callback;
   gpointer user_data;
+  const GDataYouTubeService *service;
+  guint error_code;
+  GDataQuery *query;
 } OperationSpec;
 
-typedef struct {
-  GrlMetadataSource *source;
-  const GList *keys;
-  GrlMediaSourceMetadataCb callback;
-  gpointer user_data;
-} MetadataOperationSpec;
-
-typedef struct {
-  OperationSpec *os;
-  xmlNodePtr node;
-  xmlDocPtr doc;
-  guint count;
-} ParseEntriesIdle;
-
-typedef struct {
-  gchar *id;
-  gchar *name;
-  gchar *url;
-} CategoryInfo;
-
-typedef struct {
-  AsyncReadCbFunc callback;
-  gchar *url;
-  gpointer user_data;
-} AsyncReadCb;
-
-typedef struct {
-  OperationSpec *os;
-  CategoryInfo *directory;
-  guint index;
-  guint remaining;
-  gboolean set_childcount;
-} ProduceFromDirectoryIdle;
-
 typedef enum {
   YOUTUBE_MEDIA_TYPE_ROOT,
   YOUTUBE_MEDIA_TYPE_FEEDS,
@@ -186,6 +122,10 @@ typedef enum {
   YOUTUBE_MEDIA_TYPE_VIDEO,
 } YoutubeMediaType;
 
+#define YOUTUBE_DEVELOPER_KEY "AI39si4EfscPllSfUy1IwexMf__kntTL_G5dfSr2iUEVN45RHGq92Aq0lX25OlnOkG6KTN-4soVAkAf67fWYXuHfVADZYr7S1A"
+#define YOUTUBE_CLIENT_ID "test-client"
+
+
 static GrlYoutubeSource *grl_youtube_source_new (void);
 
 gboolean grl_youtube_plugin_init (GrlPluginRegistry *registry,
@@ -196,47 +136,14 @@ static const GList *grl_youtube_source_supported_keys (GrlMetadataSource *source
 
 static const GList *grl_youtube_source_slow_keys (GrlMetadataSource *source);
 
-static void grl_youtube_source_metadata (GrlMediaSource *source,
-                                         GrlMediaSourceMetadataSpec *ms);
-
 static void grl_youtube_source_search (GrlMediaSource *source,
                                        GrlMediaSourceSearchSpec *ss);
 
-static void grl_youtube_source_browse (GrlMediaSource *source,
-                                       GrlMediaSourceBrowseSpec *bs);
-
-static void grl_youtube_source_cancel (GrlMediaSource *source,
-                                       guint operation_id);
-
-static gchar *read_url (const gchar *url);
-
-static void build_categories_directory (void);
-
-static void produce_next_video_chunk (OperationSpec *os);
+static void grl_youtube_source_metadata (GrlMediaSource *source,
+                                         GrlMediaSourceMetadataSpec *ms);
 
 /* ==================== Global Data  ================= */
 
-guint root_dir_size = 2;
-CategoryInfo root_dir[] = {
-  {YOUTUBE_FEEDS_ID, YOUTUBE_FEEDS_NAME, YOUTUBE_FEEDS_URL},
-  {YOUTUBE_CATEGORIES_ID, YOUTUBE_CATEGORIES_NAME, YOUTUBE_CATEGORIES_URL},
-  {NULL, NULL, NULL}
-};
-
-guint feeds_dir_size = 7;
-CategoryInfo feeds_dir[] = {
-  {YOUTUBE_VIEWED_ID, YOUTUBE_VIEWED_NAME, YOUTUBE_VIEWED_URL},
-  {YOUTUBE_RATED_ID, YOUTUBE_RATED_NAME, YOUTUBE_RATED_URL},
-  {YOUTUBE_FAVS_ID, YOUTUBE_FAVS_NAME, YOUTUBE_FAVS_URL},
-  {YOUTUBE_RECENT_ID, YOUTUBE_RECENT_NAME, YOUTUBE_RECENT_URL},
-  {YOUTUBE_DISCUSSED_ID, YOUTUBE_DISCUSSED_NAME, YOUTUBE_DISCUSSED_URL},
-  {YOUTUBE_FEATURED_ID, YOUTUBE_FEATURED_NAME, YOUTUBE_FEATURED_URL},
-  {YOUTUBE_MOBILE_ID, YOUTUBE_MOBILE_NAME, YOUTUBE_MOBILE_URL},
-  {NULL, NULL, NULL}
-};
-
-guint categories_dir_size = 0;
-CategoryInfo *categories_dir = NULL;
 
 /* =================== Youtube Plugin  =============== */
 
@@ -247,6 +154,11 @@ grl_youtube_plugin_init (GrlPluginRegistry *registry,
 {
   g_debug ("youtube_plugin_init\n");
 
+  /* libgdata needs this */
+  if (!g_thread_supported()) {
+    g_thread_init (NULL);
+  }
+
   GrlYoutubeSource *source = grl_youtube_source_new ();
   grl_plugin_registry_register_source (registry,
                                        plugin,
@@ -270,11 +182,27 @@ static GrlYoutubeSource *
 grl_youtube_source_new (void)
 {
   g_debug ("grl_youtube_source_new");
-  return g_object_new (GRL_YOUTUBE_SOURCE_TYPE,
-		       "source-id", SOURCE_ID,
-		       "source-name", SOURCE_NAME,
-		       "source-desc", SOURCE_DESC,
-		       NULL);
+
+  GrlYoutubeSource *source;
+
+  GDataYouTubeService *service =
+    gdata_youtube_service_new (YOUTUBE_DEVELOPER_KEY, YOUTUBE_CLIENT_ID);
+  
+  if (!service) {
+    g_warning ("Failed to connect to Youtube");
+    return NULL;
+  }
+
+  source = GRL_YOUTUBE_SOURCE (g_object_new (GRL_YOUTUBE_SOURCE_TYPE,
+					     "source-id", SOURCE_ID,
+					     "source-name", SOURCE_NAME,
+					     "source-desc", SOURCE_DESC,
+					     "auto-split-threshold",
+					     YOUTUBE_MAX_CHUNK,
+					     NULL));
+  source->service = service;
+
+  return source;
 }
 
 static void
@@ -282,9 +210,7 @@ grl_youtube_source_class_init (GrlYoutubeSourceClass * klass)
 {
   GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass);
   GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass);
-  source_class->browse = grl_youtube_source_browse;
   source_class->search = grl_youtube_source_search;
-  source_class->cancel = grl_youtube_source_cancel;
   source_class->metadata = grl_youtube_source_metadata;
   metadata_class->supported_keys = grl_youtube_source_supported_keys;
   metadata_class->slow_keys = grl_youtube_source_slow_keys;
@@ -293,9 +219,6 @@ grl_youtube_source_class_init (GrlYoutubeSourceClass * klass)
 static void
 grl_youtube_source_init (GrlYoutubeSource *source)
 {
-  if (!categories_dir) {
-    build_categories_directory ();
-  }
 }
 
 G_DEFINE_TYPE (GrlYoutubeSource, grl_youtube_source, GRL_TYPE_MEDIA_SOURCE);
@@ -303,38 +226,34 @@ G_DEFINE_TYPE (GrlYoutubeSource, grl_youtube_source, GRL_TYPE_MEDIA_SOURCE);
 /* ======================= Utilities ==================== */
 
 static void
-print_entry (Entry *entry)
+free_operation_spec (OperationSpec *os)
 {
-  g_print ("Entry Information:\n");
-  g_print ("            ID: %s (%d)\n", entry->id, entry->restricted);
-  g_print ("         Title: %s\n", entry->title);
-  g_print ("          Date: %s\n", entry->published);
-  g_print ("        Author: %s\n", entry->author);
-  g_print ("      Duration: %s\n", entry->duration);
-  g_print ("     Thumbnail: %s\n", entry->thumbnail);
-  g_print ("        Rating: %s\n", entry->rating);
-  g_print ("   Description: %s\n", entry->description);
+  if (os->query) {
+    g_object_unref (os->query);
+  }
+  g_free (os);
 }
 
-static void
-free_entry (Entry *entry)
+static gchar *
+read_url (const gchar *url)
 {
-  g_free (entry->id);
-  g_free (entry->title);
-  g_free (entry->published);
-  g_free (entry->author);
-  g_free (entry->duration);
-  g_free (entry->thumbnail);
-  g_free (entry->description);
-  g_free (entry->rating);
-  g_free (entry);
-}
+  GVfs *vfs;
+  GFile *uri;
+  GError *vfs_error = NULL;
+  gchar *content = NULL;
 
-static void
-free_operation_spec (OperationSpec *os)
-{
-  g_free (os->query_url);
-  g_free (os);
+  vfs = g_vfs_get_default ();
+
+  g_debug ("Opening '%s'", url);
+  uri = g_vfs_get_file_for_uri (vfs, url);
+  g_file_load_contents (uri, NULL, &content, NULL, NULL, &vfs_error);
+  g_object_unref (uri);
+  if (vfs_error) {
+    g_warning ("Failed reading '%s': %s", url, vfs_error->message);
+    return NULL;
+  } else {
+    return content;
+  }
 }
 
 static gchar *
@@ -371,81 +290,13 @@ get_video_url (const gchar *id)
   return url;
 }
 
-static void
-read_done_cb (GObject *source_object,
-              GAsyncResult *res,
-              gpointer user_data)
-{
-  AsyncReadCb *arc = (AsyncReadCb *) user_data;
-  GError *vfs_error = NULL;
-  gchar *content = NULL;
-
-  g_file_load_contents_finish (G_FILE (source_object),
-                               res,
-                               &content,
-                               NULL,
-                               NULL,
-                               &vfs_error);
-  g_object_unref (source_object);
-  if (vfs_error) {
-    g_warning ("Failed to open '%s': %s", arc->url, vfs_error->message);
-  } else {
-    arc->callback (content, arc->user_data);
-  }
-  g_free (arc->url);
-  g_free (arc);
-}
-
-static void
-read_url_async (const gchar *url,
-                AsyncReadCbFunc callback,
-                gpointer user_data)
-{
-  GVfs *vfs;
-  GFile *uri;
-  AsyncReadCb *arc;
-
-  vfs = g_vfs_get_default ();
-
-  g_debug ("Opening async '%s'", url);
-
-  arc = g_new0 (AsyncReadCb, 1);
-  arc->url = g_strdup (url);
-  arc->callback = callback;
-  arc->user_data = user_data;
-  uri = g_vfs_get_file_for_uri (vfs, url);
-  g_file_load_contents_async (uri, NULL, read_done_cb, arc);
-}
-
-static gchar *
-read_url (const gchar *url)
-{
-  GVfs *vfs;
-  GFile *uri;
-  GError *vfs_error = NULL;
-  gchar *content = NULL;
-
-  vfs = g_vfs_get_default ();
-
-  g_debug ("Opening '%s'", url);
-  uri = g_vfs_get_file_for_uri (vfs, url);
-  g_file_load_contents (uri, NULL, &content, NULL, NULL, &vfs_error);
-  g_object_unref (uri);
-  if (vfs_error) {
-    g_warning ("Failed reading '%s': %s", url, vfs_error->message);
-    return NULL;
-  } else {
-    return content;
-  }
-}
-
 static GrlMedia *
 build_media_from_entry (GrlMedia *content,
-			const Entry *entry,
+			GDataEntry *entry,
 			const GList *keys)
 {
+  GDataYouTubeVideo *video;
   GrlMedia *media;
-  gchar *url;
   GList *iter;
 
   if (!content) {
@@ -454,9 +305,11 @@ build_media_from_entry (GrlMedia *content,
     media = content;
   }
 
+  video = GDATA_YOUTUBE_VIDEO (entry);
+
   /* Make sure we set the media id in any case */
   if (!grl_media_get_id (media)) {
-    grl_media_set_id (media, entry->id);
+    grl_media_set_id (media, gdata_youtube_video_get_video_id (video));
   }
 
   iter = (GList *) keys;
@@ -464,22 +317,35 @@ build_media_from_entry (GrlMedia *content,
     GrlKeyID key_id = POINTER_TO_GRLKEYID (iter->data);
     switch (key_id) {
     case GRL_METADATA_KEY_TITLE:
-      grl_media_set_title (media, entry->title);
-      break;
-    case GRL_METADATA_KEY_AUTHOR:
-      grl_media_set_author (media, entry->author);
+      grl_media_set_title (media, gdata_entry_get_title (entry));
       break;
     case GRL_METADATA_KEY_DESCRIPTION:
-      grl_media_set_description (media, entry->description);
+      grl_media_set_description (media, gdata_entry_get_summary (entry));
       break;
     case GRL_METADATA_KEY_THUMBNAIL:
-      grl_media_set_thumbnail (media, entry->thumbnail);
+      {
+	GList *thumb_list;
+	thumb_list = gdata_youtube_video_get_thumbnails (video);
+	if (thumb_list) {
+	  GDataMediaThumbnail *thumbnail;
+	  thumbnail = GDATA_MEDIA_THUMBNAIL (thumb_list->data);
+	  grl_media_set_thumbnail (media,
+				   gdata_media_thumbnail_get_uri (thumbnail));
+	}
+      }
       break;
     case GRL_METADATA_KEY_DATE:
-      grl_media_set_date (media, entry->published);
+      {
+	GTimeVal date;
+	gchar *date_str;
+	gdata_entry_get_published (entry, &date);
+	date_str = g_time_val_to_iso8601 (&date);
+	grl_media_set_date (media, date_str);
+	g_free (date_str);
+      }
       break;
     case GRL_METADATA_KEY_DURATION:
-      grl_media_set_duration (media, atoi (entry->duration));
+      grl_media_set_duration (media, gdata_youtube_video_get_duration (video));
       break;
     case GRL_METADATA_KEY_MIME:
       grl_media_set_mime (media, YOUTUBE_VIDEO_MIME);
@@ -488,15 +354,29 @@ build_media_from_entry (GrlMedia *content,
       grl_media_set_site (media, YOUTUBE_SITE_URL);
       break;
     case GRL_METADATA_KEY_RATING:
-      grl_media_set_rating (media, entry->rating, "5.00");
+      {
+	gdouble average;
+	gdata_youtube_video_get_rating (video, NULL, NULL, NULL, &average);
+	grl_media_set_rating (media, average, 5.00);
+      }
       break;
     case GRL_METADATA_KEY_URL:
-      if (!entry->restricted) {
-	url = get_video_url (entry->id);
+      {
+	gchar *url = get_video_url (gdata_youtube_video_get_video_id (video));
 	if (url) {
 	  grl_media_set_url (media, url);
+	  g_free (url);
+	} else {
+	  GDataYouTubeContent *youtube_content;
+	  youtube_content =
+	    gdata_youtube_video_look_up_content (video,
+						 "application/x-shockwave-flash");
+	  if (youtube_content != NULL) {
+	    GDataMediaContent *content = GDATA_MEDIA_CONTENT (youtube_content);
+	    grl_media_set_url (media,
+			       gdata_media_content_get_uri (content));
+	  }
 	}
-	g_free (url);
       }
       break;
     default:
@@ -508,798 +388,98 @@ build_media_from_entry (GrlMedia *content,
   return media;
 }
 
-static gchar *
-parse_id (xmlDocPtr doc, xmlNodePtr id)
-{
-  gchar *value, *video_id;
-  value = (gchar *) xmlNodeListGetString (doc, id->xmlChildrenNode, 1);
-  video_id = g_strdup (g_strrstr (value , "/") + 1);
-  g_free (value);
-  return video_id;
-}
-
-static gchar *
-parse_author (xmlDocPtr doc, xmlNodePtr author)
-{
-  xmlNodePtr node;
-  node = author->xmlChildrenNode;
-  while (node) {
-    if (!xmlStrcmp (node->name, (const xmlChar *) "name")) {
-      return (gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-    }
-    node = node->next;
-  }
-  return NULL;
-}
-
-static void
-parse_media_group (xmlDocPtr doc, xmlNodePtr media, Entry *entry)
-{
-  xmlNodePtr node;
-  xmlNs *ns;
-
-  node = media->xmlChildrenNode;
-  while (node) {
-    ns = node->ns;
-    if (!xmlStrcmp (node->name, (const xmlChar *) "description")) {
-      entry->description =
-	(gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-    } else if (!xmlStrcmp (node->name, (const xmlChar *) "thumbnail") &&
-	       !entry->thumbnail) {
-      entry->thumbnail =
-	(gchar *) xmlGetProp (node, (xmlChar *) "url");
-    } else if (!xmlStrcmp (node->name, (const xmlChar *) "duration")) {
-      entry->duration =
-	(gchar *) xmlGetProp (node, (xmlChar *) "seconds");
-    }
-    node = node->next;
-  }
-}
-
-static void
-parse_app_control (xmlDocPtr doc, xmlNodePtr media, Entry *entry)
-{
-  xmlNodePtr node;
-  xmlChar *value;
-
-  node = media->xmlChildrenNode;
-  while (node) {
-    if (!xmlStrcmp (node->name, (const xmlChar *) "state")) {
-      value = xmlGetProp (node, (xmlChar *) "name");
-      if (!xmlStrcmp (value, (xmlChar *) "restricted")) {
-	entry->restricted = TRUE;
-      }
-      g_free ((gchar *) value);
-    }
-    node = node->next;
-  }
-}
-
-static void
-parse_entry (xmlDocPtr doc, xmlNodePtr entry, Entry *data)
-{
-  xmlNodePtr node;
-  xmlNs *ns;
-
-  node = entry->xmlChildrenNode;
-  while (node) {
-    ns = node->ns;
-    if (!xmlStrcmp (node->name, (const xmlChar *) "id")) {
-      data->id = parse_id (doc, node);
-    } else if (!xmlStrcmp (node->name, (const xmlChar *) "published")) {
-      data->published =
-	(gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-    } else if (!xmlStrcmp (node->name, (const xmlChar *) "title")) {
-      data->title =
-	(gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-    } else if (!xmlStrcmp (node->name, (const xmlChar *) "author")) {
-      data->author = parse_author (doc, node);
-    } else if (ns && !xmlStrcmp (ns->prefix, (const xmlChar *) "media") &&
-	       !xmlStrcmp (node->name, (const xmlChar *) "group")) {
-      parse_media_group (doc, node, data);
-    } else if (ns && !xmlStrcmp (ns->prefix, (const xmlChar *) "app") &&
-	       !xmlStrcmp (node->name, (const xmlChar *) "control")) {
-      parse_app_control (doc, node, data);
-    } else if (ns && !xmlStrcmp (ns->prefix, (const xmlChar *) "gd") &&
-	       !xmlStrcmp (node->name, (const xmlChar *) "rating")) {
-      data->rating = (gchar *) xmlGetProp (node, (xmlChar *) "average");
-    }
-
-    node = node->next;
-  }
-}
-
-static gboolean
-parse_entries_idle (gpointer user_data)
-{
-  ParseEntriesIdle *pei = (ParseEntriesIdle *) user_data;
-  gboolean parse_more = FALSE;
-
-  g_debug ("parse_entries_idle");
-
-  /* Do not bother if operation was cancelled */
-  if (!pei->os->cancelled) {
-    while (pei->node && xmlStrcmp (pei->node->name,
-				   (const xmlChar *) "entry")) {
-      pei->node = pei->node->next;
-    }
-
-    if (pei->node) {
-      Entry *entry = g_new0 (Entry, 1);
-      parse_entry (pei->doc, pei->node, entry);
-      if (0) print_entry (entry);
-      GrlMedia *media =
-	build_media_from_entry (NULL, entry, pei->os->keys);
-      free_entry (entry);
-
-      pei->os->skip++;
-      pei->os->count--;
-      pei->count++;
-      pei->os->callback (pei->os->source,
-			 pei->os->operation_id,
-			 media,
-			 pei->os->count,
-			 pei->os->user_data,
-			 NULL);
-
-      parse_more = TRUE;
-      pei->node = pei->node->next;
-    }
-  }
-
-  if (!parse_more) {
-    xmlFreeDoc (pei->doc);
-    /* Did we split the query in chunks? if so, query next chunk now */
-    if (!pei->os->cancelled && pei->os->count > 0 && pei->count > 0) {
-      /* We can go for the next chunk: operation not cancelled,
-	 still more results were requested and last chunk returned
-	 valid results */
-      produce_next_video_chunk (pei->os);
-    } else {
-      /* The operation is finished */
-      if (pei->os->cancelled && pei->os->count > 0) {
-	/* Operation cancelled before finalization. We stop the
-	   operation now */
-	g_debug ("Operation was cancelled, stopping next chunk");
-	pei->os->callback (pei->os->source,
-			   pei->os->operation_id,
-			   NULL,
-			   0,
-			   pei->os->user_data,
-			   NULL);
-      } else if (pei->count == 0) {
-	/* This can only happen in youtube's totalResults is wrong
-	   (actually greater than it should be). If that's the case
-	   there are not more results and we must finish the operation now */
-	g_warning ("Wrong totalResults from Youtube "		\
-		   "using NULL media to finish operation");
-	pei->os->callback (pei->os->source,
-			   pei->os->operation_id,
-			   NULL,
-			   0,
-			   pei->os->user_data,
-			   NULL);
-      }
-      free_operation_spec (pei->os);
-    }
-    g_free (pei);
-  }
-
-  return parse_more;
-}
-
-static void
-parse_feed (OperationSpec *os, const gchar *str, GError **error)
-{
-  xmlDocPtr doc;
-  xmlNodePtr node;
-  guint total_results;
-  xmlNs *ns;
-
-  doc = xmlRecoverDoc ((xmlChar *) str);
-  if (!doc) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_BROWSE_FAILED,
-			  "Failed to parse Youtube's response");
-    goto free_resources;
-  }
-
-  node = xmlDocGetRootElement (doc);
-  if (!node) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_BROWSE_FAILED,
-			  "Empty response from Youtube");
-    goto free_resources;
-  }
-
-  if (xmlStrcmp (node->name, (const xmlChar *) "feed")) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_BROWSE_FAILED,
-			  "Unexpected response from Youtube: no feed");
-    goto free_resources;
-  }
-
-  node = node->xmlChildrenNode;
-  if (!node) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_BROWSE_FAILED,
-			  "Unexpected response from Youtube: empty feed");
-    goto free_resources;
-  }
-
-  /* Compute # of items to send only when we execute the
-     first chunk of the query (os->chained_chunk == FALSE) */
-  if (!os->chained_chunk) {
-    os->chained_chunk = TRUE;
-    total_results = 0;
-    while (node && !total_results) {
-      if (!xmlStrcmp (node->name, (const xmlChar *) "entry")) {
-	break;
-      } else {
-	ns = node->ns;
-	if (ns && !xmlStrcmp (ns->prefix, (xmlChar *) "openSearch")) {
-	  if (!xmlStrcmp (node->name, (const xmlChar *) "totalResults")) {
-	    gchar *total_results_str =
-	      (gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-	    total_results = atoi (total_results_str);
-	    g_free (total_results_str);
-	  }
-	}
-      }
-      node = node->next;
-    }
-
-    if (total_results >= os->skip + os->count) {
-      /* Ok, we can send all the elements requested, no problem */
-    } else if (total_results > os->skip) {
-      /* We cannot send all, there aren't so many: adjust os->count
-	 so it represents the total available */
-      os->count = total_results - os->skip;
-    } else {
-      /* No results to send */
-      os->callback (os->source,
-                    os->operation_id,
-                    NULL,
-                    0,
-                    os->user_data,
-                    NULL);
-      goto free_resources;
-    }
-  }
-
-  /* Now go for the entries */
-  ParseEntriesIdle *pei = g_new0 (ParseEntriesIdle, 1);
-  pei->os = os;
-  pei->node = node;
-  pei->doc = doc;
-  g_idle_add (parse_entries_idle, pei);
-  return;
-
- free_resources:
-  xmlFreeDoc (doc);
-  return;
-}
-
-static GrlMedia *
-parse_metadata_entry (GrlMediaSourceMetadataSpec *os,
-		      xmlDocPtr doc,
-		      xmlNodePtr node,
-		      GError **error)
-{
-  xmlNs *ns;
-  guint total_results = 0;
-  GrlMedia *media = NULL;
-
-  /* First checkout search information looking for totalResults */
-  while (node && !total_results) {
-    if (!xmlStrcmp (node->name, (const xmlChar *) "entry")) {
-      break;
-    } else {
-      ns = node->ns;
-      if (ns && !xmlStrcmp (ns->prefix, (xmlChar *) "openSearch")) {
-	if (!xmlStrcmp (node->name, (const xmlChar *) "totalResults")) {
-	  gchar *total_results_str =
-	    (gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
-	  total_results = atoi (total_results_str);
-	  g_free (total_results_str);
-	}
-      }
-    }
-    node = node->next;
-  }
-
-  if (total_results <= 0) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_MEDIA_NOT_FOUND,
-			  "Could not find requested media");
-    return NULL;
-  }
-
-  while (node && xmlStrcmp (node->name, (const xmlChar *) "entry")) {
-    node = node->next;
-  }
-  if (node) {
-    const gchar *target_id = grl_media_get_id (os->media);
-    Entry *entry = g_new0 (Entry, 1);
-    parse_entry (doc, node, entry);
-    if (0) print_entry (entry);
-    if (!strcmp (entry->id, target_id)) {
-      build_media_from_entry (os->media, entry, os->keys);
-    } else {
-      /* FIXME: The query using the video id at target text resulted in various
-	 matches and the one we were looking for was not the first one */
-      g_warning ("Metadata query did not match expected target");
-    }
-    free_entry (entry);
-  }
-
-  return media;
-}
-
-static void
-parse_metadata_feed (GrlMediaSourceMetadataSpec *os,
-		     const gchar *str,
-		     GError **error)
-{
-  xmlDocPtr doc;
-  xmlNodePtr node;
-
-  doc = xmlRecoverDoc ((xmlChar *) str);
-  if (!doc) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_METADATA_FAILED,
-			  "Failed to parse Youtube's response");
-    goto free_resources;
-  }
-
-  node = xmlDocGetRootElement (doc);
-  if (!node) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_METADATA_FAILED,
-			  "Empty response from Youtube");
-    goto free_resources;
-  }
-
-  if (xmlStrcmp (node->name, (const xmlChar *) "feed")) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_METADATA_FAILED,
-			  "Unexpected response from Youtube: no feed");
-    goto free_resources;
-  }
-
-  node = node->xmlChildrenNode;
-  if (!node) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_METADATA_FAILED,
-			  "Unexpected response from Youtube: empty feed");
-    goto free_resources;
-  }
-
-  parse_metadata_entry (os, doc, node, error);
-
- free_resources:
-  xmlFreeDoc (doc);
-}
-
-static void
-parse_categories (xmlDocPtr doc, xmlNodePtr node)
-{
-  g_debug ("parse_categories");
-
-  guint total = 0;
-  GList *all = NULL, *iter;
-  CategoryInfo *cat_info;
-  gchar *id;
-  guint index = 0;
-
-  while (node) {
-    cat_info = g_new (CategoryInfo, 1);
-    id = (gchar *) xmlGetProp (node, (xmlChar *) "term");
-    cat_info->id = g_strconcat (YOUTUBE_CATEGORIES_ID, "/", id, NULL);
-    cat_info->name = (gchar *) xmlGetProp (node, (xmlChar *) "label");
-    cat_info->url = g_strdup_printf (YOUTUBE_CATEGORY_URL,
-				     id, "%d", "%d");
-    all = g_list_prepend (all, cat_info);
-    g_free (id);
-    node = node->next;
-    total++;
-    g_debug ("  Found category: '%d - %s'", index++, cat_info->name);
-  }
-
-  if (all) {
-    categories_dir_size = total;
-    categories_dir = g_new0 (CategoryInfo, total + 1);
-    iter = all;
-    do {
-      cat_info = (CategoryInfo *) iter->data;
-      categories_dir[total - 1].id = cat_info->id ;
-      categories_dir[total - 1].name = cat_info->name;
-      categories_dir[total - 1].url = cat_info->url;
-      total--;
-      g_free (cat_info);
-      iter = g_list_next (iter);
-    } while (iter);
-    g_list_free (all);
-  }
-}
-
 static void
-build_categories_directory_read_cb (gchar *xmldata, gpointer user_data)
+process_feed (GDataFeed *feed, OperationSpec *os)
 {
-  xmlDocPtr doc;
-  xmlNodePtr node;
+  GList *entries;
 
-  if (!xmldata) {
-    g_critical ("Failed to build category directory (1)");
-    return;
-  }
-
-  doc = xmlRecoverDoc ((xmlChar *) xmldata);
-  if (!doc) {
-    g_critical ("Failed to build category directory (2)");
-    goto free_resources;
-  }
-
-  node = xmlDocGetRootElement (doc);
-  if (!node) {
-    g_critical ("Failed to build category directory (3)");
-    goto free_resources;
-  }
-
-  if (xmlStrcmp (node->name, (const xmlChar *) "categories")) {
-    g_critical ("Failed to build category directory (4)");
-    goto free_resources;
-  }
-
-  node = node->xmlChildrenNode;
-  if (!node) {
-    g_critical ("Failed to build category directory (5)");
-    goto free_resources;
-  }
-
-  parse_categories (doc, node);
-
- free_resources:
-  xmlFreeDoc (doc);
-  return;
-}
-
-static void
-build_categories_directory (void)
-{
-  read_url_async (YOUTUBE_CATEGORIES_URL,
-                  build_categories_directory_read_cb,
-                  NULL);
-}
-
-static gboolean
-is_category_container (const gchar *container_id)
-{
-  return g_str_has_prefix (container_id, YOUTUBE_CATEGORIES_ID "/");
-}
-
-static gboolean
-is_feeds_container (const gchar *container_id)
-{
-  return g_str_has_prefix (container_id, YOUTUBE_FEEDS_ID "/");
-}
-
-static const gchar *
-get_container_url (const gchar *container_id)
-{
-  g_debug ("get_container_url (%s)", container_id);
-
-  guint index;
-  CategoryInfo *directory;
-
-  if (is_category_container (container_id)) {
-    directory = categories_dir;
-  } else if (is_feeds_container (container_id)) {
-    directory = feeds_dir;
-  } else {
-    g_warning ("Cannot get URL for container id '%s'", container_id);
-    return NULL;
-  }
-
-  if (directory == NULL) {
-    g_critical ("Required directory is not initialized");
-    return NULL;
-  }
-
-  index = 0;
-  while (directory[index].id &&
-	 strcmp (container_id, directory[index].id)) {
-    index++;
-  }
-  if (directory[index].id) {
-    return directory[index].url;
-  } else {
-    return NULL;
-  }
-}
-
-static void
-set_category_childcount (GrlMediaBox *content,
-                         CategoryInfo *dir,
-                         guint index)
-{
-  gint childcount;
-  gboolean set_childcount = TRUE;
-
-  if (dir == NULL) {
-    /* Special case: we want childcount of root category */
-    childcount = root_dir_size;
-  } else if (!strcmp (dir[index].id, YOUTUBE_FEEDS_ID)) {
-    childcount = feeds_dir_size;
-  } else if (!strcmp (dir[index].id, YOUTUBE_CATEGORIES_ID)) {
-    childcount = categories_dir_size;
-  } else {
-    const gchar *_url = get_container_url (dir[index].id);
-    if (_url) {
-      gchar *url = g_strdup_printf (_url, 1, 0);
-      gchar  *xmldata = read_url (url);
-      g_free (url);
-      if (!xmldata) {
-	g_warning ("Failed to connect to Youtube to get category childcount");
-	return;
-      }
-      gchar *start = strstr (xmldata, YOUTUBE_TOTAL_RESULTS_START) +
-	strlen (YOUTUBE_TOTAL_RESULTS_START);
-      gchar *end = strstr (start, YOUTUBE_TOTAL_RESULTS_END);
-      gchar *childcount_str = g_strndup (start, end - start);
-      childcount = strtol (childcount_str, (char **) NULL, 10);
-    } else {
-      set_childcount = FALSE;
-    }
-  }
-
-  if (set_childcount) {
-    grl_media_box_set_childcount (content, childcount);
-  }
-}
-
-static GrlMedia *
-produce_container_from_directory (GrlMedia *media,
-				  CategoryInfo *dir,
-				  guint index,
-				  gboolean set_childcount)
-{
-  GrlMedia *content;
-
-  if (!media) {
-    /* Create mode */
-    content = grl_media_box_new ();
-  } else {
-    /* Update mode */
-    content = media;
-  }
-
-  if (!dir) {
-    grl_media_set_id (content, NULL);
-    grl_media_set_title (content, YOUTUBE_ROOT_NAME);
-  } else {
-    grl_media_set_id (content, dir[index].id);
-    grl_media_set_title (content, dir[index].name);
-  }
-  grl_media_set_site (content, YOUTUBE_SITE_URL);
-  if (set_childcount) {
-    set_category_childcount (GRL_MEDIA_BOX (content), dir, index);
-  }
-
-  return content;
-}
-
-static GrlMedia *
-produce_container_from_directory_by_id (GrlMedia *media,
-					CategoryInfo *dir,
-					const gchar *id,
-					gboolean set_childcount)
-{
-  GrlMedia *content;
-  guint index = 0;
-
-  while (dir[index].id && strcmp (dir[index].id, id)) index++;
-  if (dir[index].id) {
-    content = produce_container_from_directory (media, dir,
-						index, set_childcount);
-  } else {
-    /* If don't have that entry, return the media as it was
-       provided (if media was NULL, we return NULL) */
-    content = media;
-  }
-
-  return content;
-}
-
-static YoutubeMediaType
-classify_media_id (const gchar *media_id)
-{
-  if (!media_id) {
-    return YOUTUBE_MEDIA_TYPE_ROOT;
-  } else if (!strcmp (media_id, YOUTUBE_FEEDS_ID)) {
-    return YOUTUBE_MEDIA_TYPE_FEEDS;
-  } else if (!strcmp (media_id, YOUTUBE_CATEGORIES_ID)) {
-    return YOUTUBE_MEDIA_TYPE_CATEGORIES;
-  } else if (is_category_container (media_id)) {
-    return YOUTUBE_MEDIA_TYPE_CATEGORY;
-  } else if (is_feeds_container (media_id)) {
-    return YOUTUBE_MEDIA_TYPE_FEED;
-  } else {
-    return YOUTUBE_MEDIA_TYPE_VIDEO;
-  }
-}
-
-static gboolean
-produce_from_directory_idle (gpointer user_data)
-{
-  GrlMedia *content;
-  ProduceFromDirectoryIdle *pfdi = (ProduceFromDirectoryIdle *) user_data;
-
-  if (!pfdi->os->cancelled) {
-    content = produce_container_from_directory (NULL,
-						pfdi->directory,
-						pfdi->index,
-						pfdi->set_childcount);
-    pfdi->remaining--;
-    pfdi->index++;
-  } else {
-    content = NULL;
-    pfdi->remaining = 0;
-  }
-
-  pfdi->os->callback (pfdi->os->source,
-		      pfdi->os->operation_id,
-		      content,
-		      pfdi->remaining,
-		      pfdi->os->user_data,
-		      NULL);
-
-  if (pfdi->remaining == 0) {
-    free_operation_spec (pfdi->os);
-    g_free (pfdi);
-    return FALSE;
+  /* Send results to client */
+  entries = gdata_feed_get_entries (feed);
+  while (entries) {
+    GrlMedia *media =
+      build_media_from_entry (NULL, GDATA_ENTRY (entries->data), os->keys);
+    os->callback (os->source,
+		  os->operation_id,
+		  media,
+		  --(os->count),
+		  os->user_data,
+		  NULL);
+    entries = g_list_next (entries);
   }
 
-  return TRUE;
-}
-
-static void
-produce_from_directory (CategoryInfo *dir, guint dir_size, OperationSpec *os)
-{
-  g_debug ("produce_from_directory");
-
-  guint index, remaining;
-  gboolean set_childcount;
-  YoutubeMediaType media_type;
-
-  if (os->skip >= dir_size) {
-    /* No results */
+  /* Send last result if not yet sent */
+  if (os->count > 0) {
     os->callback (os->source,
 		  os->operation_id,
 		  NULL,
 		  0,
 		  os->user_data,
 		  NULL);
-    free_operation_spec (os);
-  } else {
-    /* Do not compute childcount when it is expensive and user requested
-       GRL_RESOLVE_FAST_ONLY */
-    media_type = classify_media_id (os->container_id);
-    if ((os->flags & GRL_RESOLVE_FAST_ONLY) &&
-	(media_type == YOUTUBE_MEDIA_TYPE_CATEGORIES ||
-	 media_type == YOUTUBE_MEDIA_TYPE_FEEDS)) {
-      set_childcount = FALSE;
-    } else {
-      set_childcount =
-	(g_list_find (os->keys,
-		      GRLKEYID_TO_POINTER (GRL_METADATA_KEY_CHILDCOUNT)) != NULL);
-    }
-    index = os->skip;
-    remaining = MIN (dir_size - os->skip, os->count);
-
-    /* We use the idle loop because computing the childcount is blocking
-       and it may be called for every entry in the directory */
-    ProduceFromDirectoryIdle *pfdi = g_new0 (ProduceFromDirectoryIdle, 1);
-    pfdi->os = os;
-    pfdi->directory = dir;
-    pfdi->index = index;
-    pfdi->remaining = remaining;
-    pfdi->set_childcount = set_childcount;
-    g_idle_add (produce_from_directory_idle, pfdi);
   }
+
+  free_operation_spec (os);
 }
 
 static void
-produce_next_video_chunk_read_cb (gchar *xmldata, gpointer user_data)
+process_metadata (GDataYouTubeVideo *video, GrlMediaSourceMetadataSpec *ms)
 {
-  GError *error = NULL;
-  OperationSpec *os = (OperationSpec *) user_data;
-
-  if (!xmldata) {
-    error = g_error_new (GRL_ERROR,
-			 GRL_ERROR_BROWSE_FAILED,
-			 "Failed to read from Youtube");
-  } else {
-    parse_feed (os, xmldata, &error);
-    g_free (xmldata);
-  }
-
-  if (error) {
-    os->callback (os->source,
-		  os->operation_id,
-		  NULL,
-		  0,
-		  os->user_data,
-		  error);
-    g_error_free (error);
-    free_operation_spec (os);
-  }
+  build_media_from_entry (ms->media, GDATA_ENTRY (video), ms->keys);
+  ms->callback (ms->source, ms->media, ms->user_data, NULL);
 }
 
 static void
-produce_next_video_chunk (OperationSpec *os)
+metadata_cb (GObject *object,
+	     GAsyncResult *result,
+	     GrlMediaSourceMetadataSpec *ms)
 {
-  gchar *url;
+  g_debug ("metadata_cb");
 
-  g_debug ("produce_next_video_chunk");
+  GError *error = NULL;
+  GrlYoutubeSource *source = GRL_YOUTUBE_SOURCE (ms->source);
 
-  if (os->count > YOUTUBE_MAX_CHUNK) {
-    url = g_strdup_printf (os->query_url, os->skip + 1, YOUTUBE_MAX_CHUNK);
+  GDataYouTubeVideo *video =
+    gdata_youtube_service_query_single_video_finish (GDATA_YOUTUBE_SERVICE (source->service),
+						     result,
+						     &error);
+  if (error) {
+    error->code = GRL_ERROR_METADATA_FAILED;
+    ms->callback (ms->source, ms->media, ms->user_data, error);
+    g_error_free (error);
   } else {
-    url = g_strdup_printf (os->query_url, os->skip + 1, os->count);
+    process_metadata (video, ms);
   }
-  read_url_async (url, produce_next_video_chunk_read_cb, os);
-  g_free (url);
-}
 
-static void
-produce_videos_from_container (OperationSpec *os, GError **error)
-{
-  const gchar *_url;
-
-  _url = get_container_url (os->container_id);
-  if (!_url) {
-    *error = g_error_new (GRL_ERROR,
-			  GRL_ERROR_BROWSE_FAILED,
-			  "Invalid container-id: '%s'",
-			  os->container_id);
-  } else {
-    os->query_url = g_strdup (_url);
-    produce_next_video_chunk (os);
+  if (video) {
+    g_object_unref (video);
   }
 }
 
 static void
-produce_videos_from_search (const gchar *text,
-			    OperationSpec *os,
-			    GError **error)
+search_cb (GObject *object, GAsyncResult *result, OperationSpec *os)
 {
-  gchar *url;
-  url = g_strdup_printf (YOUTUBE_SEARCH_URL, text, "%d", "%d");
-  os->query_url = url;
-  produce_next_video_chunk (os);
-}
+  g_debug ("search_cb");
 
-static void
-metadata_read_cb (gchar *xmldata, gpointer user_data)
-{
+  GDataFeed *feed;
   GError *error = NULL;
-  GrlMediaSourceMetadataSpec *ms = (GrlMediaSourceMetadataSpec *) user_data;
-
-  if (!xmldata) {
-    error = g_error_new (GRL_ERROR,
-			 GRL_ERROR_METADATA_FAILED,
-			 "Failed to read from Youtube");
-  } else {
-    parse_metadata_feed (ms, xmldata, &error);
-    g_free (xmldata);
-  }
-
+  GrlYoutubeSource *source = GRL_YOUTUBE_SOURCE (os->source);
+  
+  feed = gdata_service_query_finish (GDATA_SERVICE (source->service),
+				     result, &error);
   if (error) {
-    ms->callback (ms->source, ms->media, ms->user_data, error);
+    error->code = os->error_code;
+    os->callback (os->source, os->operation_id, NULL, 0, os->user_data, error);
     g_error_free (error);
+    if (feed) {
+      g_object_unref (feed);
+    }
   } else {
-    ms->callback (ms->source, ms->media, ms->user_data, NULL);
+    g_debug ("Feed info: %s - %u/%u/%u",
+	     gdata_feed_get_title (feed),
+	     gdata_feed_get_start_index (feed),
+	     gdata_feed_get_items_per_page (feed),
+	     gdata_feed_get_total_results (feed));
+
+    process_feed (feed, os);
   }
 }
 
@@ -1313,7 +493,6 @@ grl_youtube_source_supported_keys (GrlMetadataSource *source)
     keys = grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
                                       GRL_METADATA_KEY_TITLE,
                                       GRL_METADATA_KEY_URL,
-                                      GRL_METADATA_KEY_AUTHOR,
                                       GRL_METADATA_KEY_DESCRIPTION,
                                       GRL_METADATA_KEY_DURATION,
                                       GRL_METADATA_KEY_DATE,
@@ -1342,55 +521,12 @@ grl_youtube_source_slow_keys (GrlMetadataSource *source)
 }
 
 static void
-grl_youtube_source_browse (GrlMediaSource *source,
-                           GrlMediaSourceBrowseSpec *bs)
-{
-  OperationSpec *os;
-  GError *error = NULL;
-  const gchar *container_id;
-
-  g_debug ("grl_youtube_source_browse");
-
-  container_id = grl_media_get_id (bs->container);
-
-  os = g_new0 (OperationSpec, 1);
-  os->source = bs->source;
-  os->operation_id = bs->browse_id;
-  os->container_id = container_id;
-  os->keys = bs->keys;
-  os->flags = bs->flags;
-  os->skip = bs->skip;
-  os->count = bs->count;
-  os->callback = bs->callback;
-  os->user_data = bs->user_data;
-
-  grl_media_source_set_operation_data (source, os->operation_id, os);
-
-  if (!container_id) {
-    produce_from_directory (root_dir, root_dir_size, os);
-  } else if (!strcmp (container_id, YOUTUBE_FEEDS_ID)) {
-    produce_from_directory (feeds_dir, feeds_dir_size, os);
-  } else if (!strcmp (container_id, YOUTUBE_CATEGORIES_ID)) {
-    produce_from_directory (categories_dir, categories_dir_size, os);
-  } else {
-    produce_videos_from_container (os, &error);
-    if (error) {
-      os->callback (os->source, os->operation_id, NULL,
-		    0, os->user_data, error);
-      g_error_free (error);
-      free_operation_spec (os);
-    }
-  }
-}
-
-static void
 grl_youtube_source_search (GrlMediaSource *source,
                            GrlMediaSourceSearchSpec *ss)
 {
   OperationSpec *os;
-  GError *error = NULL;
 
-  g_debug ("grl_youtube_source_search");
+  g_debug ("grl_youtube_source_search %u", ss->count);
 
   os = g_new0 (OperationSpec, 1);
   os->source = source;
@@ -1400,100 +536,28 @@ grl_youtube_source_search (GrlMediaSource *source,
   os->count = ss->count;
   os->callback = ss->callback;
   os->user_data = ss->user_data;
+  os->error_code = GRL_ERROR_SEARCH_FAILED;
+  os->query = gdata_query_new_with_limits (ss->text, ss->skip, ss->count);
 
-  grl_media_source_set_operation_data (source, os->operation_id, os);
-  produce_videos_from_search (ss->text, os, &error);
-
-  if (error) {
-    error->code = GRL_ERROR_SEARCH_FAILED;
-    os->callback (os->source, os->operation_id, NULL, 0, os->user_data, error);
-    g_error_free (error);
-    g_free (os->query_url);
-    g_free (os);
-  }
+  gdata_youtube_service_query_videos_async (GRL_YOUTUBE_SOURCE (source)->service,
+					    os->query,
+					    NULL,
+					    NULL,
+					    NULL,
+					    (GAsyncReadyCallback) search_cb,
+					    os);
 }
 
 static void
 grl_youtube_source_metadata (GrlMediaSource *source,
                              GrlMediaSourceMetadataSpec *ms)
 {
-  gchar *url;
-  GError *error = NULL;
-  GrlMedia *media = NULL;
-  YoutubeMediaType media_type;
-  gboolean set_childcount;
-  const gchar *id;
-
   g_debug ("grl_youtube_source_metadata");
-
-  id = grl_media_get_id (ms->media);
-  media_type = classify_media_id (id);
-
-  /* Do not compute childcount for expensive categories
-     if user requested that */
-  if ((ms->flags & GRL_RESOLVE_FAST_ONLY) &&
-      (media_type == YOUTUBE_MEDIA_TYPE_CATEGORIES ||
-       media_type == YOUTUBE_MEDIA_TYPE_FEEDS)) {
-    set_childcount = FALSE;
-  } else {
-    set_childcount =
-      (g_list_find (ms->keys,
-		    GRLKEYID_TO_POINTER (GRL_METADATA_KEY_CHILDCOUNT)) != NULL);
-  }
-
-  switch (media_type) {
-  case YOUTUBE_MEDIA_TYPE_ROOT:
-    media = produce_container_from_directory (ms->media, NULL,
-					      0, set_childcount);
-    break;
-  case YOUTUBE_MEDIA_TYPE_FEEDS:
-    media = produce_container_from_directory (ms->media, root_dir,
-					      0, set_childcount);
-    break;
-  case YOUTUBE_MEDIA_TYPE_CATEGORIES:
-    media = produce_container_from_directory (ms->media, root_dir,
-					      1, set_childcount);
-    break;
-  case YOUTUBE_MEDIA_TYPE_FEED:
-    media = produce_container_from_directory_by_id (ms->media,
-						    feeds_dir,
-						    id,
-						    set_childcount);
-    break;
-  case YOUTUBE_MEDIA_TYPE_CATEGORY:
-    media = produce_container_from_directory_by_id (ms->media,
-						    categories_dir,
-						    id,
-						    set_childcount);
-    break;
-  case YOUTUBE_MEDIA_TYPE_VIDEO:
-  default:
-    {
-      /* For metadata retrieval we just search by text using the video ID */
-      /* This case is async, we will emit results in the read callback */
-      url = g_strdup_printf (YOUTUBE_SEARCH_URL, id, "1", "1");
-      read_url_async (url, metadata_read_cb, ms);
-      g_free (url);
-    }
-    break;
-  }
-
-  if (error) {
-    ms->callback (ms->source, ms->media, ms->user_data, error);
-    g_error_free (error);
-  } else if (media) {
-    ms->callback (ms->source, ms->media, ms->user_data, NULL);
-  }
-}
-
-static void
-grl_youtube_source_cancel (GrlMediaSource *source, guint operation_id)
-{
-  OperationSpec *spec;
-  g_debug ("grl_youtube_source_cancel");
-  spec = (OperationSpec *) grl_media_source_get_operation_data (source,
-                                                                operation_id);
-  if (spec) {
-    spec->cancelled = TRUE;
-  }
+  
+  gdata_youtube_service_query_single_video_async (GRL_YOUTUBE_SOURCE (source)->service,
+						  NULL,
+						  grl_media_get_id (ms->media),
+						  NULL,
+						  (GAsyncReadyCallback) metadata_cb,
+						  ms);
 }
diff --git a/src/youtube/grl-youtube.h b/src/youtube/grl-youtube.h
index 5a26ac9..b88d637 100644
--- a/src/youtube/grl-youtube.h
+++ b/src/youtube/grl-youtube.h
@@ -24,6 +24,7 @@
 #define _GRL_YOUTUBE_SOURCE_H_
 
 #include <grilo.h>
+#include <gdata/gdata.h>
 
 #define GRL_YOUTUBE_SOURCE_TYPE                 \
   (grl_youtube_source_get_type ())
@@ -56,6 +57,7 @@ typedef struct _GrlYoutubeSource GrlYoutubeSource;
 struct _GrlYoutubeSource {
 
   GrlMediaSource parent;
+  GDataYouTubeService *service;
 };
 
 typedef struct _GrlYoutubeSourceClass GrlYoutubeSourceClass;



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