[grilo-plugins] podcasts: update podcast description and thumbnail information when podcast is refreshed.



commit 2d4f453d5ecce9b343bb91ca1b1d46b08b8b0d90
Author: Iago Toral Quiroga <itoral igalia com>
Date:   Wed Jun 1 11:10:39 2011 +0200

    podcasts: update podcast description and thumbnail information when podcast is refreshed.

 src/media/podcasts/grl-podcasts.c |  137 +++++++++++++++++++++++++++++++------
 1 files changed, 117 insertions(+), 20 deletions(-)
---
diff --git a/src/media/podcasts/grl-podcasts.c b/src/media/podcasts/grl-podcasts.c
index 791764b..62aef46 100644
--- a/src/media/podcasts/grl-podcasts.c
+++ b/src/media/podcasts/grl-podcasts.c
@@ -54,7 +54,8 @@ GRL_LOG_DOMAIN_STATIC(podcasts_log_domain);
   "title TEXT,"                                 \
   "url   TEXT,"                                 \
   "desc  TEXT,"                                 \
-  "last_refreshed DATE)"
+  "last_refreshed DATE,"                        \
+  "image TEXT)"
 
 #define GRL_SQL_CREATE_TABLE_STREAMS		 \
   "CREATE TABLE IF NOT EXISTS streams ( "        \
@@ -131,8 +132,10 @@ GRL_LOG_DOMAIN_STATIC(podcasts_log_domain);
 
 #define GRL_SQL_TOUCH_PODCAST			\
   "UPDATE podcasts "				\
-  "SET last_refreshed='%s' "			\
-  "WHERE id='%s'"
+  "SET last_refreshed=?, "			\
+  "    desc=?, "                                \
+  "    image=? "                                \
+  "WHERE id=?"
 
 /* --- Other --- */
 
@@ -152,6 +155,7 @@ enum {
   PODCAST_URL,
   PODCAST_DESC,
   PODCAST_LAST_REFRESHED,
+  PODCAST_IMAGE,
   PODCAST_LAST,
 };
 
@@ -174,6 +178,11 @@ typedef struct {
 } AsyncReadCb;
 
 typedef struct {
+  gchar *image;
+  gchar *desc;
+} PodcastData;
+
+typedef struct {
   gchar *id;
   gchar *url;
   gchar *title;
@@ -393,6 +402,14 @@ free_entry (Entry *entry)
 }
 
 static void
+free_podcast_data (PodcastData *data)
+{
+  g_free (data->image);
+  g_free (data->desc);
+  g_slice_free (PodcastData, data);
+}
+
+static void
 read_done_cb (GObject *source_object,
               GAsyncResult *res,
               gpointer user_data)
@@ -521,6 +538,7 @@ build_media (GrlMedia *content,
 	     const gchar *desc,
 	     const gchar *mime,
 	     const gchar *date,
+             const gchar *image,
 	     guint duration,
 	     guint childcount)
 {
@@ -565,6 +583,8 @@ build_media (GrlMedia *content,
 
   grl_media_set_title (media, title);
   grl_media_set_url (media, url);
+  if (image)
+    grl_media_add_thumbnail (media, image);
 
   site = get_site_from_url (url);
   if (site) {
@@ -585,7 +605,7 @@ build_media_from_entry (Entry *entry)
   media = build_media (NULL, FALSE,
 		       entry->url, entry->title, entry->url,
 		       entry->summary, entry->mime, entry->published,
-		       duration, 0);
+		       NULL, duration, 0);
   return media;
 }
 
@@ -601,6 +621,7 @@ build_media_from_stmt (GrlMedia *content,
   gchar *desc;
   gchar *mime;
   gchar *date;
+  gchar *image;
   guint duration;
   guint childcount;
 
@@ -609,9 +630,10 @@ build_media_from_stmt (GrlMedia *content,
     title = (gchar *) sqlite3_column_text (sql_stmt, PODCAST_TITLE);
     url = (gchar *) sqlite3_column_text (sql_stmt, PODCAST_URL);
     desc = (gchar *) sqlite3_column_text (sql_stmt, PODCAST_DESC);
+    image = (gchar *) sqlite3_column_text (sql_stmt, PODCAST_IMAGE);
     childcount = (guint) sqlite3_column_int (sql_stmt, PODCAST_LAST);
-    media = build_media (content, is_podcast,
-			 id, title, url, desc, NULL, NULL, 0, childcount);
+    media = build_media (content, is_podcast, id,
+                         title, url, desc, NULL, NULL, image, 0, childcount);
   } else {
     mime = (gchar *) sqlite3_column_text (sql_stmt, STREAM_MIME);
     url = (gchar *) sqlite3_column_text (sql_stmt, STREAM_URL);
@@ -619,8 +641,8 @@ build_media_from_stmt (GrlMedia *content,
     date = (gchar *) sqlite3_column_text (sql_stmt, STREAM_DATE);
     desc = (gchar *) sqlite3_column_text (sql_stmt, STREAM_DESC);
     duration = sqlite3_column_int (sql_stmt, STREAM_LENGTH);
-    media = build_media (content, is_podcast,
-			 url, title, url, desc, mime, date, duration, 0);
+    media = build_media (content, is_podcast, url,
+                         title, url, desc, mime, date, NULL, duration, 0);
   }
 
   return media;
@@ -910,6 +932,44 @@ store_stream (sqlite3 *db, const gchar *podcast_id, Entry *entry)
   sqlite3_finalize (sql_stmt);
 }
 
+static PodcastData *
+parse_podcast_data (xmlDocPtr doc, xmlXPathObjectPtr xpathObj)
+{
+  xmlNodeSetPtr nodes;
+  xmlNodePtr node;
+  PodcastData *podcast_data = NULL;
+
+  nodes = xpathObj->nodesetval;
+  if (!nodes || !nodes->nodeTab) {
+    return NULL;
+  }
+
+  /* Loop through the podcast data (we skip the "item" tags, since
+     the podcast entries will be parsed later on */
+
+  /* At the moment we are only interested in 'image' and 'description' tags */
+  podcast_data = g_slice_new0 (PodcastData);
+  node = nodes->nodeTab[0]->xmlChildrenNode;
+  while (node && xmlStrcmp (node->name, (const xmlChar *) "item")) {
+    if (!xmlStrcmp (node->name, (const xmlChar *) "image")) {
+      xmlNodePtr imgNode = node->xmlChildrenNode;
+      while (imgNode && xmlStrcmp (imgNode->name, (const xmlChar *) "url")) {
+        imgNode = imgNode->next;
+      }
+      if (imgNode) {
+        podcast_data->image =
+          (gchar *) xmlNodeListGetString (doc, imgNode->xmlChildrenNode, 1);
+      }
+    } else if (!xmlStrcmp (node->name, (const xmlChar *) "description")) {
+      podcast_data->desc =
+	(gchar *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
+    }
+    node = node->next;
+  }
+
+  return podcast_data;
+}
+
 static void
 parse_entry (xmlDocPtr doc, xmlNodePtr entry, Entry *data)
 {
@@ -938,28 +998,45 @@ parse_entry (xmlDocPtr doc, xmlNodePtr entry, Entry *data)
 }
 
 static void
-touch_podcast (sqlite3 *db, const gchar *podcast_id)
+touch_podcast (sqlite3 *db, const gchar *podcast_id, PodcastData *data)
 {
   gint r;
-  gchar *sql, *sql_error;
+  sqlite3_stmt *sql_stmt = NULL;
   GTimeVal now;
   gchar *now_str;
+  gchar *img;
+  gchar *desc;
 
   GRL_DEBUG ("touch_podcast");
 
   g_get_current_time (&now);
   now_str = g_time_val_to_iso8601 (&now);
+  desc = data->desc ? data->desc : "";
+  img = data->image ? data->image : "";
 
-  sql = g_strdup_printf (GRL_SQL_TOUCH_PODCAST, now_str, podcast_id);
-  GRL_DEBUG ("%s", sql);
-  r = sqlite3_exec (db, sql, NULL, NULL, &sql_error);
-  g_free (sql);
-
+  r = sqlite3_prepare_v2 (db,
+			  GRL_SQL_TOUCH_PODCAST,
+			  strlen (GRL_SQL_TOUCH_PODCAST),
+			  &sql_stmt, NULL);
   if (r != SQLITE_OK) {
-    GRL_WARNING ("Failed to touch podcast, '%s': %s", podcast_id, sql_error);
-    sqlite3_free (sql_error);
-    return;
+    GRL_WARNING ("Failed to touch podcast '%s': %s",
+                 podcast_id, sqlite3_errmsg (db));
+  } else {
+    sqlite3_bind_text (sql_stmt, 1, now_str, -1, SQLITE_STATIC);
+    sqlite3_bind_text (sql_stmt, 2, desc, -1, SQLITE_STATIC);
+    sqlite3_bind_text (sql_stmt, 3, img, -1, SQLITE_STATIC);
+    sqlite3_bind_text (sql_stmt, 4, podcast_id, -1, SQLITE_STATIC);
+
+    while ((r = sqlite3_step (sql_stmt)) == SQLITE_BUSY);
+    if (r != SQLITE_DONE) {
+      GRL_WARNING ("Failed to touch podcast '%s': %s", podcast_id,
+                   sqlite3_errmsg (db));
+    }
+
+    sqlite3_finalize (sql_stmt);
   }
+
+  g_free (now_str);
 }
 
 static gboolean
@@ -1052,6 +1129,7 @@ parse_feed (OperationSpec *os, const gchar *str, GError **error)
   xmlXPathContextPtr xpathCtx = NULL;
   xmlXPathObjectPtr xpathObj = NULL;
   guint stream_count;
+  PodcastData *podcast_data = NULL;
 
   GRL_DEBUG ("parse_feed");
 
@@ -1071,7 +1149,22 @@ parse_feed (OperationSpec *os, const gchar *str, GError **error)
 			  "Failed to parse podcast contents");
     goto free_resources;
   }
+
+  /* Check podcast data */
+  xpathObj = xmlXPathEvalExpression ((xmlChar *) "/rss/channel",
+				     xpathCtx);
+  if(xpathObj == NULL) {
+    *error = g_error_new (GRL_CORE_ERROR,
+			  os->error_code,
+			  "Failed to parse podcast contents");
+    goto free_resources;
+  }
   
+  podcast_data = parse_podcast_data (doc, xpathObj);
+  xmlXPathFreeObject (xpathObj);
+
+  /* Check podcast items */
+
   xpathObj = xmlXPathEvalExpression ((xmlChar *) "/rss/channel/item",
 				     xpathCtx);
   if(xpathObj == NULL) {
@@ -1091,8 +1184,10 @@ parse_feed (OperationSpec *os, const gchar *str, GError **error)
     goto free_resources;
   }
 
-  /* Then update the last_refreshed date of the podcast */
-  touch_podcast (GRL_PODCASTS_SOURCE (os->source)->priv->db, os->media_id);
+  /* Then update the podcast data, including the last_refreshed date */
+  touch_podcast (GRL_PODCASTS_SOURCE (os->source)->priv->db,
+                 os->media_id,
+                 podcast_data);
 
   /* If the feed contains no streams, notify and bail out */
   stream_count = xpathObj->nodesetval ? xpathObj->nodesetval->nodeNr : 0;
@@ -1128,6 +1223,8 @@ parse_feed (OperationSpec *os, const gchar *str, GError **error)
   return;
 
  free_resources:
+  if (podcast_data)
+    free_podcast_data (podcast_data);
   if (xpathObj)
     xmlXPathFreeObject (xpathObj);
   if (xpathCtx)



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