[grilo-plugins] thetvdb: avoid cache miss with fuzzy series name



commit 510f88aca3aaa82007b20378dbc126c8aad71a74
Author: Victor Toso <me victortoso com>
Date:   Sun Apr 26 20:49:17 2015 +0200

    thetvdb: avoid cache miss with fuzzy series name
    
    Including the requested show name in the database we can map it with
    what thetvdb returned. By looking in both columns we can avoid the cache
    miss. e.g:
    
    thetvdb: "CSI: Miami"
    application: "CSI - Miami"
    
    https://bugzilla.gnome.org/show_bug.cgi?id=748423

 src/thetvdb/Makefile.am                     |    1 +
 src/thetvdb/grl-thetvdb.c                   |  113 ++++++++++++++++++--
 src/thetvdb/thetvdb-resources-fuzzy-names.c |  155 +++++++++++++++++++++++++++
 src/thetvdb/thetvdb-resources.h             |   52 +++++++++
 4 files changed, 313 insertions(+), 8 deletions(-)
---
diff --git a/src/thetvdb/Makefile.am b/src/thetvdb/Makefile.am
index 29c8dd4..cc1c056 100644
--- a/src/thetvdb/Makefile.am
+++ b/src/thetvdb/Makefile.am
@@ -27,6 +27,7 @@ libgrlthetvdb_la_SOURCES = \
         grl-thetvdb.h \
         thetvdb-resources-series.c \
         thetvdb-resources-episodes.c \
+        thetvdb-resources-fuzzy-names.c \
         thetvdb-resources.h
 
 extdir                         = $(GRL_PLUGINS_DIR)
diff --git a/src/thetvdb/grl-thetvdb.c b/src/thetvdb/grl-thetvdb.c
index 71578cc..d8e54ea 100644
--- a/src/thetvdb/grl-thetvdb.c
+++ b/src/thetvdb/grl-thetvdb.c
@@ -62,6 +62,7 @@ GRL_LOG_DOMAIN_STATIC (thetvdb_log_domain);
 #define THETVDB_STR_DELIMITER   "|"
 #define THETVDB_DEFAULT_LANG    "en"
 #define GRL_SQL_DB              "grl-thetvdb.db"
+#define GOM_DB_VERSION          3
 
 /* --- XML Fields --- */
 #define THETVDB_ID              BAD_CAST "id"
@@ -394,8 +395,9 @@ grl_thetvdb_source_init (GrlTheTVDBSource *source)
   source->priv->repository = gom_repository_new (source->priv->adapter);
   tables = g_list_prepend (NULL, GINT_TO_POINTER (SERIES_TYPE_RESOURCE));
   tables = g_list_prepend (tables, GINT_TO_POINTER (EPISODE_TYPE_RESOURCE));
-  gom_repository_automatic_migrate_async (source->priv->repository, 2, tables,
-                                          thetvdb_migrate_db_done, source);
+  tables = g_list_prepend (tables, GINT_TO_POINTER (FUZZY_SERIES_NAMES_TYPE_RESOURCE));
+  gom_repository_automatic_migrate_async (source->priv->repository, GOM_DB_VERSION,
+                                          tables, thetvdb_migrate_db_done, source);
 }
 
 G_DEFINE_TYPE (GrlTheTVDBSource, grl_thetvdb_source, GRL_TYPE_SOURCE);
@@ -641,15 +643,38 @@ xml_parse_get_series_id (xmlDocPtr doc)
   return series_id;
 }
 
+static void
+cache_save_fuzzy_series_names (GomRepository *repository,
+                               const gchar *fuzzy_name,
+                               const gchar *series_id)
+{
+  GError *error = NULL;
+  FuzzySeriesNamesResource *fsres =
+    g_object_new (FUZZY_SERIES_NAMES_TYPE_RESOURCE,
+                  "repository", repository,
+                  FUZZY_SERIES_NAMES_COLUMN_FUZZY_NAME, fuzzy_name,
+                  FUZZY_SERIES_NAMES_COLUMN_SERIES_ID, series_id,
+                  NULL);
+  gom_resource_save_sync (GOM_RESOURCE (fsres), &error);
+  if (error != NULL) {
+    GRL_DEBUG ("Failed to store fuzzy series name '%s' due %s",
+               fuzzy_name, error->message);
+    g_error_free (error);
+  }
+  g_object_unref (fsres);
+}
+
 static SeriesResource *
 xml_parse_and_save_serie (GomRepository *repository,
-                          xmlDocPtr doc)
+                          xmlDocPtr doc,
+                          const gchar *requested_show)
 {
   xmlNodePtr node;
   xmlChar *node_data = NULL;
   SeriesResource *sres;
   GError *error = NULL;
   gchar *show = NULL;
+  gchar *series_id = NULL;
 
   sres = g_object_new (SERIES_TYPE_RESOURCE,
                        "repository", repository,
@@ -705,6 +730,7 @@ xml_parse_and_save_serie (GomRepository *repository,
     } else if (xmlStrcmp (node->name, THETVDB_ID) == 0) {
       g_object_set (G_OBJECT (sres), SERIES_COLUMN_SERIES_ID,
                     (gchar *) node_data, NULL);
+      series_id = g_strdup ((gchar *) node_data);
 
     } else if (xmlStrcmp (node->name, THETVDB_BANNER) == 0) {
       gchar *str = g_strdup_printf (THETVDB_BASE_IMG, (gchar *) node_data);
@@ -737,9 +763,20 @@ xml_parse_and_save_serie (GomRepository *repository,
     GRL_DEBUG ("Failed to store series '%s' due %s",
                 show, error->message);
     g_error_free (error);
+
+  } else if (series_id != NULL) {
+    /* This is a new series to our db. Keep it on fuzzy naming db as well */
+      cache_save_fuzzy_series_names (repository, show, series_id);
+  }
+
+  if (series_id != NULL && requested_show != NULL &&
+      g_strcmp0 (show, requested_show) != 0) {
+    /* Always save the user's requested show to our fuzzy naming db */
+    cache_save_fuzzy_series_names (repository, requested_show, series_id);
   }
 
   g_clear_pointer (&show, g_free);
+  g_clear_pointer (&series_id, g_free);
   return sres;
 }
 
@@ -1194,7 +1231,8 @@ web_get_all_zipped_done (GObject *source_object,
   }
   g_free (xml_data);
 
-  sres = xml_parse_and_save_serie (tvdb_source->priv->repository, doc);
+  sres = xml_parse_and_save_serie (tvdb_source->priv->repository, doc,
+                                   grl_media_video_get_show (video));
   eres = xml_parse_and_save_episodes (tvdb_source->priv->repository, doc,
                                       grl_media_get_title (os->media),
                                       grl_media_video_get_season (video),
@@ -1459,6 +1497,65 @@ cache_find_serie_done (GObject *object,
 }
 
 static void
+cache_find_fuzzy_series_done (GObject *object,
+                              GAsyncResult *res,
+                              gpointer user_data)
+{
+  GrlTheTVDBSource *tvdb_source;
+  OperationSpec *os;
+  GomResource *resource;
+  GError *err = NULL;
+  GomFilter *query;
+  GValue value = { 0, };
+  gchar *series_id;
+
+  os = (OperationSpec *) user_data;
+  tvdb_source = GRL_THETVDB_SOURCE (os->source);
+
+  /* we are interested in the series-id */
+  resource = gom_repository_find_one_finish (GOM_REPOSITORY (object),
+                                             res,
+                                             &err);
+  if (resource == NULL)
+    goto cache_miss;
+
+  g_object_get (G_OBJECT (resource),
+                FUZZY_SERIES_NAMES_COLUMN_SERIES_ID, &series_id,
+                NULL);
+  g_object_unref (resource);
+
+  /* Get series async */
+  g_value_init (&value, G_TYPE_STRING);
+  g_value_set_string (&value, series_id);
+  g_free (series_id);
+  query = gom_filter_new_like (SERIES_TYPE_RESOURCE,
+                               SERIES_COLUMN_SERIES_ID,
+                               &value);
+  g_value_unset (&value);
+  gom_repository_find_one_async (tvdb_source->priv->repository,
+                                 SERIES_TYPE_RESOURCE,
+                                 query,
+                                 cache_find_serie_done,
+                                 os);
+  g_object_unref (query);
+  return;
+
+cache_miss:
+  if (err != NULL) {
+    const gchar *show = grl_media_video_get_show (GRL_MEDIA_VIDEO (os->media));
+    GRL_DEBUG ("[Series] Cache miss with '%s' due '%s'", show, err->message);
+    g_error_free (err);
+  }
+
+  if (os->cache_only == FALSE) {
+    thetvdb_execute_resolve_web (os);
+  } else {
+    os->callback (os->source, os->operation_id, os->media, os->user_data, NULL);
+    free_operation_spec (os);
+  }
+}
+
+static void
 thetvdb_execute_resolve_cache (OperationSpec *os)
 {
   const gchar *show;
@@ -1474,14 +1571,14 @@ thetvdb_execute_resolve_cache (OperationSpec *os)
   /* Get series async */
   g_value_init (&value, G_TYPE_STRING);
   g_value_set_string (&value, show);
-  query = gom_filter_new_like (SERIES_TYPE_RESOURCE,
-                               SERIES_COLUMN_SERIES_NAME,
+  query = gom_filter_new_like (FUZZY_SERIES_NAMES_TYPE_RESOURCE,
+                               FUZZY_SERIES_NAMES_COLUMN_FUZZY_NAME,
                                &value);
   g_value_unset (&value);
   gom_repository_find_one_async (tvdb_source->priv->repository,
-                                 SERIES_TYPE_RESOURCE,
+                                 FUZZY_SERIES_NAMES_TYPE_RESOURCE,
                                  query,
-                                 cache_find_serie_done,
+                                 cache_find_fuzzy_series_done,
                                  os);
   g_object_unref (query);
 }
diff --git a/src/thetvdb/thetvdb-resources-fuzzy-names.c b/src/thetvdb/thetvdb-resources-fuzzy-names.c
new file mode 100644
index 0000000..809c24d
--- /dev/null
+++ b/src/thetvdb/thetvdb-resources-fuzzy-names.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 Victor Toso.
+ *
+ * Contact: Victor Toso <me victortoso com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "thetvdb-resources.h"
+
+G_DEFINE_TYPE (FuzzySeriesNamesResource, fuzzy_series_names_resource, GOM_TYPE_RESOURCE)
+
+struct _FuzzySeriesNamesResourcePrivate {
+  gint64      db_id;
+  gchar      *series_id;
+  gchar      *fuzzy_name;
+};
+
+enum {
+  PROP_0,
+  PROP_DB_ID,
+  PROP_SERIES_ID,
+  PROP_FUZZY_NAME,
+  LAST_PROP
+};
+
+static GParamSpec *specs[LAST_PROP];
+
+static void
+fuzzy_series_names_resource_finalize (GObject *object)
+{
+  FuzzySeriesNamesResourcePrivate *priv = FUZZY_SERIES_NAMES_RESOURCE(object)->priv;
+
+  g_clear_pointer (&priv->series_id, g_free);
+  g_clear_pointer (&priv->fuzzy_name, g_free);
+
+  G_OBJECT_CLASS(fuzzy_series_names_resource_parent_class)->finalize(object);
+}
+
+static void
+fuzzy_series_names_resource_get_property (GObject    *object,
+                                          guint       prop_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  FuzzySeriesNamesResource *resource = FUZZY_SERIES_NAMES_RESOURCE(object);
+
+  switch (prop_id) {
+  case PROP_DB_ID:
+    g_value_set_int64 (value, resource->priv->db_id);
+    break;
+  case PROP_SERIES_ID:
+    g_value_set_string (value, resource->priv->series_id);
+    break;
+  case PROP_FUZZY_NAME:
+    g_value_set_string (value, resource->priv->fuzzy_name);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+  }
+}
+
+static void
+fuzzy_series_names_resource_set_property (GObject      *object,
+                                          guint         prop_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  FuzzySeriesNamesResource *resource = FUZZY_SERIES_NAMES_RESOURCE(object);
+
+  switch (prop_id) {
+  case PROP_DB_ID:
+    resource->priv->db_id = g_value_get_int64 (value);
+    break;
+  case PROP_SERIES_ID:
+    g_clear_pointer (&resource->priv->series_id, g_free);
+    resource->priv->series_id = g_value_dup_string (value);
+    break;
+  case PROP_FUZZY_NAME:
+    g_clear_pointer (&resource->priv->fuzzy_name, g_free);
+    resource->priv->fuzzy_name = g_value_dup_string (value);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+  }
+}
+
+static void
+fuzzy_series_names_resource_class_init (FuzzySeriesNamesResourceClass *klass)
+{
+  GObjectClass *object_class;
+  GomResourceClass *resource_class;
+
+  object_class = G_OBJECT_CLASS(klass);
+  object_class->finalize = fuzzy_series_names_resource_finalize;
+  object_class->get_property = fuzzy_series_names_resource_get_property;
+  object_class->set_property = fuzzy_series_names_resource_set_property;
+  g_type_class_add_private(object_class, sizeof(FuzzySeriesNamesResourcePrivate));
+
+  resource_class = GOM_RESOURCE_CLASS(klass);
+  gom_resource_class_set_table(resource_class, FUZZY_SERIES_NAMES_TABLE_NAME);
+
+  specs[PROP_DB_ID] = g_param_spec_int64 (FUZZY_SERIES_NAMES_COLUMN_ID,
+                                          NULL, NULL,
+                                          0, G_MAXINT64,
+                                          0, G_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_DB_ID,
+                                   specs[PROP_DB_ID]);
+  gom_resource_class_set_primary_key (resource_class, FUZZY_SERIES_NAMES_COLUMN_ID);
+  gom_resource_class_set_property_new_in_version (resource_class,
+                                                  FUZZY_SERIES_NAMES_COLUMN_ID,
+                                                  3);
+
+  specs[PROP_FUZZY_NAME] = g_param_spec_string (FUZZY_SERIES_NAMES_COLUMN_FUZZY_NAME,
+                                                 NULL, NULL, NULL,
+                                                 G_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_FUZZY_NAME,
+                                   specs[PROP_FUZZY_NAME]);
+  gom_resource_class_set_property_new_in_version (resource_class,
+                                                  FUZZY_SERIES_NAMES_COLUMN_FUZZY_NAME,
+                                                  3);
+
+  specs[PROP_SERIES_ID] = g_param_spec_string (FUZZY_SERIES_NAMES_COLUMN_SERIES_ID,
+                                               NULL, NULL, NULL,
+                                               G_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_SERIES_ID,
+                                   specs[PROP_SERIES_ID]);
+  gom_resource_class_set_reference (resource_class, FUZZY_SERIES_NAMES_COLUMN_SERIES_ID,
+                                    SERIES_TABLE_NAME, SERIES_COLUMN_SERIES_ID);
+  gom_resource_class_set_property_new_in_version (resource_class,
+                                                  FUZZY_SERIES_NAMES_COLUMN_SERIES_ID,
+                                                  3);
+}
+
+static void
+fuzzy_series_names_resource_init (FuzzySeriesNamesResource *resource)
+{
+  resource->priv = G_TYPE_INSTANCE_GET_PRIVATE(resource,
+                                               FUZZY_SERIES_NAMES_TYPE_RESOURCE,
+                                               FuzzySeriesNamesResourcePrivate);
+}
diff --git a/src/thetvdb/thetvdb-resources.h b/src/thetvdb/thetvdb-resources.h
index 8631853..3581ee0 100644
--- a/src/thetvdb/thetvdb-resources.h
+++ b/src/thetvdb/thetvdb-resources.h
@@ -154,4 +154,56 @@ struct _EpisodeResourceClass
 
 GType episode_resource_get_type (void);
 
+/*----- Series Fuzzy Names ----- */
+#define FUZZY_SERIES_NAMES_TYPE_RESOURCE   \
+  (fuzzy_series_names_resource_get_type())
+
+#define FUZZY_SERIES_NAMES_TYPE_TYPE  \
+  (fuzzy_series_names_type_get_type())
+
+#define FUZZY_SERIES_NAMES_RESOURCE(obj)                         \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                            \
+                               FUZZY_SERIES_NAMES_TYPE_RESOURCE, \
+                               FuzzySeriesNamesResource))
+
+#define FUZZY_SERIES_NAMES_RESOURCE_CLASS(klass)              \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                          \
+                            FUZZY_SERIES_NAMES_TYPE_RESOURCE, \
+                            FuzzySeriesNamesResourceClass))
+
+#define FUZZY_SERIES_NAMES_IS_RESOURCE(obj)                       \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                             \
+                               FUZZY_SERIES_NAMES_TYPE_RESOURCE))
+
+#define FUZZY_SERIES_NAMES_IS_RESOURCE_CLASS(klass)             \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass),                            \
+                            FUZZY_SERIES_NAMES_TYPE_RESOURCE))
+
+#define FUZZY_SERIES_NAMES_RESOURCE_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                            \
+                              FUZZY_SERIES_NAMES_TYPE_RESOURCE, \
+                              FuzzySeriesNamesResourceClass))
+
+#define FUZZY_SERIES_NAMES_TABLE_NAME           "fuzzy_series_names"
+#define FUZZY_SERIES_NAMES_COLUMN_ID            "id"
+#define FUZZY_SERIES_NAMES_COLUMN_SERIES_ID     "tvdb-series-id"
+#define FUZZY_SERIES_NAMES_COLUMN_FUZZY_NAME    "fuzzy-name"
+
+typedef struct _FuzzySeriesNamesResource        FuzzySeriesNamesResource;
+typedef struct _FuzzySeriesNamesResourceClass   FuzzySeriesNamesResourceClass;
+typedef struct _FuzzySeriesNamesResourcePrivate FuzzySeriesNamesResourcePrivate;
+
+struct _FuzzySeriesNamesResource
+{
+   GomResource parent;
+   FuzzySeriesNamesResourcePrivate *priv;
+};
+
+struct _FuzzySeriesNamesResourceClass
+{
+   GomResourceClass parent_class;
+};
+
+GType fuzzy_series_names_resource_get_type (void);
+
 #endif /* _GRL_THETVDB_RESOURCES_H_ */


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