[grilo-plugins] tracker: Add Tracker plugin



commit 772d4b5ef9393deb1588ecf1b5b7eca43903e9b7
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Wed Jan 12 10:44:24 2011 +0000

    tracker: Add Tracker plugin
    
    Plugin that searches multimedia content using Tracker.
    
    This first version implements the query function. A query must be a sparql
    query that Tracker can understand.
    
    In order to make possible to map Tracker results to Grilo, all columns must be
    named with the name of metadata key, and must include a column telling the type
    of result returning. More information in grilo_tracker_source_query() function.
    
    Signed-off-by: Juan A. Suarez Romero <jasuarez igalia com>

 configure.ac                |   42 +++++-
 src/Makefile.am             |   16 ++-
 src/tracker/Makefile.am     |   36 ++++
 src/tracker/grl-tracker.c   |  395 +++++++++++++++++++++++++++++++++++++++++++
 src/tracker/grl-tracker.h   |   78 +++++++++
 src/tracker/grl-tracker.xml |    9 +
 6 files changed, 570 insertions(+), 6 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 31128b0..ba91484 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@
 # 
 # Author: Iago Toral Quiroga <itoral igalia com>
 #
-# Copyright (C) 2010 Igalia S.L.. All rights reserved.
+# Copyright (C) 2010, 2011 Igalia S.L.. All rights reserved.
 
 m4_define([prj_name],    [grilo-plugins])
 m4_define([prj_version], [0.1.7])
@@ -120,6 +120,10 @@ AC_CHECK_HEADER([gcrypt.h], HAVE_GCRYPT=yes, HAVE_GCRYPT=no)
 
 PKG_CHECK_MODULES(GTHREAD, gthread-2.0, HAVE_GTHREAD=yes, HAVE_GTHREAD=no)
 
+PKG_CHECK_MODULES(TRACKER_SPARQL, tracker-sparql-0.9,
+                                  HAVE_TRACKER_SPARQL=yes,
+                                  HAVE_TRACKER_SPARQL=no)
+
 # ----------------------------------------------------------
 # GUPNP-AV VERSION
 # ----------------------------------------------------------
@@ -660,6 +664,41 @@ AC_SUBST(GRAVATAR_PLUGIN_ID)
 AC_DEFINE_UNQUOTED([GRAVATAR_PLUGIN_ID], ["$GRAVATAR_PLUGIN_ID"], [Gravatar plugin ID])
 
 # ----------------------------------------------------------
+# BUILD TRACKER PLUGIN
+# ----------------------------------------------------------
+
+AC_ARG_ENABLE(tracker,
+        AC_HELP_STRING([--enable-tracker],
+                [enable Tracker plugin (default: auto)]),
+        [
+                case "$enableval" in
+                     yes)
+                        if test "x$HAVE_TRACKER_SPARQL" = "xno"; then
+                           AC_MSG_ERROR([tracker-sparql-0.9 not found, install it or use --disable-tracker])
+                        fi
+                        ;;
+                esac
+        ],
+        [
+                if test "x$HAVE_TRACKER_SPARQL" = "xyes"; then
+                   enable_tracker=yes
+                else
+                   enable_tracker=no
+                fi
+        ])
+
+AM_CONDITIONAL([TRACKER_PLUGIN], [test "x$enable_tracker" = "xyes"])
+GRL_PLUGINS_ALL="$GRL_PLUGINS_ALL tracker"
+if test "x$enable_tracker" = "xyes"
+then
+	GRL_PLUGINS_ENABLED="$GRL_PLUGINS_ENABLED tracker"
+fi
+
+TRACKER_PLUGIN_ID="grl-tracker"
+AC_SUBST(TRACKER_PLUGIN_ID)
+AC_DEFINE_UNQUOTED([TRACKER_PLUGIN_ID], ["$TRACKER_PLUGIN_ID"], [Tracker plugin ID])
+
+# ----------------------------------------------------------
 # GETTEXT
 # ----------------------------------------------------------
 
@@ -697,6 +736,7 @@ AC_CONFIG_FILES([
   src/metadata-store/Makefile
   src/vimeo/Makefile
   src/gravatar/Makefile
+  src/tracker/Makefile
   test/Makefile
 ])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 72ac7cd..11b9cf4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,7 +3,7 @@
 #
 # Author: Iago Toral Quiroga <itoral igalia com>
 #
-# Copyright (C) 2010 Igalia S.L. All rights reserved.
+# Copyright (C) 2010, 2011 Igalia S.L. All rights reserved.
 
 SUBDIRS =
 
@@ -63,11 +63,17 @@ if GRAVATAR_PLUGIN
 SUBDIRS += gravatar
 endif
 
-DIST_SUBDIRS = youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr podcasts bookmarks shoutcast apple-trailers metadata-store vimeo gravatar
+if TRACKER_PLUGIN
+SUBDIRS += tracker
+endif
+
+DIST_SUBDIRS =									\
+	youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr	\
+	podcasts bookmarks shoutcast apple-trailers metadata-store vimeo	\
+	gravatar tracker
 
-MAINTAINERCLEANFILES = \
-        *.in \
+MAINTAINERCLEANFILES =	\
+        *.in		\
         *~
 
 DISTCLEANFILES = $(MAINTAINERCLEANFILES)
-
diff --git a/src/tracker/Makefile.am b/src/tracker/Makefile.am
new file mode 100644
index 0000000..5510f5a
--- /dev/null
+++ b/src/tracker/Makefile.am
@@ -0,0 +1,36 @@
+#
+# Makefile.am
+#
+# Author: Juan A. Suarez Romero <jasuarez igalia com>
+#
+# Copyright (C) 2011 Igalia S.L. All rights reserved.
+
+lib_LTLIBRARIES		 = libgrltracker.la
+
+libgrltracker_la_CFLAGS =	\
+	$(DEPS_CFLAGS)		\
+	$(TRACKER_SPARQL_CFLAGS)
+
+libgrltracker_la_LIBADD =	\
+	$(DEPS_LIBS)		\
+	$(TRACKER_SPARQL_LIBS)
+
+libgrltracker_la_LDFLAGS = \
+	-module		   \
+	-avoid-version
+
+libgrltracker_la_SOURCES = 	\
+	grl-tracker.c 		\
+	grl-tracker.h
+
+libdir = $(GRL_PLUGINS_DIR)
+trackerxmldir = $(GRL_PLUGINS_CONF_DIR)
+trackerxml_DATA	= $(TRACKER_PLUGIN_ID).xml
+
+EXTRA_DIST = $(trackerxml_DATA)
+
+MAINTAINERCLEANFILES =	\
+	*.in		\
+	*~
+
+DISTCLEANFILES = $(MAINTAINERCLEANFILES)
diff --git a/src/tracker/grl-tracker.c b/src/tracker/grl-tracker.c
new file mode 100644
index 0000000..cc5db70
--- /dev/null
+++ b/src/tracker/grl-tracker.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Juan A. Suarez Romero <jasuarez igalia 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <grilo.h>
+#include <string.h>
+#include <tracker-sparql.h>
+
+#include "grl-tracker.h"
+
+/* --------- Logging  -------- */
+
+#define GRL_LOG_DOMAIN_DEFAULT tracker_log_domain
+GRL_LOG_DOMAIN_STATIC(tracker_log_domain);
+
+/* ------- Definitions ------- */
+
+#define MEDIA_TYPE "grilo-media-type"
+
+#define RDF_TYPE_ALBUM  "nmm#MusicAlbum"
+#define RDF_TYPE_ARTIST "nmm#Artist"
+#define RDF_TYPE_AUDIO  "nmm#MusicPiece"
+#define RDF_TYPE_IMAGE  "nmm#Photo"
+#define RDF_TYPE_VIDEO  "nmm#Video"
+#define RDF_TYPE_BOX    "grilo#Box"
+
+/* ---- Plugin information --- */
+
+#define PLUGIN_ID   TRACKER_PLUGIN_ID
+
+#define SOURCE_ID   "grl-tracker"
+#define SOURCE_NAME "Tracker"
+#define SOURCE_DESC "A plugin for searching multimedia content using Tracker"
+
+#define AUTHOR      "Igalia S.L."
+#define LICENSE     "LGPL"
+#define SITE        "http://www.igalia.com";
+
+enum {
+  METADATA,
+  BROWSE,
+  QUERY,
+  SEARCH
+};
+
+struct _GrlTrackerSourcePriv {
+  TrackerSparqlConnection *tracker_connection;
+};
+
+#define GRL_TRACKER_SOURCE_GET_PRIVATE(object)		\
+  (G_TYPE_INSTANCE_GET_PRIVATE((object),                \
+                               GRL_TRACKER_SOURCE_TYPE,	\
+                               GrlTrackerSourcePriv))
+
+static GrlTrackerSource *grl_tracker_source_new (void);
+
+gboolean grl_tracker_plugin_init (GrlPluginRegistry *registry,
+                                  const GrlPluginInfo *plugin,
+                                  GList *configs);
+
+static const GList *grl_tracker_source_supported_keys (GrlMetadataSource *source);
+
+
+static void grl_tracker_source_query (GrlMediaSource *source,
+                                      GrlMediaSourceQuerySpec *qs);
+
+
+/* =================== Tracker Plugin  =============== */
+
+gboolean
+grl_tracker_plugin_init (GrlPluginRegistry *registry,
+                         const GrlPluginInfo *plugin,
+                         GList *configs)
+{
+  GRL_LOG_DOMAIN_INIT (tracker_log_domain, "tracker");
+
+  GRL_DEBUG ("tracker_plugin_init");
+
+  GrlTrackerSource *source = grl_tracker_source_new ();
+  grl_plugin_registry_register_source (registry,
+                                       plugin,
+                                       GRL_MEDIA_PLUGIN (source),
+                                       NULL);
+  return TRUE;
+}
+
+GRL_PLUGIN_REGISTER (grl_tracker_plugin_init,
+                     NULL,
+                     PLUGIN_ID);
+
+/* ================== Tracker GObject ================ */
+
+static GrlTrackerSource *
+grl_tracker_source_new (void)
+{
+  GError *error = NULL;
+  GrlTrackerSource *source;
+  TrackerSparqlConnection *connection;
+
+  GRL_DEBUG ("grl_tracker_source_new");
+
+  connection = tracker_sparql_connection_get_direct (NULL, &error);
+  if (!connection) {
+    GRL_WARNING ("Failed to get Tracker connection: %s", error->message);
+    return NULL;
+  }
+
+  source =  g_object_new (GRL_TRACKER_SOURCE_TYPE,
+                          "source-id", SOURCE_ID,
+                          "source-name", SOURCE_NAME,
+                          "source-desc", SOURCE_DESC,
+                          NULL);
+  source->priv->tracker_connection = connection;
+
+  return source;
+}
+
+G_DEFINE_TYPE (GrlTrackerSource, grl_tracker_source, GRL_TYPE_MEDIA_SOURCE);
+
+static void
+grl_tracker_source_finalize (GObject *object)
+{
+  GrlTrackerSource *self;
+
+  self = GRL_TRACKER_SOURCE (object);
+  if (self->priv->tracker_connection) {
+    g_object_unref (self->priv->tracker_connection);
+  }
+
+  G_OBJECT_CLASS (grl_tracker_source_parent_class)->finalize (object);
+}
+
+static void
+grl_tracker_source_class_init (GrlTrackerSourceClass * klass)
+{
+  GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass);
+  GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass);
+  GObjectClass *g_class = G_OBJECT_CLASS (klass);
+  source_class->query = grl_tracker_source_query;
+  metadata_class->supported_keys = grl_tracker_source_supported_keys;
+  g_class->finalize = grl_tracker_source_finalize;
+
+  g_type_class_add_private (klass, sizeof (GrlTrackerSourcePriv));
+}
+
+static void
+grl_tracker_source_init (GrlTrackerSource *source)
+{
+  source->priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
+}
+
+/* ======================= Utilities ==================== */
+
+/* Builds an appropriate GrlMedia based on ontology type returned by tracker, or
+   NULL if unknown */
+static GrlMedia *
+build_grilo_media (const gchar *rdf_type)
+{
+  GrlMedia *media = NULL;
+  gchar **rdf_single_type;
+  int i;
+
+  if (!rdf_type) {
+    return NULL;
+  }
+
+  /* As rdf_type can be formed by several types, split them */
+  rdf_single_type = g_strsplit (rdf_type, ",", -1);
+  i = g_strv_length (rdf_single_type);
+
+  while (!media && i > 0) {
+    if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_AUDIO)) {
+      media = grl_media_audio_new ();
+    } else if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_VIDEO)) {
+      media = grl_media_video_new ();
+    } else if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_IMAGE)) {
+      media = grl_media_image_new ();
+    } else if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_ARTIST)) {
+      media = grl_media_box_new ();
+    } else if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_ALBUM)) {
+      media = grl_media_box_new ();
+    } else if (g_str_has_suffix (rdf_single_type[i], RDF_TYPE_BOX)) {
+      media = grl_media_box_new ();
+    }
+    i--;
+  }
+
+  g_strfreev (rdf_single_type);
+
+  return media;
+}
+
+/* ================== API Implementation ================ */
+
+static const GList *
+grl_tracker_source_supported_keys (GrlMetadataSource *source)
+{
+  static GList *keys = NULL;
+
+  if (!keys) {
+    keys = grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
+                                      GRL_METADATA_KEY_TITLE,
+                                      GRL_METADATA_KEY_URL,
+                                      NULL);
+  }
+  return keys;
+}
+
+/**
+ * Query is a SPARQL query.
+ *
+ * Columns must be named with the Grilo key name that the column
+ * represent. Unnamed or unknown columns will be ignored.
+ *
+ * For the case of media type, name to be used is "grilo-media-type". This is a
+ * mandatory column. It must match with rdf:type() property. Types understood
+ * are:
+ *
+ * <itemizedlist>
+ *   <listitem>
+ *     <para>
+ *       <literal>nmm#MusicPiece</literal>
+ *     </para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>
+ *       <literal>nmm#Video</literal>
+ *     </para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>
+ *       <literal>nmm#Photo</literal>
+ *     </para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>
+ *       <literal>nmm#Artist</literal>
+ *     </para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>
+ *       <literal>nmm#MusicAlbum</literal>
+ *     </para>
+ *   </listitem>
+ *   <listitem>
+ *     <para>
+ *       <literal>grilo#Box</literal>
+ *     </para>
+ *   </listitem>
+ * </itemizedlist>
+ *
+ * An example for searching all songs:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *     SELECT rdf:type(?song)  AS grilo-media-type
+ *            ?song            AS id
+ *            nie:title(?song) AS title
+ *            nie:url(?song)   AS url
+ *     WHERE { ?song a nmm:MusicPiece }
+ *   </programlisting>
+ * </informalexample>
+ */
+static void
+grl_tracker_source_query (GrlMediaSource *source,
+                          GrlMediaSourceQuerySpec *qs)
+{
+  GError *error = NULL;
+  GError *tracker_error = NULL;
+  GrlKeyID key;
+  GrlMedia *media;
+  TrackerSparqlCursor *cursor;
+  const gchar *key_name = NULL;
+  int i;
+  int n_columns;
+  int type_column;
+
+  GRL_DEBUG ("grl_tracker_source_query");
+
+  if (!qs->query || qs->query[0] == '\0') {
+    error = g_error_new_literal (GRL_CORE_ERROR,
+                                 GRL_CORE_ERROR_QUERY_FAILED,
+                                 "Empty query");
+    goto send_error;
+  }
+
+  cursor =
+    tracker_sparql_connection_query (GRL_TRACKER_SOURCE (source)->priv->tracker_connection,
+                                     qs->query,
+                                     NULL,
+                                     &tracker_error);
+  if (!cursor) {
+    error = g_error_new (GRL_CORE_ERROR,
+                         GRL_CORE_ERROR_QUERY_FAILED,
+                         "Query failed: %s",
+                         tracker_error->message);
+    goto send_error;
+  }
+
+  while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
+      n_columns = tracker_sparql_cursor_get_n_columns (cursor);
+      /* Search column with type */
+      for (type_column = 0; type_column < n_columns; i++) {
+        if (strcmp (tracker_sparql_cursor_get_variable_name (cursor,
+                                                             type_column),
+                    MEDIA_TYPE) == 0) {
+          break;
+        }
+      }
+
+      /* type not found */
+      if (type_column >= n_columns) {
+        continue;
+      }
+
+      media = build_grilo_media (tracker_sparql_cursor_get_string (cursor,
+                                                                   type_column,
+                                                                   NULL));
+      /* Unknown media */
+      if (!media) {
+        continue;
+      }
+
+      /* Fill data */
+      for (i = 0; i < n_columns; i++) {
+        /* Skip type */
+        if (i == type_column) {
+          continue;
+        }
+
+        /* Column has no value */
+        if (!tracker_sparql_cursor_is_bound (cursor, i)) {
+          continue;
+        }
+
+        key_name = tracker_sparql_cursor_get_variable_name (cursor, i);
+
+        /* Unnamed column */
+        if (!key_name) {
+          continue;
+        }
+
+        key = grl_plugin_registry_lookup_metadata_key (grl_plugin_registry_get_default (),
+                                                       key_name);
+        /* Unknown key */
+        if (!key) {
+          continue;
+        }
+
+        grl_data_set_string (GRL_DATA (media),
+                             key,
+                             tracker_sparql_cursor_get_string (cursor,
+                                                               i,
+                                                               NULL));
+      }
+
+      /* Send data */
+      qs->callback (qs->source, qs->query_id, media, -1, qs->user_data, NULL);
+  }
+
+  /* Notify there is no more elements */
+  qs->callback (qs->source, qs->query_id, NULL, 0, qs->user_data, NULL);
+
+  g_object_unref (cursor);
+
+  return;
+
+ send_error:
+  qs->callback (qs->source, qs->query_id, NULL, 0, qs->user_data, error);
+  g_error_free (error);
+}
diff --git a/src/tracker/grl-tracker.h b/src/tracker/grl-tracker.h
new file mode 100644
index 0000000..b0130ef
--- /dev/null
+++ b/src/tracker/grl-tracker.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Juan A. Suarez Romero <jasuarez igalia 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
+ *
+ */
+
+#ifndef _GRL_TRACKER_SOURCE_H_
+#define _GRL_TRACKER_SOURCE_H_
+
+#include <grilo.h>
+
+#define GRL_TRACKER_SOURCE_TYPE                 \
+  (grl_tracker_source_get_type ())
+
+#define GRL_TRACKER_SOURCE(obj)                         \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                   \
+                               GRL_TRACKER_SOURCE_TYPE, \
+                               GrlTrackerSource))
+
+#define GRL_IS_TRACKER_SOURCE(obj)                              \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                           \
+                               GRL_TRACKER_SOURCE_TYPE))
+
+#define GRL_TRACKER_SOURCE_CLASS(klass)                 \
+  (G_TYPE_CHECK_CLASS_CAST((klass),                     \
+                           GRL_TRACKER_SOURCE_TYPE,     \
+                           GrlTrackerSourceClass))
+
+#define GRL_IS_TRACKER_SOURCE_CLASS(klass)              \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),                     \
+                           GRL_TRACKER_SOURCE_TYPE))
+
+#define GRL_TRACKER_SOURCE_GET_CLASS(obj)               \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                    \
+                              GRL_TRACKER_SOURCE_TYPE,  \
+                              GrlTrackerSourceClass))
+
+typedef struct _GrlTrackerSource GrlTrackerSource;
+typedef struct _GrlTrackerSourcePriv GrlTrackerSourcePriv;
+
+struct _GrlTrackerSource {
+
+  GrlMediaSource parent;
+
+  /*< private >*/
+  GrlTrackerSourcePriv *priv;
+
+};
+
+typedef struct _GrlTrackerSourceClass GrlTrackerSourceClass;
+
+struct _GrlTrackerSourceClass {
+
+  GrlMediaSourceClass parent_class;
+
+};
+
+GType grl_tracker_source_get_type (void);
+
+#endif /* _GRL_TRACKER_SOURCE_H_ */
diff --git a/src/tracker/grl-tracker.xml b/src/tracker/grl-tracker.xml
new file mode 100644
index 0000000..20f7bb6
--- /dev/null
+++ b/src/tracker/grl-tracker.xml
@@ -0,0 +1,9 @@
+<plugin>
+  <info>
+    <name>Tracker</name>
+    <description>A plugin for searching multimedia content using Tracker</description>
+    <author>Igalia S.L.</author>
+    <license>LGPL</license>
+    <site>http://www.igalia.com</site>
+  </info>
+</plugin>



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