[PATCH 1/4] tracker: reorganize files before add metadata support



From: Lionel Landwerlin <lionel g landwerlin linux intel com>

Signed-off-by: Lionel Landwerlin <lionel g landwerlin linux intel com>
---
 src/media/tracker/Makefile.am               |   21 +-
 src/media/tracker/grl-tracker-api.c         |  840 --------------------------
 src/media/tracker/grl-tracker-api.h         |   56 --
 src/media/tracker/grl-tracker-cache.c       |  188 ------
 src/media/tracker/grl-tracker-cache.h       |   45 --
 src/media/tracker/grl-tracker-media-api.c   |  841 +++++++++++++++++++++++++++
 src/media/tracker/grl-tracker-media-api.h   |   56 ++
 src/media/tracker/grl-tracker-media-cache.c |  188 ++++++
 src/media/tracker/grl-tracker-media-cache.h |   45 ++
 src/media/tracker/grl-tracker-media-notif.c |  641 ++++++++++++++++++++
 src/media/tracker/grl-tracker-media-notif.h |   54 ++
 src/media/tracker/grl-tracker-media-priv.h  |   86 +++
 src/media/tracker/grl-tracker-media.c       |  417 +++++++++++++
 src/media/tracker/grl-tracker-media.h       |   88 +++
 src/media/tracker/grl-tracker-notif.c       |  641 --------------------
 src/media/tracker/grl-tracker-notif.h       |   54 --
 src/media/tracker/grl-tracker-priv.h        |   86 ---
 src/media/tracker/grl-tracker-utils.c       |   17 +-
 src/media/tracker/grl-tracker-utils.h       |   16 +-
 src/media/tracker/grl-tracker.c             |  416 -------------
 src/media/tracker/grl-tracker.h             |   88 ---
 21 files changed, 2443 insertions(+), 2441 deletions(-)
 delete mode 100644 src/media/tracker/grl-tracker-api.c
 delete mode 100644 src/media/tracker/grl-tracker-api.h
 delete mode 100644 src/media/tracker/grl-tracker-cache.c
 delete mode 100644 src/media/tracker/grl-tracker-cache.h
 create mode 100644 src/media/tracker/grl-tracker-media-api.c
 create mode 100644 src/media/tracker/grl-tracker-media-api.h
 create mode 100644 src/media/tracker/grl-tracker-media-cache.c
 create mode 100644 src/media/tracker/grl-tracker-media-cache.h
 create mode 100644 src/media/tracker/grl-tracker-media-notif.c
 create mode 100644 src/media/tracker/grl-tracker-media-notif.h
 create mode 100644 src/media/tracker/grl-tracker-media-priv.h
 create mode 100644 src/media/tracker/grl-tracker-media.c
 create mode 100644 src/media/tracker/grl-tracker-media.h
 delete mode 100644 src/media/tracker/grl-tracker-notif.c
 delete mode 100644 src/media/tracker/grl-tracker-notif.h
 delete mode 100644 src/media/tracker/grl-tracker-priv.h
 delete mode 100644 src/media/tracker/grl-tracker.c
 delete mode 100644 src/media/tracker/grl-tracker.h

diff --git a/src/media/tracker/Makefile.am b/src/media/tracker/Makefile.am
index 537aaa4..accacfe 100644
--- a/src/media/tracker/Makefile.am
+++ b/src/media/tracker/Makefile.am
@@ -19,16 +19,17 @@ libgrltracker_la_LDFLAGS = \
 	-module		   \
 	-avoid-version
 
-libgrltracker_la_SOURCES = 	\
-	grl-tracker.c 		\
-	grl-tracker.h		\
-	grl-tracker-api.c	\
-	grl-tracker-api.h	\
-	grl-tracker-cache.c	\
-	grl-tracker-cache.h	\
-	grl-tracker-notif.c	\
-	grl-tracker-notif.h	\
-	grl-tracker-utils.c	\
+libgrltracker_la_SOURCES = 		\
+	grl-tracker-media.c		\
+	grl-tracker-media.h		\
+	grl-tracker-media-api.c		\
+	grl-tracker-media-api.h		\
+	grl-tracker-media-cache.c	\
+	grl-tracker-media-cache.h	\
+	grl-tracker-media-notif.c	\
+	grl-tracker-media-notif.h	\
+	\
+	grl-tracker-utils.c		\
 	grl-tracker-utils.h
 
 libdir = $(GRL_PLUGINS_DIR)
diff --git a/src/media/tracker/grl-tracker-api.c b/src/media/tracker/grl-tracker-api.c
deleted file mode 100644
index a85f564..0000000
--- a/src/media/tracker/grl-tracker-api.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <gio/gio.h>
-#include <tracker-sparql.h>
-
-#include "grl-tracker-api.h"
-#include "grl-tracker-cache.h"
-#include "grl-tracker-priv.h"
-#include "grl-tracker-utils.h"
-
-/* --------- Logging  -------- */
-
-#define GRL_LOG_DOMAIN_DEFAULT tracker_request_log_domain
-
-GRL_LOG_DOMAIN_STATIC(tracker_request_log_domain);
-GRL_LOG_DOMAIN_STATIC(tracker_result_log_domain);
-
-/* Inputs/requests */
-#define GRL_IDEBUG(args...)            \
-  GRL_LOG (tracker_request_log_domain, \
-           GRL_LOG_LEVEL_DEBUG, args)
-
-/* Outputs/results */
-#define GRL_ODEBUG(args...)           \
-  GRL_LOG (tracker_result_log_domain, \
-           GRL_LOG_LEVEL_DEBUG, args)
-
-/* ------- Definitions ------- */
-
-#define TRACKER_QUERY_REQUEST                   \
-  "SELECT rdf:type(?urn) %s "                   \
-  "WHERE { %s . %s } "                          \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
-  "OFFSET %i "                                  \
-  "LIMIT %i"
-
-#define TRACKER_SEARCH_REQUEST                  \
-  "SELECT rdf:type(?urn) %s "                   \
-  "WHERE "                                      \
-  "{ "                                          \
-  "?urn a nfo:Media . "                         \
-  "?urn tracker:available ?tr . "               \
-  "?urn fts:match '*%s*' . "                    \
-  "%s "                                         \
-  "} "                                          \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
-  "OFFSET %i "                                  \
-  "LIMIT %i"
-
-#define TRACKER_SEARCH_ALL_REQUEST              \
-  "SELECT rdf:type(?urn) %s "                   \
-  "WHERE "                                      \
-  "{ "                                          \
-  "?urn a nfo:Media . "                         \
-  "?urn tracker:available ?tr . "               \
-  "%s "                                         \
-  "} "                                          \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
-  "OFFSET %i "                                  \
-  "LIMIT %i"
-
-#define TRACKER_BROWSE_CATEGORY_REQUEST         \
-  "SELECT rdf:type(?urn) %s "                   \
-  "WHERE "                                      \
-  "{ "                                          \
-  "?urn a %s . "                                \
-  "?urn tracker:available ?tr . "               \
-  "%s "                                         \
-  "} "                                          \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
-  "OFFSET %i "                                  \
-  "LIMIT %i"
-
-#define TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST          \
-  "SELECT DISTINCT rdf:type(?urn) %s "                  \
-  "WHERE "                                              \
-  "{ "                                                  \
-  "{ ?urn a nfo:Folder } UNION "                        \
-  "{ ?urn a nfo:Audio } UNION "                         \
-  "{ ?urn a nfo:Document } UNION "                      \
-  "{ ?urn a nmm:Photo } UNION "                         \
-  "{ ?urn a nmm:Video } . "                             \
-  "%s "                                                 \
-  "FILTER (!bound(nfo:belongsToContainer(?urn))) "      \
-  "} "                                                  \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "          \
-  "OFFSET %i "                                          \
-  "LIMIT %i"
-
-#define TRACKER_BROWSE_FILESYSTEM_REQUEST                       \
-  "SELECT DISTINCT rdf:type(?urn) %s "                          \
-  "WHERE "                                                      \
-  "{ "                                                          \
-  "{ ?urn a nfo:Folder } UNION "                                \
-  "{ ?urn a nfo:Audio } UNION "                                 \
-  "{ ?urn a nfo:Document } UNION "                              \
-  "{ ?urn a nmm:Photo } UNION "                                 \
-  "{ ?urn a nmm:Video } . "                                     \
-  "%s "                                                         \
-  "FILTER(tracker:id(nfo:belongsToContainer(?urn)) = %s) "      \
-  "} "                                                          \
-  "ORDER BY DESC(nfo:fileLastModified(?urn)) "                  \
-  "OFFSET %i "                                                  \
-  "LIMIT %i"
-
-#define TRACKER_METADATA_REQUEST                \
-  "SELECT %s "                                  \
-  "WHERE "                                      \
-  "{ "                                          \
-  "?urn a nie:DataObject . "                    \
-  "FILTER (tracker:id(?urn) = %s) "             \
-  "}"
-
-/**/
-
-struct OperationSpec {
-  GrlMediaSource         *source;
-  GrlTrackerSourcePriv   *priv;
-  guint                   operation_id;
-  GCancellable           *cancel_op;
-  const GList            *keys;
-  guint                   skip;
-  guint                   count;
-  guint                   current;
-  GrlMediaSourceResultCb  callback;
-  gpointer                user_data;
-  TrackerSparqlCursor    *cursor;
-};
-
-/**/
-
-static GrlKeyID grl_metadata_key_tracker_category;
-
-/**/
-
-static struct OperationSpec *
-tracker_operation_initiate (GrlMediaSource *source,
-                            GrlTrackerSourcePriv *priv,
-                            guint operation_id)
-{
-  struct OperationSpec *os = g_slice_new0 (struct OperationSpec);
-
-  os->source       = source;
-  os->priv         = priv;
-  os->operation_id = operation_id;
-  os->cancel_op    = g_cancellable_new ();
-
-  g_hash_table_insert (priv->operations, GSIZE_TO_POINTER (operation_id), os);
-
-  return os;
-}
-
-static void
-tracker_operation_terminate (struct OperationSpec *os)
-{
-  if (os == NULL)
-    return;
-
-  g_hash_table_remove (os->priv->operations,
-                       GSIZE_TO_POINTER (os->operation_id));
-
-  g_object_unref (G_OBJECT (os->cursor));
-  g_object_unref (G_OBJECT (os->cancel_op));
-  g_slice_free (struct OperationSpec, os);
-}
-
-static void
-fill_grilo_media_from_sparql (GrlTrackerSource    *source,
-                              GrlMedia            *media,
-                              TrackerSparqlCursor *cursor,
-                              gint                 column)
-{
-  const gchar *sparql_key = tracker_sparql_cursor_get_variable_name (cursor,
-                                                                     column);
-  tracker_grl_sparql_t *assoc =
-    grl_tracker_get_mapping_from_sparql (sparql_key);
-  union {
-    gint int_val;
-    gdouble double_val;
-    const gchar *str_val;
-  } val;
-
-  if (assoc == NULL)
-    return;
-
-  GRL_ODEBUG ("\tSetting media prop (col=%i/var=%s/prop=%s) %s",
-              column,
-              sparql_key,
-              g_param_spec_get_name (G_PARAM_SPEC (assoc->grl_key)),
-              tracker_sparql_cursor_get_string (cursor, column, NULL));
-
-  if (tracker_sparql_cursor_is_bound (cursor, column) == FALSE) {
-    GRL_ODEBUG ("\t\tDropping, no data");
-    return;
-  }
-
-  if (grl_data_key_is_known (GRL_DATA (media), assoc->grl_key)) {
-    GRL_ODEBUG ("\t\tDropping, already here");
-    return;
-  }
-
-  switch (G_PARAM_SPEC (assoc->grl_key)->value_type) {
-  case G_TYPE_STRING:
-    /* Cache the source associated to this result. */
-    if (assoc->grl_key == GRL_METADATA_KEY_ID) {
-      grl_tracker_cache_add_item (grl_tracker_item_cache,
-                                  tracker_sparql_cursor_get_integer (cursor, column),
-                                  source);
-    }
-    val.str_val = tracker_sparql_cursor_get_string (cursor, column, NULL);
-    if (val.str_val != NULL)
-      grl_data_set_string (GRL_DATA (media), assoc->grl_key, val.str_val);
-    break;
-
-  case G_TYPE_INT:
-    val.int_val = tracker_sparql_cursor_get_integer (cursor, column);
-    grl_data_set_int (GRL_DATA (media), assoc->grl_key, val.int_val);
-    break;
-
-  case G_TYPE_FLOAT:
-    val.double_val = tracker_sparql_cursor_get_double (cursor, column);
-    grl_data_set_float (GRL_DATA (media), assoc->grl_key, (gfloat) val.double_val);
-    break;
-
-  default:
-    GRL_ODEBUG ("\t\tUnexpected data type");
-    break;
-  }
-}
-
-static void
-tracker_query_result_cb (GObject              *source_object,
-                         GAsyncResult         *result,
-                         struct OperationSpec *operation)
-{
-  gint         col;
-  const gchar *sparql_type;
-  GError      *tracker_error = NULL, *error = NULL;
-  GrlMedia    *media;
-
-  GRL_ODEBUG ("%s", __FUNCTION__);
-
-  if (g_cancellable_is_cancelled (operation->cancel_op)) {
-    GRL_ODEBUG ("\tOperation %u cancelled", operation->operation_id);
-    operation->callback (operation->source,
-                         operation->operation_id,
-                         NULL, 0,
-                         operation->user_data, NULL);
-    tracker_operation_terminate (operation);
-
-    return;
-  }
-
-  if (!tracker_sparql_cursor_next_finish (operation->cursor,
-                                          result,
-                                          &tracker_error)) {
-    if (tracker_error != NULL) {
-      GRL_ODEBUG ("\terror in parsing query id=%u : %s",
-                  operation->operation_id, tracker_error->message);
-
-      error = g_error_new (GRL_CORE_ERROR,
-                           GRL_CORE_ERROR_BROWSE_FAILED,
-                           "Failed to start browse/query action : %s",
-                           tracker_error->message);
-
-      operation->callback (operation->source,
-                           operation->operation_id,
-                           NULL, 0,
-                           operation->user_data, error);
-
-      g_error_free (error);
-      g_error_free (tracker_error);
-    } else {
-      GRL_ODEBUG ("\tend of parsing id=%u :)", operation->operation_id);
-
-      /* Only emit this last one if more result than expected */
-      if (operation->count > 1)
-        operation->callback (operation->source,
-                             operation->operation_id,
-                             NULL, 0,
-                             operation->user_data, NULL);
-    }
-
-    tracker_operation_terminate (operation);
-    return;
-  }
-
-  sparql_type = tracker_sparql_cursor_get_string (operation->cursor, 0, NULL);
-
-  GRL_ODEBUG ("\tParsing line %i of type %s", operation->current, sparql_type);
-
-  media = grl_tracker_build_grilo_media (sparql_type);
-
-  if (media != NULL) {
-    for (col = 1 ;
-         col < tracker_sparql_cursor_get_n_columns (operation->cursor) ;
-         col++) {
-      fill_grilo_media_from_sparql (GRL_TRACKER_SOURCE (operation->source),
-                                    media, operation->cursor, col);
-    }
-
-    operation->callback (operation->source,
-                         operation->operation_id,
-                         media,
-                         --operation->count,
-                         operation->user_data,
-                         NULL);
-  }
-
-  /* Schedule the next line to parse */
-  operation->current++;
-  if (operation->count < 1)
-    tracker_operation_terminate (operation);
-  else
-    tracker_sparql_cursor_next_async (operation->cursor, operation->cancel_op,
-                                      (GAsyncReadyCallback) tracker_query_result_cb,
-                                      (gpointer) operation);
-}
-
-static void
-tracker_query_cb (GObject              *source_object,
-                  GAsyncResult         *result,
-                  struct OperationSpec *operation)
-{
-  GError *tracker_error = NULL, *error = NULL;
-
-  GRL_ODEBUG ("%s", __FUNCTION__);
-
-  operation->cursor =
-    tracker_sparql_connection_query_finish (operation->priv->tracker_connection,
-                                            result, &tracker_error);
-
-  if (tracker_error) {
-    GRL_WARNING ("Could not execute sparql query id=%u: %s",
-                 operation->operation_id, tracker_error->message);
-
-    error = g_error_new (GRL_CORE_ERROR,
-			 GRL_CORE_ERROR_BROWSE_FAILED,
-			 "Failed to start browse/query action : %s",
-                         tracker_error->message);
-
-    operation->callback (operation->source, operation->operation_id, NULL, 0,
-                         operation->user_data, error);
-
-    g_error_free (tracker_error);
-    g_error_free (error);
-    g_slice_free (struct OperationSpec, operation);
-
-    return;
-  }
-
-  /* Start parsing results */
-  operation->current = 0;
-  tracker_sparql_cursor_next_async (operation->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_query_result_cb,
-                                    (gpointer) operation);
-}
-
-static void
-tracker_metadata_cb (GObject                    *source_object,
-                     GAsyncResult               *result,
-                     GrlMediaSourceMetadataSpec *ms)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (ms->source);
-  gint                  col;
-  GError               *tracker_error = NULL, *error = NULL;
-  TrackerSparqlCursor  *cursor;
-
-  GRL_ODEBUG ("%s", __FUNCTION__);
-
-  cursor = tracker_sparql_connection_query_finish (priv->tracker_connection,
-                                                   result, &tracker_error);
-
-  if (tracker_error) {
-    GRL_WARNING ("Could not execute sparql query id=%u : %s",
-                 ms->metadata_id, tracker_error->message);
-
-    error = g_error_new (GRL_CORE_ERROR,
-			 GRL_CORE_ERROR_BROWSE_FAILED,
-			 "Failed to start metadata action : %s",
-                         tracker_error->message);
-
-    ms->callback (ms->source, NULL, ms->user_data, error);
-
-    g_error_free (tracker_error);
-    g_error_free (error);
-
-    goto end_operation;
-  }
-
-
-  tracker_sparql_cursor_next (cursor, NULL, NULL);
-
-  /* Translate Sparql result into Grilo result */
-  for (col = 0 ; col < tracker_sparql_cursor_get_n_columns (cursor) ; col++) {
-    fill_grilo_media_from_sparql (GRL_TRACKER_SOURCE (ms->source),
-                                  ms->media, cursor, col);
-  }
-
-  ms->callback (ms->source, ms->media, ms->user_data, NULL);
-
- end_operation:
-  if (cursor)
-    g_object_unref (G_OBJECT (cursor));
-}
-
-/**/
-
-const GList *
-grl_tracker_source_supported_keys (GrlMetadataSource *source)
-{
-  return
-    grl_plugin_registry_get_metadata_keys (grl_plugin_registry_get_default ());
-}
-
-/**
- * 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.
- *
- * First column must be the media type, and it does not need to be named.  It
- * must match with any value supported in rdf:type() property, or
- * grilo#Box. 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)
- *            ?song            AS id
- *            nie:title(?song) AS title
- *            nie:url(?song)   AS url
- *     WHERE { ?song a nmm:MusicPiece }
- *   </programlisting>
- * </informalexample>
- *
- * Alternatively, we can use a partial SPARQL query: just specify the sentence
- * in the WHERE part. In this case, "?urn" is the ontology concept to be used in
- * the clause.
- *
- * An example of such partial query:
- *
- * <informalexample>
- *   <programlisting>
- *     ?urn a nfo:Media
- *   </programlisting>
- * </informalexample>
- *
- * In this case, all data required to build a full SPARQL query will be get from
- * the query spec.
- */
-void
-grl_tracker_source_query (GrlMediaSource *source,
-                          GrlMediaSourceQuerySpec *qs)
-{
-  GError               *error = NULL;
-  GrlTrackerSourcePriv *priv  = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  gchar                *constraint;
-  gchar                *sparql_final;
-  gchar                *sparql_select;
-  struct OperationSpec *os;
-
-  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, qs->query_id);
-
-  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;
-  }
-
-  /* Check if it is a full sparql query */
-  if (g_ascii_strncasecmp (qs->query, "select ", 7) != 0) {
-    constraint = grl_tracker_source_get_device_constraint (priv);
-    sparql_select = grl_tracker_source_get_select_string (source, qs->keys);
-    sparql_final = g_strdup_printf (TRACKER_QUERY_REQUEST,
-                                    sparql_select,
-                                    qs->query,
-                                    constraint,
-                                    qs->skip,
-                                    qs->count);
-    g_free (constraint);
-    g_free (qs->query);
-    g_free (sparql_select);
-    qs->query = sparql_final;
-    grl_tracker_source_query (source, qs);
-    return;
-  }
-
-  GRL_IDEBUG ("\tselect : '%s'", qs->query);
-
-  os = tracker_operation_initiate (source, priv, qs->query_id);
-  os->keys         = qs->keys;
-  os->skip         = qs->skip;
-  os->count        = qs->count;
-  os->callback     = qs->callback;
-  os->user_data    = qs->user_data;
-
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         qs->query,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
-
-  return;
-
- send_error:
-  qs->callback (qs->source, qs->query_id, NULL, 0, qs->user_data, error);
-  g_error_free (error);
-}
-
-void
-grl_tracker_source_metadata (GrlMediaSource *source,
-                             GrlMediaSourceMetadataSpec *ms)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  gchar                *constraint = NULL, *sparql_select, *sparql_final;
-
-  GRL_IDEBUG ("%s: id=%i", __FUNCTION__, ms->metadata_id);
-
-  if (grl_media_get_id (ms->media) == NULL) {
-    if (grl_tracker_per_device_source) {
-      constraint = grl_tracker_source_get_device_constraint (priv);
-      sparql_select = grl_tracker_source_get_select_string (source, ms->keys);
-      sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST,
-                                      sparql_select, constraint, 0, 1);
-    } else {
-      ms->callback (ms->source, ms->media, ms->user_data, NULL);
-      return;
-    }
-  } else {
-    sparql_select = grl_tracker_source_get_select_string (source, ms->keys);
-    sparql_final = g_strdup_printf (TRACKER_METADATA_REQUEST, sparql_select,
-                                    grl_media_get_id (ms->media));
-  }
-
-  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
-
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         NULL,
-                                         (GAsyncReadyCallback) tracker_metadata_cb,
-                                         ms);
-
-  if (constraint != NULL)
-    g_free (constraint);
-  if (sparql_select != NULL)
-    g_free (sparql_select);
-  if (sparql_final != NULL)
-    g_free (sparql_final);
-}
-
-void
-grl_tracker_source_search (GrlMediaSource *source, GrlMediaSourceSearchSpec *ss)
-{
-  GrlTrackerSourcePriv *priv  = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  gchar                *constraint;
-  gchar                *sparql_select;
-  gchar                *sparql_final;
-  struct OperationSpec *os;
-
-  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, ss->search_id);
-
-  constraint = grl_tracker_source_get_device_constraint (priv);
-  sparql_select = grl_tracker_source_get_select_string (source, ss->keys);
-  if (!ss->text || ss->text[0] == '\0') {
-    /* Search all */
-    sparql_final = g_strdup_printf (TRACKER_SEARCH_ALL_REQUEST, sparql_select,
-                                    constraint, ss->skip, ss->count);
-  } else {
-    sparql_final = g_strdup_printf (TRACKER_SEARCH_REQUEST, sparql_select,
-                                    ss->text, constraint, ss->skip, ss->count);
-  }
-
-  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
-
-  os = tracker_operation_initiate (source, priv, ss->search_id);
-  os->keys         = ss->keys;
-  os->skip         = ss->skip;
-  os->count        = ss->count;
-  os->callback     = ss->callback;
-  os->user_data    = ss->user_data;
-
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
-
-  g_free (constraint);
-  g_free (sparql_select);
-  g_free (sparql_final);
-}
-
-static void
-grl_tracker_source_browse_category (GrlMediaSource *source,
-                                    GrlMediaSourceBrowseSpec *bs)
-{
-  GrlTrackerSourcePriv *priv  = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  gchar                *constraint;
-  gchar                *sparql_select;
-  gchar                *sparql_final;
-  struct OperationSpec *os;
-  GrlMedia             *media;
-  const gchar          *category;
-
-  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, bs->browse_id);
-
-  if (bs->container == NULL ||
-      !grl_data_key_is_known (GRL_DATA (bs->container),
-                              grl_metadata_key_tracker_category)) {
-    /* Hardcoded categories */
-    media = grl_media_box_new ();
-    grl_media_set_title (media, "Documents");
-    grl_data_set_string (GRL_DATA (media),
-                         grl_metadata_key_tracker_category,
-                         "nfo:Document");
-    bs->callback (bs->source, bs->browse_id, media, 3, bs->user_data, NULL);
-
-    media = grl_media_box_new ();
-    grl_media_set_title (media, "Music");
-    grl_data_set_string (GRL_DATA (media),
-                         grl_metadata_key_tracker_category,
-                         "nmm:MusicPiece");
-    bs->callback (bs->source, bs->browse_id, media, 2, bs->user_data, NULL);
-
-    media = grl_media_box_new ();
-    grl_media_set_title (media, "Photos");
-    grl_data_set_string (GRL_DATA (media),
-                         grl_metadata_key_tracker_category,
-                         "nmm:Photo");
-    bs->callback (bs->source, bs->browse_id, media, 1, bs->user_data, NULL);
-
-    media = grl_media_box_new ();
-    grl_media_set_title (media, "Videos");
-    grl_data_set_string (GRL_DATA (media),
-                         grl_metadata_key_tracker_category,
-                         "nmm:Video");
-    bs->callback (bs->source, bs->browse_id, media, 0, bs->user_data, NULL);
-    return;
-  }
-
-  category = grl_data_get_string (GRL_DATA (bs->container),
-                                  grl_metadata_key_tracker_category);
-
-  constraint = grl_tracker_source_get_device_constraint (priv);
-  sparql_select = grl_tracker_source_get_select_string (bs->source, bs->keys);
-  sparql_final = g_strdup_printf (TRACKER_BROWSE_CATEGORY_REQUEST,
-                                  sparql_select,
-                                  category,
-                                  constraint,
-                                  bs->skip, bs->count);
-
-  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
-
-  os = tracker_operation_initiate (source, priv, bs->browse_id);
-  os->keys         = bs->keys;
-  os->skip         = bs->skip;
-  os->count        = bs->count;
-  os->callback     = bs->callback;
-  os->user_data    = bs->user_data;
-
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
-
-  g_free (constraint);
-  g_free (sparql_select);
-  g_free (sparql_final);
-}
-
-static void
-grl_tracker_source_browse_filesystem (GrlMediaSource *source,
-                                      GrlMediaSourceBrowseSpec *bs)
-{
-  GrlTrackerSourcePriv *priv  = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  gchar                *constraint;
-  gchar                *sparql_select;
-  gchar                *sparql_final;
-  struct OperationSpec *os;
-
-  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, bs->browse_id);
-
-  sparql_select = grl_tracker_source_get_select_string (bs->source, bs->keys);
-  constraint = grl_tracker_source_get_device_constraint (priv);
-
-  if (bs->container == NULL ||
-      !grl_media_get_id (bs->container)) {
-    sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST,
-                                    sparql_select,
-                                    constraint,
-                                    bs->skip, bs->count);
-
-  } else {
-    sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_REQUEST,
-                                    sparql_select,
-                                    constraint,
-                                    grl_media_get_id (bs->container),
-                                    bs->skip, bs->count);
-  }
-
-  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
-
-  os = tracker_operation_initiate (source, priv, bs->browse_id);
-  os->keys         = bs->keys;
-  os->skip         = bs->skip;
-  os->count        = bs->count;
-  os->callback     = bs->callback;
-  os->user_data    = bs->user_data;
-
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
-
-  g_free (constraint);
-  g_free (sparql_select);
-  g_free (sparql_final);
-}
-
-void
-grl_tracker_source_browse (GrlMediaSource *source,
-                           GrlMediaSourceBrowseSpec *bs)
-{
-  if (grl_tracker_browse_filesystem)
-    grl_tracker_source_browse_filesystem (source, bs);
-  else
-    grl_tracker_source_browse_category (source, bs);
-}
-
-void
-grl_tracker_source_cancel (GrlMediaSource *source, guint operation_id)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  struct OperationSpec *os;
-
-  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, operation_id);
-
-  os = g_hash_table_lookup (priv->operations, GSIZE_TO_POINTER (operation_id));
-
-  if (os != NULL)
-    g_cancellable_cancel (os->cancel_op);
-}
-
-gboolean
-grl_tracker_source_change_start (GrlMediaSource *source, GError **error)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  priv->notify_changes = TRUE;
-
-  return TRUE;
-}
-
-gboolean
-grl_tracker_source_change_stop (GrlMediaSource *source, GError **error)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  priv->notify_changes = FALSE;
-
-  return TRUE;
-}
-
-void
-grl_tracker_init_requests (void)
-{
-  grl_metadata_key_tracker_category =
-    grl_plugin_registry_register_metadata_key (grl_plugin_registry_get_default (),
-                                               g_param_spec_string ("tracker-category",
-                                                                    "Tracker category",
-                                                                    "Category a media belongs to",
-                                                                    NULL,
-                                                                    G_PARAM_STATIC_STRINGS |
-                                                                    G_PARAM_READWRITE),
-                                               NULL);
-
-
-  GRL_LOG_DOMAIN_INIT (tracker_request_log_domain, "tracker-request");
-  GRL_LOG_DOMAIN_INIT (tracker_result_log_domain, "tracker-result");
-}
diff --git a/src/media/tracker/grl-tracker-api.h b/src/media/tracker/grl-tracker-api.h
deleted file mode 100644
index 4e2b52b..0000000
--- a/src/media/tracker/grl-tracker-api.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_API_H_
-#define _GRL_TRACKER_API_H_
-
-#include "grl-tracker.h"
-
-/**/
-
-void grl_tracker_init_requests (void);
-
-const GList *grl_tracker_source_supported_keys (GrlMetadataSource *source);
-
-void grl_tracker_source_query (GrlMediaSource *source,
-                               GrlMediaSourceQuerySpec *qs);
-
-void grl_tracker_source_metadata (GrlMediaSource *source,
-                                  GrlMediaSourceMetadataSpec *ms);
-
-void grl_tracker_source_search (GrlMediaSource *source,
-                                GrlMediaSourceSearchSpec *ss);
-
-void grl_tracker_source_browse (GrlMediaSource *source,
-                                GrlMediaSourceBrowseSpec *bs);
-
-void grl_tracker_source_cancel (GrlMediaSource *source, guint operation_id);
-
-gboolean grl_tracker_source_change_start (GrlMediaSource *source,
-                                          GError **error);
-
-gboolean grl_tracker_source_change_stop (GrlMediaSource *source,
-                                         GError **error);
-
-#endif /* _GRL_TRACKER_API_H_ */
diff --git a/src/media/tracker/grl-tracker-cache.c b/src/media/tracker/grl-tracker-cache.c
deleted file mode 100644
index e5801e7..0000000
--- a/src/media/tracker/grl-tracker-cache.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <glib.h>
-
-#include "grl-tracker-cache.h"
-
-typedef struct {
-  GrlTrackerSource *source;
-
-  GHashTable *id_table;
-} GrlTrackerCacheSource;
-
-struct _GrlTrackerCache {
-  gsize size_limit;
-  gsize size_current;
-
-  GHashTable *id_table;
-  GHashTable *source_table;
-  GList      *id_list;
-};
-
-static GrlTrackerCacheSource *
-grl_tracker_cache_source_new (GrlTrackerSource *source)
-{
-  GrlTrackerCacheSource *csource = g_slice_new0 (GrlTrackerCacheSource);
-
-  csource->source = source;
-  csource->id_table = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-  return csource;
-}
-
-static void
-grl_tracker_cache_source_free (GrlTrackerCacheSource *csource)
-{
-  g_hash_table_destroy (csource->id_table);
-
-  g_slice_free (GrlTrackerCacheSource, csource);
-}
-
-/**/
-
-GrlTrackerCache *
-grl_tracker_cache_new (gsize size)
-{
-  GrlTrackerCache *cache;
-
-  g_return_val_if_fail (size > 0, NULL);
-
-  cache = g_slice_new0 (GrlTrackerCache);
-
-  if (!cache)
-    return NULL;
-
-  cache->size_limit   = size;
-  cache->id_table     = g_hash_table_new (g_direct_hash, g_direct_equal);
-  cache->source_table = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-  return cache;
-}
-
-void
-grl_tracker_cache_free (GrlTrackerCache *cache)
-{
-  GHashTableIter iter;
-  gpointer key, value;
-
-  g_return_if_fail (cache != NULL);
-
-  g_hash_table_iter_init (&iter, cache->source_table);
-  while (g_hash_table_iter_next (&iter, &key, &value)) {
-    grl_tracker_cache_del_source (cache, key);
-  }
-
-  if (cache->id_list) {
-    g_warning ("Memleak detected");
-    g_list_free (cache->id_list);
-  }
-  g_hash_table_destroy (cache->id_table);
-  g_hash_table_destroy (cache->source_table);
-
-  g_slice_free (GrlTrackerCache, cache);
-}
-
-void
-grl_tracker_cache_add_item (GrlTrackerCache *cache,
-                            guint id,
-                            GrlTrackerSource *source)
-{
-  GList *lid;
-  GrlTrackerCacheSource *csource;
-
-  g_return_if_fail (cache != NULL);
-
-  if (g_hash_table_lookup (cache->id_table, GSIZE_TO_POINTER (id)) != NULL)
-    return; /* TODO: is it worth to have an LRU ? */
-
-  csource = g_hash_table_lookup (cache->source_table, source);
-
-  if (!csource) {
-    csource = grl_tracker_cache_source_new (source);
-    g_hash_table_insert (cache->source_table, source, csource);
-  }
-
-  if (cache->size_current >= cache->size_limit) {
-    lid = g_list_last (cache->id_list); /* TODO: optimize that ! */
-    g_hash_table_remove (cache->id_table, lid->data);
-    cache->id_list = g_list_remove_link (cache->id_list, lid);
-
-    lid->data = GSIZE_TO_POINTER (id);
-    lid->next = cache->id_list;
-    cache->id_list->prev = lid;
-    cache->id_list = lid;
-  } else {
-    cache->id_list = g_list_prepend (cache->id_list, GSIZE_TO_POINTER (id));
-    cache->size_current++;
-  }
-
-  g_hash_table_insert (cache->id_table, GSIZE_TO_POINTER (id), csource);
-  g_hash_table_insert (csource->id_table, GSIZE_TO_POINTER (id),
-                       cache->id_list);
-}
-
-void
-grl_tracker_cache_del_source (GrlTrackerCache *cache,
-                              GrlTrackerSource *source)
-{
-  GrlTrackerCacheSource *csource;
-  GHashTableIter iter;
-  gpointer key, value;
-
-  g_return_if_fail (cache != NULL);
-  g_return_if_fail (source != NULL);
-
-  csource = g_hash_table_lookup (cache->source_table, source);
-
-  if (!csource)
-    return;
-
-  g_hash_table_iter_init (&iter, csource->id_table);
-
-  while (g_hash_table_iter_next (&iter, &key, &value)) {
-    g_hash_table_remove (cache->id_table, key);
-    cache->id_list = g_list_delete_link (cache->id_list, value);
-  }
-
-  g_hash_table_remove (cache->source_table, source);
-  grl_tracker_cache_source_free (csource);
-}
-
-GrlTrackerSource *
-grl_tracker_cache_get_source (GrlTrackerCache *cache, guint id)
-{
-  GrlTrackerCacheSource *csource;
-
-  g_return_val_if_fail (cache != NULL, NULL);
-
-  csource = (GrlTrackerCacheSource *) g_hash_table_lookup (cache->id_table,
-                                                      GSIZE_TO_POINTER (id));
-
-  if (csource) {
-    return csource->source;
-  }
-
-  return NULL;
-}
diff --git a/src/media/tracker/grl-tracker-cache.h b/src/media/tracker/grl-tracker-cache.h
deleted file mode 100644
index ad07865..0000000
--- a/src/media/tracker/grl-tracker-cache.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_CACHE_H_
-#define _GRL_TRACKER_CACHE_H_
-
-#include "grl-tracker.h"
-
-typedef struct _GrlTrackerCache GrlTrackerCache;
-
-GrlTrackerCache *grl_tracker_cache_new (gsize size);
-
-void grl_tracker_cache_free (GrlTrackerCache *cache);
-
-void grl_tracker_cache_add_item (GrlTrackerCache *cache,
-                                 guint id,
-                                 GrlTrackerSource *source);
-void grl_tracker_cache_del_source (GrlTrackerCache *cache,
-                                   GrlTrackerSource *source);
-
-GrlTrackerSource *grl_tracker_cache_get_source (GrlTrackerCache *cache,
-                                                guint id);
-
-#endif /* _GRL_TRACKER_CACHE_H_ */
diff --git a/src/media/tracker/grl-tracker-media-api.c b/src/media/tracker/grl-tracker-media-api.c
new file mode 100644
index 0000000..7b803ec
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-api.c
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <gio/gio.h>
+#include <tracker-sparql.h>
+
+#include "grl-tracker-media-api.h"
+#include "grl-tracker-media-cache.h"
+#include "grl-tracker-media-priv.h"
+#include "grl-tracker-utils.h"
+
+/* --------- Logging  -------- */
+
+#define GRL_LOG_DOMAIN_DEFAULT tracker_request_log_domain
+
+GRL_LOG_DOMAIN_STATIC(tracker_request_log_domain);
+GRL_LOG_DOMAIN_STATIC(tracker_result_log_domain);
+
+/* Inputs/requests */
+#define GRL_IDEBUG(args...)                     \
+  GRL_LOG (tracker_request_log_domain,          \
+           GRL_LOG_LEVEL_DEBUG, args)
+
+/* Outputs/results */
+#define GRL_ODEBUG(args...)                     \
+  GRL_LOG (tracker_result_log_domain,           \
+           GRL_LOG_LEVEL_DEBUG, args)
+
+/* ------- Definitions ------- */
+
+#define TRACKER_QUERY_REQUEST                   \
+  "SELECT rdf:type(?urn) %s "                   \
+  "WHERE { %s . %s } "                          \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
+  "OFFSET %i "                                  \
+  "LIMIT %i"
+
+#define TRACKER_SEARCH_REQUEST                  \
+  "SELECT rdf:type(?urn) %s "                   \
+  "WHERE "                                      \
+  "{ "                                          \
+  "?urn a nfo:Media . "                         \
+  "?urn tracker:available ?tr . "               \
+  "?urn fts:match '*%s*' . "                    \
+  "%s "                                         \
+  "} "                                          \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
+  "OFFSET %i "                                  \
+  "LIMIT %i"
+
+#define TRACKER_SEARCH_ALL_REQUEST              \
+  "SELECT rdf:type(?urn) %s "                   \
+  "WHERE "                                      \
+  "{ "                                          \
+  "?urn a nfo:Media . "                         \
+  "?urn tracker:available ?tr . "               \
+  "%s "                                         \
+  "} "                                          \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
+  "OFFSET %i "                                  \
+  "LIMIT %i"
+
+#define TRACKER_BROWSE_CATEGORY_REQUEST         \
+  "SELECT rdf:type(?urn) %s "                   \
+  "WHERE "                                      \
+  "{ "                                          \
+  "?urn a %s . "                                \
+  "?urn tracker:available ?tr . "               \
+  "%s "                                         \
+  "} "                                          \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "  \
+  "OFFSET %i "                                  \
+  "LIMIT %i"
+
+#define TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST          \
+  "SELECT DISTINCT rdf:type(?urn) %s "                  \
+  "WHERE "                                              \
+  "{ "                                                  \
+  "{ ?urn a nfo:Folder } UNION "                        \
+  "{ ?urn a nfo:Audio } UNION "                         \
+  "{ ?urn a nfo:Document } UNION "                      \
+  "{ ?urn a nmm:Photo } UNION "                         \
+  "{ ?urn a nmm:Video } . "                             \
+  "%s "                                                 \
+  "FILTER (!bound(nfo:belongsToContainer(?urn))) "      \
+  "} "                                                  \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "          \
+  "OFFSET %i "                                          \
+  "LIMIT %i"
+
+#define TRACKER_BROWSE_FILESYSTEM_REQUEST                       \
+  "SELECT DISTINCT rdf:type(?urn) %s "                          \
+  "WHERE "                                                      \
+  "{ "                                                          \
+  "{ ?urn a nfo:Folder } UNION "                                \
+  "{ ?urn a nfo:Audio } UNION "                                 \
+  "{ ?urn a nfo:Document } UNION "                              \
+  "{ ?urn a nmm:Photo } UNION "                                 \
+  "{ ?urn a nmm:Video } . "                                     \
+  "%s "                                                         \
+  "FILTER(tracker:id(nfo:belongsToContainer(?urn)) = %s) "      \
+  "} "                                                          \
+  "ORDER BY DESC(nfo:fileLastModified(?urn)) "                  \
+  "OFFSET %i "                                                  \
+  "LIMIT %i"
+
+#define TRACKER_METADATA_REQUEST                \
+  "SELECT %s "                                  \
+  "WHERE "                                      \
+  "{ "                                          \
+  "?urn a nie:DataObject . "                    \
+  "FILTER (tracker:id(?urn) = %s) "             \
+  "}"
+
+/**/
+
+struct OperationSpec {
+  GrlMediaSource         *source;
+  GrlTrackerMediaPriv    *priv;
+  guint                   operation_id;
+  GCancellable           *cancel_op;
+  const GList            *keys;
+  guint                   skip;
+  guint                   count;
+  guint                   current;
+  GrlMediaSourceResultCb  callback;
+  gpointer                user_data;
+  TrackerSparqlCursor    *cursor;
+};
+
+/**/
+
+static GrlKeyID grl_metadata_key_tracker_category;
+
+/**/
+
+static struct OperationSpec *
+tracker_operation_initiate (GrlMediaSource *source,
+                            GrlTrackerMediaPriv *priv,
+                            guint operation_id)
+{
+  struct OperationSpec *os = g_slice_new0 (struct OperationSpec);
+
+  os->source       = source;
+  os->priv         = priv;
+  os->operation_id = operation_id;
+  os->cancel_op    = g_cancellable_new ();
+
+  g_hash_table_insert (priv->operations, GSIZE_TO_POINTER (operation_id), os);
+
+  return os;
+}
+
+static void
+tracker_operation_terminate (struct OperationSpec *os)
+{
+  if (os == NULL)
+    return;
+
+  g_hash_table_remove (os->priv->operations,
+                       GSIZE_TO_POINTER (os->operation_id));
+
+  g_object_unref (G_OBJECT (os->cursor));
+  g_object_unref (G_OBJECT (os->cancel_op));
+  g_slice_free (struct OperationSpec, os);
+}
+
+static void
+fill_grilo_media_from_sparql (GrlTrackerMedia    *source,
+                              GrlMedia            *media,
+                              TrackerSparqlCursor *cursor,
+                              gint                 column)
+{
+  const gchar *sparql_key = tracker_sparql_cursor_get_variable_name (cursor,
+                                                                     column);
+  tracker_grl_sparql_t *assoc =
+    grl_tracker_get_mapping_from_sparql (sparql_key);
+  union {
+    gint int_val;
+    gdouble double_val;
+    const gchar *str_val;
+  } val;
+
+  if (assoc == NULL)
+    return;
+
+  GRL_ODEBUG ("\tSetting media prop (col=%i/var=%s/prop=%s) %s",
+              column,
+              sparql_key,
+              g_param_spec_get_name (G_PARAM_SPEC (assoc->grl_key)),
+              tracker_sparql_cursor_get_string (cursor, column, NULL));
+
+  if (tracker_sparql_cursor_is_bound (cursor, column) == FALSE) {
+    GRL_ODEBUG ("\t\tDropping, no data");
+    return;
+  }
+
+  if (grl_data_key_is_known (GRL_DATA (media), assoc->grl_key)) {
+    GRL_ODEBUG ("\t\tDropping, already here");
+    return;
+  }
+
+  switch (G_PARAM_SPEC (assoc->grl_key)->value_type) {
+  case G_TYPE_STRING:
+    /* Cache the source associated to this result. */
+    if (assoc->grl_key == GRL_METADATA_KEY_ID) {
+      grl_tracker_media_cache_add_item (grl_tracker_item_cache,
+                                        tracker_sparql_cursor_get_integer (cursor,
+                                                                           column),
+                                        source);
+    }
+    val.str_val = tracker_sparql_cursor_get_string (cursor, column, NULL);
+    if (val.str_val != NULL)
+      grl_data_set_string (GRL_DATA (media), assoc->grl_key, val.str_val);
+    break;
+
+  case G_TYPE_INT:
+    val.int_val = tracker_sparql_cursor_get_integer (cursor, column);
+    grl_data_set_int (GRL_DATA (media), assoc->grl_key, val.int_val);
+    break;
+
+  case G_TYPE_FLOAT:
+    val.double_val = tracker_sparql_cursor_get_double (cursor, column);
+    grl_data_set_float (GRL_DATA (media), assoc->grl_key, (gfloat) val.double_val);
+    break;
+
+  default:
+    GRL_ODEBUG ("\t\tUnexpected data type");
+    break;
+  }
+}
+
+static void
+tracker_query_result_cb (GObject              *source_object,
+                         GAsyncResult         *result,
+                         struct OperationSpec *operation)
+{
+  gint         col;
+  const gchar *sparql_type;
+  GError      *tracker_error = NULL, *error = NULL;
+  GrlMedia    *media;
+
+  GRL_ODEBUG ("%s", __FUNCTION__);
+
+  if (g_cancellable_is_cancelled (operation->cancel_op)) {
+    GRL_ODEBUG ("\tOperation %u cancelled", operation->operation_id);
+    operation->callback (operation->source,
+                         operation->operation_id,
+                         NULL, 0,
+                         operation->user_data, NULL);
+    tracker_operation_terminate (operation);
+
+    return;
+  }
+
+  if (!tracker_sparql_cursor_next_finish (operation->cursor,
+                                          result,
+                                          &tracker_error)) {
+    if (tracker_error != NULL) {
+      GRL_ODEBUG ("\terror in parsing query id=%u : %s",
+                  operation->operation_id, tracker_error->message);
+
+      error = g_error_new (GRL_CORE_ERROR,
+                           GRL_CORE_ERROR_BROWSE_FAILED,
+                           "Failed to start browse/query action : %s",
+                           tracker_error->message);
+
+      operation->callback (operation->source,
+                           operation->operation_id,
+                           NULL, 0,
+                           operation->user_data, error);
+
+      g_error_free (error);
+      g_error_free (tracker_error);
+    } else {
+      GRL_ODEBUG ("\tend of parsing id=%u :)", operation->operation_id);
+
+      /* Only emit this last one if more result than expected */
+      if (operation->count > 1)
+        operation->callback (operation->source,
+                             operation->operation_id,
+                             NULL, 0,
+                             operation->user_data, NULL);
+    }
+
+    tracker_operation_terminate (operation);
+    return;
+  }
+
+  sparql_type = tracker_sparql_cursor_get_string (operation->cursor, 0, NULL);
+
+  GRL_ODEBUG ("\tParsing line %i of type %s", operation->current, sparql_type);
+
+  media = grl_tracker_build_grilo_media (sparql_type);
+
+  if (media != NULL) {
+    for (col = 1 ;
+         col < tracker_sparql_cursor_get_n_columns (operation->cursor) ;
+         col++) {
+      fill_grilo_media_from_sparql (GRL_TRACKER_MEDIA (operation->source),
+                                    media, operation->cursor, col);
+    }
+
+    operation->callback (operation->source,
+                         operation->operation_id,
+                         media,
+                         --operation->count,
+                         operation->user_data,
+                         NULL);
+  }
+
+  /* Schedule the next line to parse */
+  operation->current++;
+  if (operation->count < 1)
+    tracker_operation_terminate (operation);
+  else
+    tracker_sparql_cursor_next_async (operation->cursor, operation->cancel_op,
+                                      (GAsyncReadyCallback) tracker_query_result_cb,
+                                      (gpointer) operation);
+}
+
+static void
+tracker_query_cb (GObject              *source_object,
+                  GAsyncResult         *result,
+                  struct OperationSpec *operation)
+{
+  GError *tracker_error = NULL, *error = NULL;
+
+  GRL_ODEBUG ("%s", __FUNCTION__);
+
+  operation->cursor =
+    tracker_sparql_connection_query_finish (operation->priv->tracker_connection,
+                                            result, &tracker_error);
+
+  if (tracker_error) {
+    GRL_WARNING ("Could not execute sparql query id=%u: %s",
+                 operation->operation_id, tracker_error->message);
+
+    error = g_error_new (GRL_CORE_ERROR,
+			 GRL_CORE_ERROR_BROWSE_FAILED,
+			 "Failed to start browse/query action : %s",
+                         tracker_error->message);
+
+    operation->callback (operation->source, operation->operation_id, NULL, 0,
+                         operation->user_data, error);
+
+    g_error_free (tracker_error);
+    g_error_free (error);
+    g_slice_free (struct OperationSpec, operation);
+
+    return;
+  }
+
+  /* Start parsing results */
+  operation->current = 0;
+  tracker_sparql_cursor_next_async (operation->cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_query_result_cb,
+                                    (gpointer) operation);
+}
+
+static void
+tracker_metadata_cb (GObject                    *source_object,
+                     GAsyncResult               *result,
+                     GrlMediaSourceMetadataSpec *ms)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (ms->source);
+  gint                  col;
+  GError               *tracker_error = NULL, *error = NULL;
+  TrackerSparqlCursor  *cursor;
+
+  GRL_ODEBUG ("%s", __FUNCTION__);
+
+  cursor = tracker_sparql_connection_query_finish (priv->tracker_connection,
+                                                   result, &tracker_error);
+
+  if (tracker_error) {
+    GRL_WARNING ("Could not execute sparql query id=%u : %s",
+                 ms->metadata_id, tracker_error->message);
+
+    error = g_error_new (GRL_CORE_ERROR,
+			 GRL_CORE_ERROR_BROWSE_FAILED,
+			 "Failed to start metadata action : %s",
+                         tracker_error->message);
+
+    ms->callback (ms->source, NULL, ms->user_data, error);
+
+    g_error_free (tracker_error);
+    g_error_free (error);
+
+    goto end_operation;
+  }
+
+
+  tracker_sparql_cursor_next (cursor, NULL, NULL);
+
+  /* Translate Sparql result into Grilo result */
+  for (col = 0 ; col < tracker_sparql_cursor_get_n_columns (cursor) ; col++) {
+    fill_grilo_media_from_sparql (GRL_TRACKER_MEDIA (ms->source),
+                                  ms->media, cursor, col);
+  }
+
+  ms->callback (ms->source, ms->media, ms->user_data, NULL);
+
+ end_operation:
+  if (cursor)
+    g_object_unref (G_OBJECT (cursor));
+}
+
+/**/
+
+const GList *
+grl_tracker_media_supported_keys (GrlMetadataSource *source)
+{
+  return
+    grl_plugin_registry_get_metadata_keys (grl_plugin_registry_get_default ());
+}
+
+/**
+ * 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.
+ *
+ * First column must be the media type, and it does not need to be named.  It
+ * must match with any value supported in rdf:type() property, or
+ * grilo#Box. 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)
+ *            ?song            AS id
+ *            nie:title(?song) AS title
+ *            nie:url(?song)   AS url
+ *     WHERE { ?song a nmm:MusicPiece }
+ *   </programlisting>
+ * </informalexample>
+ *
+ * Alternatively, we can use a partial SPARQL query: just specify the sentence
+ * in the WHERE part. In this case, "?urn" is the ontology concept to be used in
+ * the clause.
+ *
+ * An example of such partial query:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *     ?urn a nfo:Media
+ *   </programlisting>
+ * </informalexample>
+ *
+ * In this case, all data required to build a full SPARQL query will be get from
+ * the query spec.
+ */
+void
+grl_tracker_media_query (GrlMediaSource *source,
+                         GrlMediaSourceQuerySpec *qs)
+{
+  GError               *error = NULL;
+  GrlTrackerMediaPriv *priv  = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar                *constraint;
+  gchar                *sparql_final;
+  gchar                *sparql_select;
+  struct OperationSpec *os;
+
+  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, qs->query_id);
+
+  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;
+  }
+
+  /* Check if it is a full sparql query */
+  if (g_ascii_strncasecmp (qs->query, "select ", 7) != 0) {
+    constraint = grl_tracker_media_get_device_constraint (priv);
+    sparql_select = grl_tracker_media_get_select_string (source, qs->keys);
+    sparql_final = g_strdup_printf (TRACKER_QUERY_REQUEST,
+                                    sparql_select,
+                                    qs->query,
+                                    constraint,
+                                    qs->skip,
+                                    qs->count);
+    g_free (constraint);
+    g_free (qs->query);
+    g_free (sparql_select);
+    qs->query = sparql_final;
+    grl_tracker_media_query (source, qs);
+    return;
+  }
+
+  GRL_IDEBUG ("\tselect : '%s'", qs->query);
+
+  os = tracker_operation_initiate (source, priv, qs->query_id);
+  os->keys         = qs->keys;
+  os->skip         = qs->skip;
+  os->count        = qs->count;
+  os->callback     = qs->callback;
+  os->user_data    = qs->user_data;
+
+  tracker_sparql_connection_query_async (priv->tracker_connection,
+                                         qs->query,
+                                         os->cancel_op,
+                                         (GAsyncReadyCallback) tracker_query_cb,
+                                         os);
+
+  return;
+
+ send_error:
+  qs->callback (qs->source, qs->query_id, NULL, 0, qs->user_data, error);
+  g_error_free (error);
+}
+
+void
+grl_tracker_media_metadata (GrlMediaSource *source,
+                            GrlMediaSourceMetadataSpec *ms)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar                *constraint = NULL, *sparql_select, *sparql_final;
+
+  GRL_IDEBUG ("%s: id=%i", __FUNCTION__, ms->metadata_id);
+
+  if (grl_media_get_id (ms->media) == NULL) {
+    if (grl_tracker_per_device_source) {
+      constraint = grl_tracker_media_get_device_constraint (priv);
+      sparql_select = grl_tracker_media_get_select_string (source, ms->keys);
+      sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST,
+                                      sparql_select, constraint, 0, 1);
+    } else {
+      ms->callback (ms->source, ms->media, ms->user_data, NULL);
+      return;
+    }
+  } else {
+    sparql_select = grl_tracker_media_get_select_string (source, ms->keys);
+    sparql_final = g_strdup_printf (TRACKER_METADATA_REQUEST, sparql_select,
+                                    grl_media_get_id (ms->media));
+  }
+
+  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
+
+  tracker_sparql_connection_query_async (priv->tracker_connection,
+                                         sparql_final,
+                                         NULL,
+                                         (GAsyncReadyCallback) tracker_metadata_cb,
+                                         ms);
+
+  if (constraint != NULL)
+    g_free (constraint);
+  if (sparql_select != NULL)
+    g_free (sparql_select);
+  if (sparql_final != NULL)
+    g_free (sparql_final);
+}
+
+void
+grl_tracker_media_search (GrlMediaSource *source, GrlMediaSourceSearchSpec *ss)
+{
+  GrlTrackerMediaPriv *priv  = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar                *constraint;
+  gchar                *sparql_select;
+  gchar                *sparql_final;
+  struct OperationSpec *os;
+
+  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, ss->search_id);
+
+  constraint = grl_tracker_media_get_device_constraint (priv);
+  sparql_select = grl_tracker_media_get_select_string (source, ss->keys);
+  if (!ss->text || ss->text[0] == '\0') {
+    /* Search all */
+    sparql_final = g_strdup_printf (TRACKER_SEARCH_ALL_REQUEST, sparql_select,
+                                    constraint, ss->skip, ss->count);
+  } else {
+    sparql_final = g_strdup_printf (TRACKER_SEARCH_REQUEST, sparql_select,
+                                    ss->text, constraint, ss->skip, ss->count);
+  }
+
+  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
+
+  os = tracker_operation_initiate (source, priv, ss->search_id);
+  os->keys         = ss->keys;
+  os->skip         = ss->skip;
+  os->count        = ss->count;
+  os->callback     = ss->callback;
+  os->user_data    = ss->user_data;
+
+  tracker_sparql_connection_query_async (priv->tracker_connection,
+                                         sparql_final,
+                                         os->cancel_op,
+                                         (GAsyncReadyCallback) tracker_query_cb,
+                                         os);
+
+  g_free (constraint);
+  g_free (sparql_select);
+  g_free (sparql_final);
+}
+
+static void
+grl_tracker_media_browse_category (GrlMediaSource *source,
+                                   GrlMediaSourceBrowseSpec *bs)
+{
+  GrlTrackerMediaPriv *priv  = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar                *constraint;
+  gchar                *sparql_select;
+  gchar                *sparql_final;
+  struct OperationSpec *os;
+  GrlMedia             *media;
+  const gchar          *category;
+
+  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, bs->browse_id);
+
+  if (bs->container == NULL ||
+      !grl_data_key_is_known (GRL_DATA (bs->container),
+                              grl_metadata_key_tracker_category)) {
+    /* Hardcoded categories */
+    media = grl_media_box_new ();
+    grl_media_set_title (media, "Documents");
+    grl_data_set_string (GRL_DATA (media),
+                         grl_metadata_key_tracker_category,
+                         "nfo:Document");
+    bs->callback (bs->source, bs->browse_id, media, 3, bs->user_data, NULL);
+
+    media = grl_media_box_new ();
+    grl_media_set_title (media, "Music");
+    grl_data_set_string (GRL_DATA (media),
+                         grl_metadata_key_tracker_category,
+                         "nmm:MusicPiece");
+    bs->callback (bs->source, bs->browse_id, media, 2, bs->user_data, NULL);
+
+    media = grl_media_box_new ();
+    grl_media_set_title (media, "Photos");
+    grl_data_set_string (GRL_DATA (media),
+                         grl_metadata_key_tracker_category,
+                         "nmm:Photo");
+    bs->callback (bs->source, bs->browse_id, media, 1, bs->user_data, NULL);
+
+    media = grl_media_box_new ();
+    grl_media_set_title (media, "Videos");
+    grl_data_set_string (GRL_DATA (media),
+                         grl_metadata_key_tracker_category,
+                         "nmm:Video");
+    bs->callback (bs->source, bs->browse_id, media, 0, bs->user_data, NULL);
+    return;
+  }
+
+  category = grl_data_get_string (GRL_DATA (bs->container),
+                                  grl_metadata_key_tracker_category);
+
+  constraint = grl_tracker_media_get_device_constraint (priv);
+  sparql_select = grl_tracker_media_get_select_string (bs->source, bs->keys);
+  sparql_final = g_strdup_printf (TRACKER_BROWSE_CATEGORY_REQUEST,
+                                  sparql_select,
+                                  category,
+                                  constraint,
+                                  bs->skip, bs->count);
+
+  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
+
+  os = tracker_operation_initiate (source, priv, bs->browse_id);
+  os->keys         = bs->keys;
+  os->skip         = bs->skip;
+  os->count        = bs->count;
+  os->callback     = bs->callback;
+  os->user_data    = bs->user_data;
+
+  tracker_sparql_connection_query_async (priv->tracker_connection,
+                                         sparql_final,
+                                         os->cancel_op,
+                                         (GAsyncReadyCallback) tracker_query_cb,
+                                         os);
+
+  g_free (constraint);
+  g_free (sparql_select);
+  g_free (sparql_final);
+}
+
+static void
+grl_tracker_media_browse_filesystem (GrlMediaSource *source,
+                                     GrlMediaSourceBrowseSpec *bs)
+{
+  GrlTrackerMediaPriv *priv  = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar                *constraint;
+  gchar                *sparql_select;
+  gchar                *sparql_final;
+  struct OperationSpec *os;
+
+  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, bs->browse_id);
+
+  sparql_select = grl_tracker_media_get_select_string (bs->source, bs->keys);
+  constraint = grl_tracker_media_get_device_constraint (priv);
+
+  if (bs->container == NULL ||
+      !grl_media_get_id (bs->container)) {
+    sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_ROOT_REQUEST,
+                                    sparql_select,
+                                    constraint,
+                                    bs->skip, bs->count);
+
+  } else {
+    sparql_final = g_strdup_printf (TRACKER_BROWSE_FILESYSTEM_REQUEST,
+                                    sparql_select,
+                                    constraint,
+                                    grl_media_get_id (bs->container),
+                                    bs->skip, bs->count);
+  }
+
+  GRL_IDEBUG ("\tselect: '%s'", sparql_final);
+
+  os = tracker_operation_initiate (source, priv, bs->browse_id);
+  os->keys         = bs->keys;
+  os->skip         = bs->skip;
+  os->count        = bs->count;
+  os->callback     = bs->callback;
+  os->user_data    = bs->user_data;
+
+  tracker_sparql_connection_query_async (priv->tracker_connection,
+                                         sparql_final,
+                                         os->cancel_op,
+                                         (GAsyncReadyCallback) tracker_query_cb,
+                                         os);
+
+  g_free (constraint);
+  g_free (sparql_select);
+  g_free (sparql_final);
+}
+
+void
+grl_tracker_media_browse (GrlMediaSource *source,
+                          GrlMediaSourceBrowseSpec *bs)
+{
+  if (grl_tracker_browse_filesystem)
+    grl_tracker_media_browse_filesystem (source, bs);
+  else
+    grl_tracker_media_browse_category (source, bs);
+}
+
+void
+grl_tracker_media_cancel (GrlMediaSource *source, guint operation_id)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  struct OperationSpec *os;
+
+  GRL_IDEBUG ("%s: id=%u", __FUNCTION__, operation_id);
+
+  os = g_hash_table_lookup (priv->operations, GSIZE_TO_POINTER (operation_id));
+
+  if (os != NULL)
+    g_cancellable_cancel (os->cancel_op);
+}
+
+gboolean
+grl_tracker_media_change_start (GrlMediaSource *source, GError **error)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  priv->notify_changes = TRUE;
+
+  return TRUE;
+}
+
+gboolean
+grl_tracker_media_change_stop (GrlMediaSource *source, GError **error)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  priv->notify_changes = FALSE;
+
+  return TRUE;
+}
+
+void
+grl_tracker_media_init_requests (void)
+{
+  grl_metadata_key_tracker_category =
+    grl_plugin_registry_register_metadata_key (grl_plugin_registry_get_default (),
+                                               g_param_spec_string ("tracker-category",
+                                                                    "Tracker category",
+                                                                    "Category a media belongs to",
+                                                                    NULL,
+                                                                    G_PARAM_STATIC_STRINGS |
+                                                                    G_PARAM_READWRITE),
+                                               NULL);
+
+
+  GRL_LOG_DOMAIN_INIT (tracker_request_log_domain, "tracker-request");
+  GRL_LOG_DOMAIN_INIT (tracker_result_log_domain, "tracker-result");
+}
diff --git a/src/media/tracker/grl-tracker-media-api.h b/src/media/tracker/grl-tracker-media-api.h
new file mode 100644
index 0000000..30589e0
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-api.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_MEDIA_API_H_
+#define _GRL_TRACKER_MEDIA_API_H_
+
+#include "grl-tracker-media.h"
+
+/**/
+
+void grl_tracker_media_init_requests (void);
+
+const GList *grl_tracker_media_supported_keys (GrlMetadataSource *source);
+
+void grl_tracker_media_query (GrlMediaSource *source,
+                              GrlMediaSourceQuerySpec *qs);
+
+void grl_tracker_media_metadata (GrlMediaSource *source,
+                                 GrlMediaSourceMetadataSpec *ms);
+
+void grl_tracker_media_search (GrlMediaSource *source,
+                               GrlMediaSourceSearchSpec *ss);
+
+void grl_tracker_media_browse (GrlMediaSource *source,
+                               GrlMediaSourceBrowseSpec *bs);
+
+void grl_tracker_media_cancel (GrlMediaSource *source, guint operation_id);
+
+gboolean grl_tracker_media_change_start (GrlMediaSource *source,
+                                         GError **error);
+
+gboolean grl_tracker_media_change_stop (GrlMediaSource *source,
+                                        GError **error);
+
+#endif /* _GRL_TRACKER_MEDIA_API_H_ */
diff --git a/src/media/tracker/grl-tracker-media-cache.c b/src/media/tracker/grl-tracker-media-cache.c
new file mode 100644
index 0000000..057c3ca
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-cache.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <glib.h>
+
+#include "grl-tracker-media-cache.h"
+
+typedef struct {
+  GrlTrackerMedia *source;
+
+  GHashTable *id_table;
+} GrlTrackerCacheSource;
+
+struct _GrlTrackerCache {
+  gsize size_limit;
+  gsize size_current;
+
+  GHashTable *id_table;
+  GHashTable *source_table;
+  GList      *id_list;
+};
+
+static GrlTrackerCacheSource *
+grl_tracker_cache_media_new (GrlTrackerMedia *source)
+{
+  GrlTrackerCacheSource *csource = g_slice_new0 (GrlTrackerCacheSource);
+
+  csource->source = source;
+  csource->id_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return csource;
+}
+
+static void
+grl_tracker_cache_media_free (GrlTrackerCacheSource *csource)
+{
+  g_hash_table_destroy (csource->id_table);
+
+  g_slice_free (GrlTrackerCacheSource, csource);
+}
+
+/**/
+
+GrlTrackerCache *
+grl_tracker_media_cache_new (gsize size)
+{
+  GrlTrackerCache *cache;
+
+  g_return_val_if_fail (size > 0, NULL);
+
+  cache = g_slice_new0 (GrlTrackerCache);
+
+  if (!cache)
+    return NULL;
+
+  cache->size_limit   = size;
+  cache->id_table     = g_hash_table_new (g_direct_hash, g_direct_equal);
+  cache->source_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return cache;
+}
+
+void
+grl_tracker_media_cache_free (GrlTrackerCache *cache)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_return_if_fail (cache != NULL);
+
+  g_hash_table_iter_init (&iter, cache->source_table);
+  while (g_hash_table_iter_next (&iter, &key, &value)) {
+    grl_tracker_media_cache_del_source (cache, key);
+  }
+
+  if (cache->id_list) {
+    g_warning ("Memleak detected");
+    g_list_free (cache->id_list);
+  }
+  g_hash_table_destroy (cache->id_table);
+  g_hash_table_destroy (cache->source_table);
+
+  g_slice_free (GrlTrackerCache, cache);
+}
+
+void
+grl_tracker_media_cache_add_item (GrlTrackerCache *cache,
+                                  guint id,
+                                  GrlTrackerMedia *source)
+{
+  GList *lid;
+  GrlTrackerCacheSource *csource;
+
+  g_return_if_fail (cache != NULL);
+
+  if (g_hash_table_lookup (cache->id_table, GSIZE_TO_POINTER (id)) != NULL)
+    return; /* TODO: is it worth to have an LRU ? */
+
+  csource = g_hash_table_lookup (cache->source_table, source);
+
+  if (!csource) {
+    csource = grl_tracker_cache_media_new (source);
+    g_hash_table_insert (cache->source_table, source, csource);
+  }
+
+  if (cache->size_current >= cache->size_limit) {
+    lid = g_list_last (cache->id_list); /* TODO: optimize that ! */
+    g_hash_table_remove (cache->id_table, lid->data);
+    cache->id_list = g_list_remove_link (cache->id_list, lid);
+
+    lid->data = GSIZE_TO_POINTER (id);
+    lid->next = cache->id_list;
+    cache->id_list->prev = lid;
+    cache->id_list = lid;
+  } else {
+    cache->id_list = g_list_prepend (cache->id_list, GSIZE_TO_POINTER (id));
+    cache->size_current++;
+  }
+
+  g_hash_table_insert (cache->id_table, GSIZE_TO_POINTER (id), csource);
+  g_hash_table_insert (csource->id_table, GSIZE_TO_POINTER (id),
+                       cache->id_list);
+}
+
+void
+grl_tracker_media_cache_del_source (GrlTrackerCache *cache,
+                                    GrlTrackerMedia *source)
+{
+  GrlTrackerCacheSource *csource;
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_return_if_fail (cache != NULL);
+  g_return_if_fail (source != NULL);
+
+  csource = g_hash_table_lookup (cache->source_table, source);
+
+  if (!csource)
+    return;
+
+  g_hash_table_iter_init (&iter, csource->id_table);
+
+  while (g_hash_table_iter_next (&iter, &key, &value)) {
+    g_hash_table_remove (cache->id_table, key);
+    cache->id_list = g_list_delete_link (cache->id_list, value);
+  }
+
+  g_hash_table_remove (cache->source_table, source);
+  grl_tracker_cache_media_free (csource);
+}
+
+GrlTrackerMedia *
+grl_tracker_media_cache_get_source (GrlTrackerCache *cache, guint id)
+{
+  GrlTrackerCacheSource *csource;
+
+  g_return_val_if_fail (cache != NULL, NULL);
+
+  csource = (GrlTrackerCacheSource *) g_hash_table_lookup (cache->id_table,
+                                                           GSIZE_TO_POINTER (id));
+
+  if (csource) {
+    return csource->source;
+  }
+
+  return NULL;
+}
diff --git a/src/media/tracker/grl-tracker-media-cache.h b/src/media/tracker/grl-tracker-media-cache.h
new file mode 100644
index 0000000..1b5329e
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-cache.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_MEDIA_CACHE_H_
+#define _GRL_TRACKER_MEDIA_CACHE_H_
+
+#include "grl-tracker-media.h"
+
+typedef struct _GrlTrackerCache GrlTrackerCache;
+
+GrlTrackerCache *grl_tracker_media_cache_new (gsize size);
+
+void grl_tracker_media_cache_free (GrlTrackerCache *cache);
+
+void grl_tracker_media_cache_add_item (GrlTrackerCache *cache,
+                                       guint id,
+                                       GrlTrackerMedia *source);
+void grl_tracker_media_cache_del_source (GrlTrackerCache *cache,
+                                         GrlTrackerMedia *source);
+
+GrlTrackerMedia *grl_tracker_media_cache_get_source (GrlTrackerCache *cache,
+                                                     guint id);
+
+#endif /* _GRL_TRACKER_MEDIA_CACHE_H_ */
diff --git a/src/media/tracker/grl-tracker-media-notif.c b/src/media/tracker/grl-tracker-media-notif.c
new file mode 100644
index 0000000..409d977
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-notif.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <tracker-sparql.h>
+
+#include "grl-tracker-media-notif.h"
+#include "grl-tracker-media-priv.h"
+#include "grl-tracker-utils.h"
+
+/* --------- Logging  -------- */
+
+#define GRL_LOG_DOMAIN_DEFAULT tracker_notif_log_domain
+GRL_LOG_DOMAIN_STATIC(tracker_notif_log_domain);
+
+/* ------- Definitions ------- */
+
+#define TRACKER_MEDIA_ITEM_START                                        \
+  "SELECT rdf:type(?urn) tracker:id(?urn) nie:dataSource(?urn) "	\
+  "WHERE { ?urn a nfo:FileDataObject . "                                \
+  "FILTER (tracker:id(?urn) IN ("
+
+#define TRACKER_MEDIA_ITEM_END ")) }"
+
+/**/
+
+typedef struct {
+  /* tables of items for which we know the source */
+  GHashTable *inserted_items;
+  GHashTable *deleted_items;
+  GHashTable *updated_items;
+
+  /* table of items for which we don't know the source */
+  GHashTable *orphan_items;
+
+  /* List of new/old sources */
+  GList *new_sources;
+  GList *old_sources;
+
+  /* Convenient stuff (for tracker/own callbacks...) */
+  TrackerSparqlCursor      *cursor;
+  gboolean                  in_use;
+  GrlMediaSourceChangeType  change_type;
+} tracker_evt_update_t;
+
+/**/
+
+static guint tracker_dbus_signal_id = 0;
+
+/**/
+static tracker_evt_update_t *
+tracker_evt_update_new (void)
+{
+  tracker_evt_update_t *evt = g_slice_new0 (tracker_evt_update_t);
+
+  evt->inserted_items = g_hash_table_new (g_direct_hash, g_direct_equal);
+  evt->deleted_items = g_hash_table_new (g_direct_hash, g_direct_equal);
+  evt->updated_items = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  evt->orphan_items = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return evt;
+}
+
+static void
+tracker_evt_update_free (tracker_evt_update_t *evt)
+{
+  if (!evt)
+    return;
+
+  g_hash_table_destroy (evt->inserted_items);
+  g_hash_table_destroy (evt->deleted_items);
+  g_hash_table_destroy (evt->updated_items);
+
+  g_hash_table_destroy (evt->orphan_items);
+
+  g_list_free (evt->new_sources);
+  g_list_free (evt->old_sources);
+
+  if (evt->cursor != NULL)
+    g_object_unref (evt->cursor);
+
+  g_slice_free (tracker_evt_update_t, evt);
+}
+
+static void
+tracker_evt_update_media_add (tracker_evt_update_t *evt,
+                              const gchar *id,
+                              const gchar *source_name)
+{
+  GrlTrackerMedia *source;
+  GrlTrackerMediaPriv *priv;
+
+  source = g_hash_table_lookup (grl_tracker_modified_sources, id);
+  if (!source) {
+    source = g_object_new (GRL_TRACKER_MEDIA_TYPE,
+			   "source-id", id,
+			   "source-name", source_name,
+			   "source-desc", GRL_TRACKER_MEDIA_DESC,
+			   "tracker-connection", grl_tracker_connection,
+			   NULL);
+    g_hash_table_insert (grl_tracker_modified_sources,
+			 (gpointer) grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)),
+			 source);
+  }
+
+  priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  priv->state = GRL_TRACKER_MEDIA_STATE_INSERTING;
+  priv->notification_ref++;
+
+  evt->new_sources = g_list_append (evt->new_sources, source);
+
+  GRL_DEBUG ("Preadd source p=%p name=%s id=%s count=%u",
+             source, source_name, id, priv->notification_ref);
+}
+
+static void
+tracker_evt_update_media_del (tracker_evt_update_t *evt,
+                              GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  priv->notification_ref++;
+  priv->state = GRL_TRACKER_MEDIA_STATE_DELETING;
+
+  evt->old_sources = g_list_append (evt->old_sources, source);
+
+  GRL_DEBUG ("Predel source p=%p name=%s id=%s count=%u", source,
+             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
+             grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)),
+             priv->notification_ref);
+}
+
+static void
+tracker_evt_postupdate_sources (tracker_evt_update_t *evt)
+{
+  GList *source;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  source = evt->old_sources;
+  while (source != NULL) {
+    grl_tracker_del_source (GRL_TRACKER_MEDIA (source->data));
+    source = source->next;
+  }
+
+  source = evt->new_sources;
+  while (source != NULL) {
+    grl_tracker_add_source (GRL_TRACKER_MEDIA (source->data));
+    source = source->next;
+  }
+
+  tracker_evt_update_free (evt);
+}
+
+static void
+tracker_evt_update_orphan_item_cb (GObject              *object,
+                                   GAsyncResult         *result,
+                                   tracker_evt_update_t *evt)
+{
+  guint id;
+  const gchar *type, *datasource;
+  GrlTrackerMedia *source = NULL;
+  GError *error = NULL;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (!tracker_sparql_cursor_next_finish (evt->cursor, result, &error)) {
+    if (error != NULL) {
+      GRL_DEBUG ("\terror in parsing : %s", error->message);
+      g_error_free (error);
+    } else {
+      GRL_DEBUG ("\tend of parsing...");
+    }
+
+    if (grl_tracker_per_device_source) {
+      /* Once all items have been processed, add new sources and we're
+	 done. */
+      tracker_evt_postupdate_sources (evt);
+    }
+
+    return;
+  }
+
+  type = tracker_sparql_cursor_get_string (evt->cursor, 0, NULL);
+  id = tracker_sparql_cursor_get_integer (evt->cursor, 1);
+  datasource = tracker_sparql_cursor_get_string (evt->cursor, 2, NULL);
+
+  GRL_DEBUG ("\tOrphan item: id=%u datasource=%s", id, datasource);
+
+  if (datasource)
+    source = grl_tracker_media_find (datasource);
+
+  if (source && GRL_IS_TRACKER_MEDIA (source)) {
+    GrlMedia *media;
+
+    GRL_DEBUG (" \tAdding to cache id=%u", id);
+    grl_tracker_media_cache_add_item (grl_tracker_item_cache, id, source);
+
+    if (grl_tracker_media_can_notify (source)) {
+      media = grl_tracker_build_grilo_media (type);
+      if (media) {
+        gchar *str_id = g_strdup_printf ("%i", id);
+        gint change_type =
+          GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
+                                                GSIZE_TO_POINTER (id)));
+
+        grl_media_set_id (media, str_id);
+        g_free (str_id);
+
+        GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
+                   grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
+                   source);
+        grl_media_source_notify_change (GRL_MEDIA_SOURCE (source), media,
+                                        change_type, FALSE);
+
+        g_object_unref (media);
+      }
+    }
+  }
+
+  tracker_sparql_cursor_next_async (evt->cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_evt_update_orphan_item_cb,
+                                    (gpointer) evt);
+}
+
+static void
+tracker_evt_update_orphans_cb (GObject              *object,
+                               GAsyncResult         *result,
+                               tracker_evt_update_t *evt)
+{
+  GError *error = NULL;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (evt->cursor != NULL)
+    g_object_unref (evt->cursor);
+  evt->cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
+                                                        result, &error);
+
+  if (error != NULL) {
+    GRL_WARNING ("Could not execute sparql query: %s", error->message);
+
+    g_error_free (error);
+    tracker_evt_postupdate_sources (evt);
+    return;
+  }
+
+  tracker_sparql_cursor_next_async (evt->cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_evt_update_orphan_item_cb,
+                                    (gpointer) evt);
+}
+
+static void
+tracker_evt_update_orphans (tracker_evt_update_t *evt)
+{
+  guint id;
+  gchar *str_id;
+  GString *request_str;
+  GList *subject, *subjects;
+  GrlMedia *media;
+  GList *source, *sources;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (g_hash_table_size (evt->orphan_items) < 1) {
+    tracker_evt_postupdate_sources (evt);
+    return;
+  }
+
+  sources = grl_plugin_registry_get_sources (grl_plugin_registry_get_default (),
+					     FALSE);
+
+  request_str = g_string_new (TRACKER_MEDIA_ITEM_START);
+  subjects = g_hash_table_get_keys (evt->orphan_items);
+
+  subject = subjects;
+  while (subject != NULL) {
+    id = GPOINTER_TO_INT (subject->data);
+    if (GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
+					      subject->data)) != GRL_CONTENT_REMOVED) {
+      g_string_append_printf (request_str, "%u", id);
+      break;
+    } else {
+      /* Notify all sources that a been removed */
+      media = grl_media_new ();
+      str_id = g_strdup_printf ("%u", id);
+      grl_media_set_id (media, str_id);
+      g_free (str_id);
+
+      source = sources;
+      while (source != NULL) {
+	if (GRL_IS_TRACKER_MEDIA (source->data)) {
+	  GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
+                     grl_metadata_source_get_name (GRL_METADATA_SOURCE (source->data)),
+                     source->data);
+	  if (grl_tracker_media_can_notify (GRL_TRACKER_MEDIA (source->data)))
+	    grl_media_source_notify_change (GRL_MEDIA_SOURCE (source->data),
+                                            media, GRL_CONTENT_REMOVED, FALSE);
+	}
+	source = source->next;
+      }
+      g_object_unref (media);
+    }
+    subject = subject->next;
+  }
+
+  if (subject != NULL) {
+    subject = subject->next;
+    while (subject != NULL) {
+      id = GPOINTER_TO_INT (subject->data);
+      if (GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
+						subject->data)) != GRL_CONTENT_REMOVED) {
+	g_string_append_printf (request_str, ", %u", id);
+      } else {
+	/* Notify all sources that a been removed */
+        media = grl_media_new ();
+	str_id = g_strdup_printf ("%u", id);
+	grl_media_set_id (media, str_id);
+	g_free (str_id);
+
+	source = sources;
+	while (source != NULL) {
+	  if (GRL_IS_TRACKER_MEDIA (source->data)) {
+	    GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
+                       grl_metadata_source_get_name (GRL_METADATA_SOURCE (source->data)),
+                       source->data);
+	    if (grl_tracker_media_can_notify (GRL_TRACKER_MEDIA (source->data)))
+              grl_media_source_notify_change (GRL_MEDIA_SOURCE (source->data),
+                                              media, GRL_CONTENT_REMOVED, FALSE);
+	  }
+	  source = source->next;
+	}
+        g_object_unref (media);
+      }
+      subject = subject->next;
+    }
+    g_list_free (subjects);
+
+    g_string_append (request_str, TRACKER_MEDIA_ITEM_END);
+
+    GRL_DEBUG ("\trequest : '%s'", request_str->str);
+
+    tracker_sparql_connection_query_async (grl_tracker_connection,
+                                           request_str->str,
+					   NULL,
+                                           (GAsyncReadyCallback) tracker_evt_update_orphans_cb,
+					   evt);
+  } else {
+    tracker_evt_postupdate_sources (evt);
+  }
+
+  g_string_free (request_str, TRUE);
+}
+
+static void
+tracker_evt_update_items_cb (gpointer              key,
+                             gpointer              value,
+                             tracker_evt_update_t *evt)
+{
+  guint id = GPOINTER_TO_INT (key);
+  gchar *str_id;
+  GrlTrackerMedia *source = (GrlTrackerMedia *) value;
+  GrlMedia *media;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (!source) {
+    g_assert ("\tnot in cache ???");
+    return;
+  }
+
+  if (!grl_tracker_media_can_notify (source)) {
+    GRL_DEBUG ("\tno notification for source %s...",
+	       grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)));
+    return;
+  }
+
+  media = grl_media_new ();
+  str_id = g_strdup_printf ("%i", id);
+  grl_media_set_id (media, str_id);
+  g_free (str_id);
+
+  GRL_DEBUG ("\tNotify id=%u source=%s", id,
+             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)));
+  grl_media_source_notify_change (GRL_MEDIA_SOURCE (source), media,
+                                  evt->change_type, FALSE);
+
+  g_object_unref (media);
+}
+
+static void
+tracker_evt_update_items (tracker_evt_update_t *evt)
+{
+  evt->change_type = GRL_CONTENT_REMOVED;
+  g_hash_table_foreach (evt->deleted_items,
+                        (GHFunc) tracker_evt_update_items_cb, evt);
+  evt->change_type = GRL_CONTENT_ADDED;
+  g_hash_table_foreach (evt->inserted_items,
+                        (GHFunc) tracker_evt_update_items_cb, evt);
+  evt->change_type = GRL_CONTENT_CHANGED;
+  g_hash_table_foreach (evt->updated_items,
+                        (GHFunc) tracker_evt_update_items_cb, evt);
+}
+
+static void
+tracker_evt_preupdate_sources_item_cb (GObject              *object,
+                                       GAsyncResult         *result,
+                                       tracker_evt_update_t *evt)
+{
+  const gchar *type, *datasource, *uri, *datasource_name;
+  gboolean source_available;
+  GrlTrackerMedia *source;
+  GError *error = NULL;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (!tracker_sparql_cursor_next_finish (evt->cursor, result, &error)) {
+    if (error != NULL) {
+      GRL_DEBUG ("\terror in parsing : %s", error->message);
+      g_error_free (error);
+    } else {
+      GRL_DEBUG ("\tend of parsing... start notifying sources");
+    }
+
+    /* Once all sources have been preupdated, start items
+       updates. */
+    tracker_evt_update_items (evt);
+    tracker_evt_update_orphans (evt);
+
+    return;
+  }
+
+  type = tracker_sparql_cursor_get_string (evt->cursor, 0, NULL);
+  datasource = tracker_sparql_cursor_get_string (evt->cursor, 1, NULL);
+  datasource_name = tracker_sparql_cursor_get_string (evt->cursor, 2, NULL);
+  uri = tracker_sparql_cursor_get_string (evt->cursor, 3, NULL);
+  source_available = tracker_sparql_cursor_get_boolean (evt->cursor, 4);
+
+  source = grl_tracker_media_find (datasource);
+
+  GRL_DEBUG ("\tdatasource=%s uri=%s available=%i source=%p",
+             datasource, uri, source_available, source);
+
+  if (source_available) {
+    if (source == NULL) {
+      gchar *source_name = grl_tracker_get_media_name (type, uri, datasource,
+                                                       datasource_name);
+      /* Defer source creation until we have processed all sources */
+      tracker_evt_update_media_add (evt, datasource, source_name);
+      g_free (source_name);
+    } else {
+      GRL_DEBUG ("\tChanges on source %p / %s", source, datasource);
+    }
+  } else if (!source_available && source != NULL) {
+    tracker_evt_update_media_del (evt, GRL_TRACKER_MEDIA (source));
+  }
+
+  tracker_sparql_cursor_next_async (evt->cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_evt_preupdate_sources_item_cb,
+                                    (gpointer) evt);
+}
+
+static void
+tracker_evt_preupdate_sources_cb (GObject              *object,
+                                  GAsyncResult         *result,
+                                  tracker_evt_update_t *evt)
+{
+  GError *error = NULL;
+
+  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
+
+  if (evt->cursor != NULL)
+    g_object_unref (evt->cursor);
+  evt->cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
+                                                        result, &error);
+
+  if (error != NULL) {
+    GRL_WARNING ("\tCannot handle datasource request : %s", error->message);
+
+    g_error_free (error);
+    tracker_evt_update_free (evt);
+    return;
+  }
+
+  tracker_sparql_cursor_next_async (evt->cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_evt_preupdate_sources_item_cb,
+                                    (gpointer) evt);
+}
+
+static void
+tracker_evt_preupdate_sources (tracker_evt_update_t *evt)
+{
+  tracker_sparql_connection_query_async (grl_tracker_connection,
+                                         TRACKER_DATASOURCES_REQUEST,
+                                         NULL,
+                                         (GAsyncReadyCallback) tracker_evt_preupdate_sources_cb,
+                                         evt);
+}
+
+static void
+tracker_dbus_signal_cb (GDBusConnection *connection,
+                        const gchar     *sender_name,
+                        const gchar     *object_path,
+                        const gchar     *interface_name,
+                        const gchar     *signal_name,
+                        GVariant        *parameters,
+                        gpointer         user_data)
+
+{
+  gchar *class_name;
+  gint graph = 0, subject = 0, predicate = 0, object = 0;
+  GVariantIter *iter1, *iter2;
+  tracker_evt_update_t *evt = tracker_evt_update_new ();
+
+  g_variant_get (parameters, "(&sa(iiii)a(iiii))", &class_name, &iter1, &iter2);
+
+  GRL_DEBUG ("\tTracker update event for class=%s ins=%lu del=%lu evt=%p",
+             class_name,
+             (unsigned long) g_variant_iter_n_children (iter1),
+             (unsigned long) g_variant_iter_n_children (iter2),
+	     evt);
+
+  /* Avoid processing item from uninteresting classes */
+  if (g_str_has_suffix (class_name, RDF_TYPE_MUSIC) ||
+      g_str_has_suffix (class_name, RDF_TYPE_AUDIO) ||
+      g_str_has_suffix (class_name, RDF_TYPE_VIDEO) ||
+      g_str_has_suffix (class_name, RDF_TYPE_IMAGE)) {
+
+    /* Process deleted items */
+    while (g_variant_iter_loop (iter1, "(iiii)", &graph,
+                                &subject, &predicate, &object)) {
+      gpointer psubject = GSIZE_TO_POINTER (subject);
+      GrlTrackerMedia *source =
+        grl_tracker_media_cache_get_source (grl_tracker_item_cache, subject);
+
+      /* GRL_DEBUG ("\tdelete=> subject=%i", subject); */
+
+      if (source) {
+        g_hash_table_insert (evt->deleted_items, psubject,
+                             g_object_ref (source));
+      } else {
+        g_hash_table_insert (evt->orphan_items, psubject,
+                             GSIZE_TO_POINTER (GRL_CONTENT_REMOVED));
+      }
+    }
+
+    /* Process inserted items */
+    while (g_variant_iter_loop (iter2, "(iiii)", &graph,
+                                &subject, &predicate, &object)) {
+      gpointer psubject = GSIZE_TO_POINTER (subject);
+      GrlTrackerMedia *source =
+        grl_tracker_media_cache_get_source (grl_tracker_item_cache, subject);
+
+      /* GRL_DEBUG ("\tinsert=> subject=%i", subject); */
+
+      if (source) {
+        /* Removed & inserted items are probably just renamed items... */
+        if (g_hash_table_lookup (evt->deleted_items, psubject)) {
+          g_hash_table_remove (evt->deleted_items, psubject);
+          g_hash_table_insert (evt->updated_items, psubject,
+                               g_object_ref (source));
+        } else if (!g_hash_table_lookup (evt->updated_items, psubject)) {
+          g_hash_table_insert (evt->inserted_items, psubject,
+                               g_object_ref (source));
+        }
+      } else {
+        gpointer state;
+
+        if (g_hash_table_lookup_extended (evt->orphan_items, psubject,
+                                          NULL, &state) &&
+            (GPOINTER_TO_INT (state) == GRL_CONTENT_REMOVED)) {
+          g_hash_table_insert (evt->orphan_items, psubject,
+                               GSIZE_TO_POINTER (GRL_CONTENT_CHANGED));
+        } else {
+          g_hash_table_insert (evt->orphan_items, psubject,
+                               GSIZE_TO_POINTER (GRL_CONTENT_ADDED));
+        }
+      }
+    }
+  }
+
+  g_variant_iter_free (iter1);
+  g_variant_iter_free (iter2);
+
+  GRL_DEBUG ("\tinserted=%i deleted=%i updated=%i orphan=%i",
+             g_hash_table_size (evt->inserted_items),
+             g_hash_table_size (evt->deleted_items),
+             g_hash_table_size (evt->updated_items),
+	     g_hash_table_size (evt->orphan_items));
+
+  if (grl_tracker_per_device_source) {
+    tracker_evt_preupdate_sources (evt);
+  } else {
+    tracker_evt_update_items (evt);
+    tracker_evt_update_orphans (evt);
+  }
+}
+
+void
+grl_tracker_media_dbus_start_watch (void)
+{
+  GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+
+  tracker_dbus_signal_id = g_dbus_connection_signal_subscribe (connection,
+                                                               TRACKER_DBUS_SERVICE,
+                                                               TRACKER_DBUS_INTERFACE_RESOURCES,
+                                                               "GraphUpdated",
+                                                               TRACKER_DBUS_OBJECT_RESOURCES,
+                                                               NULL,
+                                                               G_DBUS_SIGNAL_FLAGS_NONE,
+                                                               tracker_dbus_signal_cb,
+                                                               NULL,
+                                                               NULL);
+}
+
+void
+grl_tracker_media_init_notifs (void)
+{
+  GRL_LOG_DOMAIN_INIT (tracker_notif_log_domain, "tracker-notif");
+}
diff --git a/src/media/tracker/grl-tracker-media-notif.h b/src/media/tracker/grl-tracker-media-notif.h
new file mode 100644
index 0000000..67eeba8
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-notif.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_MEDIA_NOTIF_H_
+#define _GRL_TRACKER_MEDIA_NOTIF_H_
+
+#include "grl-tracker-media.h"
+
+/* ------- Definitions ------- */
+
+#define TRACKER_DATASOURCES_REQUEST                                     \
+  "SELECT "                                                             \
+  "(SELECT GROUP_CONCAT(rdf:type(?source), \":\") "                     \
+  " WHERE { ?urn nie:dataSource ?source }) "                            \
+  "nie:dataSource(?urn) "                                               \
+  "(SELECT GROUP_CONCAT(nie:title(?source), \":\") "                    \
+  " WHERE { ?urn nie:dataSource ?source }) "                            \
+  "(SELECT GROUP_CONCAT(nie:url(tracker:mountPoint(?source)), \":\") "  \
+  " WHERE { ?urn nie:dataSource ?source }) "                            \
+  "tracker:available(?urn) "                                            \
+  "WHERE "                                                              \
+  "{ "                                                                  \
+  "?urn a nfo:FileDataObject . FILTER (bound(nie:dataSource(?urn)))"    \
+  "} "                                                                  \
+  "GROUP BY (nie:dataSource(?urn))"
+
+/**/
+
+void grl_tracker_media_dbus_start_watch (void);
+
+void grl_tracker_media_init_notifs (void);
+
+#endif /* _GRL_TRACKER_MEDIA_NOTIF_H_ */
diff --git a/src/media/tracker/grl-tracker-media-priv.h b/src/media/tracker/grl-tracker-media-priv.h
new file mode 100644
index 0000000..0446de2
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media-priv.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_MEDIA_PRIV_H_
+#define _GRL_TRACKER_MEDIA_PRIV_H_
+
+#include "grl-tracker-media.h"
+#include "grl-tracker-media-cache.h"
+
+#include <tracker-sparql.h>
+
+/* ---- Plugin information --- */
+
+#define GRL_TRACKER_PLUGIN_ID   TRACKER_PLUGIN_ID
+
+#define GRL_TRACKER_MEDIA_ID   "grl-tracker"
+#define GRL_TRACKER_MEDIA_NAME "Tracker"
+#define GRL_TRACKER_MEDIA_DESC                 \
+  "A plugin for searching multimedia "          \
+  "content using Tracker"
+
+#define GRL_TRACKER_AUTHOR  "Igalia S.L."
+#define GRL_TRACKER_LICENSE "LGPL"
+#define GRL_TRACKER_SITE    "http://www.igalia.com";
+
+/**/
+
+#define GRL_TRACKER_MEDIA_GET_PRIVATE(object)		\
+  (G_TYPE_INSTANCE_GET_PRIVATE((object),                \
+                               GRL_TRACKER_MEDIA_TYPE,	\
+                               GrlTrackerMediaPriv))
+
+typedef enum {
+  GRL_TRACKER_MEDIA_STATE_INSERTING,
+  GRL_TRACKER_MEDIA_STATE_RUNNING,
+  GRL_TRACKER_MEDIA_STATE_DELETING,
+  GRL_TRACKER_MEDIA_STATE_DELETED,
+} GrlTrackerMediaState;
+
+struct _GrlTrackerMediaPriv {
+  TrackerSparqlConnection *tracker_connection;
+
+  GHashTable *operations;
+
+  gchar *tracker_datasource;
+  gboolean notify_changes;
+
+  GrlTrackerMediaState state;
+  guint notification_ref;
+};
+
+/**/
+
+extern TrackerSparqlConnection *grl_tracker_connection;
+extern const GrlPluginInfo *grl_tracker_plugin;
+
+/* shared data across  */
+extern GrlTrackerCache *grl_tracker_item_cache;
+extern GHashTable *grl_tracker_modified_sources;
+
+/* tracker plugin config */
+extern gboolean grl_tracker_per_device_source;
+extern gboolean grl_tracker_browse_filesystem;
+
+#endif /* _GRL_TRACKER_MEDIA_PRIV_H_ */
diff --git a/src/media/tracker/grl-tracker-media.c b/src/media/tracker/grl-tracker-media.c
new file mode 100644
index 0000000..1ac906f
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * 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-media.h"
+#include "grl-tracker-media-priv.h"
+#include "grl-tracker-media-api.h"
+#include "grl-tracker-media-cache.h"
+#include "grl-tracker-media-notif.h"
+#include "grl-tracker-utils.h"
+
+/* --------- Logging  -------- */
+
+#define GRL_LOG_DOMAIN_DEFAULT tracker_general_log_domain
+GRL_LOG_DOMAIN_STATIC(tracker_general_log_domain);
+
+/* ------- Definitions ------- */
+
+#define MEDIA_TYPE "grilo-media-type"
+
+#define TRACKER_ITEM_CACHE_SIZE (10000)
+
+/* --- Other --- */
+
+enum {
+  PROP_0,
+  PROP_TRACKER_CONNECTION,
+};
+
+static GrlTrackerMedia *grl_tracker_media_new (TrackerSparqlConnection *connection);
+
+static void grl_tracker_media_set_property (GObject      *object,
+                                             guint         propid,
+                                             const GValue *value,
+                                             GParamSpec   *pspec);
+
+static void grl_tracker_media_constructed (GObject *object);
+
+static void grl_tracker_media_finalize (GObject *object);
+
+gboolean grl_tracker_plugin_init (GrlPluginRegistry *registry,
+                                  const GrlPluginInfo *plugin,
+                                  GList *configs);
+
+/* ===================== Globals  ================= */
+
+TrackerSparqlConnection *grl_tracker_connection = NULL;
+const GrlPluginInfo *grl_tracker_plugin;
+
+/* shared data across  */
+GrlTrackerCache *grl_tracker_item_cache;
+GHashTable *grl_tracker_modified_sources;
+
+/* tracker plugin config */
+gboolean grl_tracker_per_device_source = FALSE;
+gboolean grl_tracker_browse_filesystem = FALSE;
+
+/* =================== Tracker Plugin  =============== */
+
+void
+grl_tracker_add_source (GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  GRL_DEBUG ("====================>add source '%s' count=%u",
+             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
+             priv->notification_ref);
+
+  if (priv->notification_ref > 0) {
+    priv->notification_ref--;
+  }
+  if (priv->notification_ref == 0) {
+    g_hash_table_remove (grl_tracker_modified_sources,
+                         grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)));
+    priv->state = GRL_TRACKER_MEDIA_STATE_RUNNING;
+    grl_plugin_registry_register_source (grl_plugin_registry_get_default (),
+                                         grl_tracker_plugin,
+                                         GRL_MEDIA_PLUGIN (source),
+                                         NULL);
+  }
+}
+
+void
+grl_tracker_del_source (GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  GRL_DEBUG ("==================>del source '%s' count=%u",
+             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
+             priv->notification_ref);
+  if (priv->notification_ref > 0) {
+    priv->notification_ref--;
+  }
+  if (priv->notification_ref == 0) {
+    g_hash_table_remove (grl_tracker_modified_sources,
+                         grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)));
+    grl_tracker_media_cache_del_source (grl_tracker_item_cache, source);
+    priv->state = GRL_TRACKER_MEDIA_STATE_DELETED;
+    grl_plugin_registry_unregister_source (grl_plugin_registry_get_default (),
+                                           GRL_MEDIA_PLUGIN (source),
+                                           NULL);
+  }
+}
+
+gboolean
+grl_tracker_media_can_notify (GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  if (priv->state == GRL_TRACKER_MEDIA_STATE_RUNNING)
+    return priv->notify_changes;
+
+  return FALSE;
+}
+
+GrlTrackerMedia *
+grl_tracker_media_find (const gchar *id)
+{
+  GrlMediaPlugin *source;
+
+  source = grl_plugin_registry_lookup_source (grl_plugin_registry_get_default (),
+					      id);
+
+  if (source && GRL_IS_TRACKER_MEDIA (source)) {
+    return (GrlTrackerMedia *) source;
+  }
+
+  return
+    (GrlTrackerMedia *) g_hash_table_lookup (grl_tracker_modified_sources,
+                                             id);
+}
+
+static void
+tracker_get_datasource_cb (GObject             *object,
+                           GAsyncResult        *result,
+                           TrackerSparqlCursor *cursor)
+{
+  const gchar *type, *datasource, *datasource_name, *uri;
+  gboolean source_available;
+  GError *error = NULL;
+  GrlTrackerMedia *source;
+
+  GRL_DEBUG ("%s", __FUNCTION__);
+
+  if (!tracker_sparql_cursor_next_finish (cursor, result, &error)) {
+    if (error == NULL) {
+      GRL_DEBUG ("\tEnd of parsing of devices");
+    } else {
+      GRL_WARNING ("\tError while parsing devices: %s", error->message);
+      g_error_free (error);
+    }
+    g_object_unref (G_OBJECT (cursor));
+    return;
+  }
+
+  type = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+  datasource = tracker_sparql_cursor_get_string (cursor, 1, NULL);
+  datasource_name = tracker_sparql_cursor_get_string (cursor, 2, NULL);
+  uri = tracker_sparql_cursor_get_string (cursor, 3, NULL);
+  source_available = tracker_sparql_cursor_get_boolean (cursor, 4);
+
+  source = grl_tracker_media_find (datasource);
+
+  if ((source == NULL) && source_available) {
+    gchar *source_name = grl_tracker_get_media_name (type, uri, datasource,
+                                                     datasource_name);
+    GRL_DEBUG ("\tnew datasource: urn=%s name=%s uri=%s\n",
+	       datasource, datasource_name, uri);
+    source = g_object_new (GRL_TRACKER_MEDIA_TYPE,
+                           "source-id", datasource,
+                           "source-name", source_name,
+                           "source-desc", GRL_TRACKER_MEDIA_DESC,
+                           "tracker-connection", grl_tracker_connection,
+                           NULL);
+    grl_tracker_add_source (source);
+    g_free (source_name);
+  }
+
+  tracker_sparql_cursor_next_async (cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_get_datasource_cb,
+                                    cursor);
+}
+
+static void
+tracker_get_datasources_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      data)
+{
+  GError *error = NULL;
+  TrackerSparqlCursor *cursor;
+
+  GRL_DEBUG ("%s", __FUNCTION__);
+
+  cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
+                                                   result, &error);
+
+  if (error) {
+    GRL_WARNING ("Cannot handle datasource request : %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  tracker_sparql_cursor_next_async (cursor, NULL,
+                                    (GAsyncReadyCallback) tracker_get_datasource_cb,
+                                    cursor);
+}
+
+static void
+tracker_get_connection_cb (GObject             *object,
+                           GAsyncResult        *res,
+                           const GrlPluginInfo *plugin)
+{
+  /* GrlTrackerMedia *source; */
+
+  GRL_DEBUG ("%s", __FUNCTION__);
+
+  grl_tracker_connection = tracker_sparql_connection_get_finish (res, NULL);
+
+  if (grl_tracker_connection != NULL) {
+    grl_tracker_media_dbus_start_watch ();
+
+    if (grl_tracker_per_device_source == TRUE) {
+      /* Let's discover available data sources. */
+      GRL_DEBUG ("\tper device source mode request: '"
+                 TRACKER_DATASOURCES_REQUEST "'");
+
+      tracker_sparql_connection_query_async (grl_tracker_connection,
+                                             TRACKER_DATASOURCES_REQUEST,
+                                             NULL,
+                                             (GAsyncReadyCallback) tracker_get_datasources_cb,
+                                             NULL);
+    } else {
+      /* One source to rule them all. */
+      grl_tracker_add_source (grl_tracker_media_new (grl_tracker_connection));
+    }
+  }
+}
+
+gboolean
+grl_tracker_plugin_init (GrlPluginRegistry *registry,
+                         const GrlPluginInfo *plugin,
+                         GList *configs)
+{
+  GrlConfig *config;
+  gint config_count;
+
+  GRL_DEBUG ("%s", __FUNCTION__);
+
+  GRL_LOG_DOMAIN_INIT (tracker_general_log_domain, "tracker-general");
+  grl_tracker_media_init_notifs ();
+  grl_tracker_media_init_requests ();
+
+  grl_tracker_plugin = plugin;
+  grl_tracker_item_cache =
+    grl_tracker_media_cache_new (TRACKER_ITEM_CACHE_SIZE);
+  grl_tracker_modified_sources = g_hash_table_new (g_str_hash, g_str_equal);
+
+  if (!configs) {
+    GRL_WARNING ("\tConfiguration not provided! Using default configuration.");
+  } else {
+    config_count = g_list_length (configs);
+    if (config_count > 1) {
+      GRL_WARNING ("\tProvided %i configs, but will only use one", config_count);
+    }
+
+    config = GRL_CONFIG (configs->data);
+
+    grl_tracker_per_device_source =
+      grl_config_get_boolean (config, "per-device-source");
+    grl_tracker_browse_filesystem =
+      grl_config_get_boolean (config, "browse-filesystem");
+  }
+
+  tracker_sparql_connection_get_async (NULL,
+                                       (GAsyncReadyCallback) tracker_get_connection_cb,
+                                       (gpointer) plugin);
+  return TRUE;
+}
+
+GRL_PLUGIN_REGISTER (grl_tracker_plugin_init,
+                     NULL,
+                     GRL_TRACKER_PLUGIN_ID);
+
+/* ================== Tracker GObject ================ */
+
+static GrlTrackerMedia *
+grl_tracker_media_new (TrackerSparqlConnection *connection)
+{
+  GRL_DEBUG ("%s", __FUNCTION__);
+
+  return g_object_new (GRL_TRACKER_MEDIA_TYPE,
+                       "source-id", GRL_TRACKER_MEDIA_ID,
+                       "source-name", GRL_TRACKER_MEDIA_NAME,
+                       "source-desc", GRL_TRACKER_MEDIA_DESC,
+                       "tracker-connection", connection,
+                       NULL);
+}
+
+G_DEFINE_TYPE (GrlTrackerMedia, grl_tracker_media, GRL_TYPE_MEDIA_SOURCE);
+
+static void
+grl_tracker_media_class_init (GrlTrackerMediaClass * 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_media_query;
+  source_class->metadata            = grl_tracker_media_metadata;
+  source_class->search              = grl_tracker_media_search;
+  source_class->browse              = grl_tracker_media_browse;
+  source_class->cancel              = grl_tracker_media_cancel;
+  source_class->notify_change_start = grl_tracker_media_change_start;
+  source_class->notify_change_stop  = grl_tracker_media_change_stop;
+
+  metadata_class->supported_keys = grl_tracker_media_supported_keys;
+
+  g_class->finalize     = grl_tracker_media_finalize;
+  g_class->set_property = grl_tracker_media_set_property;
+  g_class->constructed  = grl_tracker_media_constructed;
+
+  g_object_class_install_property (g_class,
+                                   PROP_TRACKER_CONNECTION,
+                                   g_param_spec_object ("tracker-connection",
+                                                        "tracker connection",
+                                                        "A Tracker connection",
+                                                        TRACKER_SPARQL_TYPE_CONNECTION,
+                                                        G_PARAM_WRITABLE
+                                                        | G_PARAM_CONSTRUCT_ONLY
+                                                        | G_PARAM_STATIC_NAME));
+
+  g_type_class_add_private (klass, sizeof (GrlTrackerMediaPriv));
+
+  grl_tracker_setup_key_mappings ();
+}
+
+static void
+grl_tracker_media_init (GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+
+  source->priv = priv;
+
+  priv->operations = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static void
+grl_tracker_media_constructed (GObject *object)
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (object);
+
+  if (grl_tracker_per_device_source)
+    g_object_get (object, "source-id", &priv->tracker_datasource, NULL);
+}
+
+static void
+grl_tracker_media_finalize (GObject *object)
+{
+  GrlTrackerMedia *self;
+
+  self = GRL_TRACKER_MEDIA (object);
+  if (self->priv->tracker_connection)
+    g_object_unref (self->priv->tracker_connection);
+
+  G_OBJECT_CLASS (grl_tracker_media_parent_class)->finalize (object);
+}
+
+static void
+grl_tracker_media_set_property (GObject      *object,
+                                 guint         propid,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+
+{
+  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (object);
+
+  switch (propid) {
+    case PROP_TRACKER_CONNECTION:
+      if (priv->tracker_connection != NULL)
+        g_object_unref (G_OBJECT (priv->tracker_connection));
+      priv->tracker_connection = g_object_ref (g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
diff --git a/src/media/tracker/grl-tracker-media.h b/src/media/tracker/grl-tracker-media.h
new file mode 100644
index 0000000..6b484c2
--- /dev/null
+++ b/src/media/tracker/grl-tracker-media.h
@@ -0,0 +1,88 @@
+/*
+ * 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_MEDIA_H_
+#define _GRL_TRACKER_MEDIA_H_
+
+#include <grilo.h>
+
+#define GRL_TRACKER_MEDIA_TYPE                  \
+  (grl_tracker_media_get_type ())
+
+#define GRL_TRACKER_MEDIA(obj)                          \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                   \
+                               GRL_TRACKER_MEDIA_TYPE,  \
+                               GrlTrackerMedia))
+
+#define GRL_IS_TRACKER_MEDIA(obj)                       \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                   \
+                               GRL_TRACKER_MEDIA_TYPE))
+
+#define GRL_TRACKER_MEDIA_CLASS(klass)                  \
+  (G_TYPE_CHECK_CLASS_CAST((klass),                     \
+                           GRL_TRACKER_MEDIA_TYPE,      \
+                           GrlTrackerMediaClass))
+
+#define GRL_IS_TRACKER_MEDIA_CLASS(klass)               \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),                     \
+                           GRL_TRACKER_MEDIA_TYPE))
+
+#define GRL_TRACKER_MEDIA_GET_CLASS(obj)                \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                    \
+                              GRL_TRACKER_MEDIA_TYPE,   \
+                              GrlTrackerMediaClass))
+
+typedef struct _GrlTrackerMedia GrlTrackerMedia;
+typedef struct _GrlTrackerMediaPriv GrlTrackerMediaPriv;
+
+struct _GrlTrackerMedia {
+
+  GrlMediaSource parent;
+
+  /*< private >*/
+  GrlTrackerMediaPriv *priv;
+
+};
+
+typedef struct _GrlTrackerMediaClass GrlTrackerMediaClass;
+
+struct _GrlTrackerMediaClass {
+
+  GrlMediaSourceClass parent_class;
+
+};
+
+GType grl_tracker_media_get_type (void);
+
+gboolean grl_tracker_media_can_notify (GrlTrackerMedia *source);
+
+/**/
+void grl_tracker_add_source (GrlTrackerMedia *source);
+
+void grl_tracker_del_source (GrlTrackerMedia *source);
+
+GrlTrackerMedia *grl_tracker_media_find (const gchar *id);
+
+
+#endif /* _GRL_TRACKER_MEDIA_H_ */
diff --git a/src/media/tracker/grl-tracker-notif.c b/src/media/tracker/grl-tracker-notif.c
deleted file mode 100644
index df70d10..0000000
--- a/src/media/tracker/grl-tracker-notif.c
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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 <tracker-sparql.h>
-
-#include "grl-tracker-notif.h"
-#include "grl-tracker-priv.h"
-#include "grl-tracker-utils.h"
-
-/* --------- Logging  -------- */
-
-#define GRL_LOG_DOMAIN_DEFAULT tracker_notif_log_domain
-GRL_LOG_DOMAIN_STATIC(tracker_notif_log_domain);
-
-/* ------- Definitions ------- */
-
-#define TRACKER_SOURCE_ITEM_START                                       \
-  "SELECT rdf:type(?urn) tracker:id(?urn) nie:dataSource(?urn) "	\
-  "WHERE { ?urn a nfo:FileDataObject . "                                \
-  "FILTER (tracker:id(?urn) IN ("
-
-#define TRACKER_SOURCE_ITEM_END ")) }"
-
-/**/
-
-typedef struct {
-  /* tables of items for which we know the source */
-  GHashTable *inserted_items;
-  GHashTable *deleted_items;
-  GHashTable *updated_items;
-
-  /* table of items for which we don't know the source */
-  GHashTable *orphan_items;
-
-  /* List of new/old sources */
-  GList *new_sources;
-  GList *old_sources;
-
-  /* Convenient stuff (for tracker/own callbacks...) */
-  TrackerSparqlCursor      *cursor;
-  gboolean                  in_use;
-  GrlMediaSourceChangeType  change_type;
-} tracker_evt_update_t;
-
-/**/
-
-static guint tracker_dbus_signal_id = 0;
-
-/**/
-static tracker_evt_update_t *
-tracker_evt_update_new (void)
-{
-  tracker_evt_update_t *evt = g_slice_new0 (tracker_evt_update_t);
-
-  evt->inserted_items = g_hash_table_new (g_direct_hash, g_direct_equal);
-  evt->deleted_items = g_hash_table_new (g_direct_hash, g_direct_equal);
-  evt->updated_items = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-  evt->orphan_items = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-  return evt;
-}
-
-static void
-tracker_evt_update_free (tracker_evt_update_t *evt)
-{
-  if (!evt)
-    return;
-
-  g_hash_table_destroy (evt->inserted_items);
-  g_hash_table_destroy (evt->deleted_items);
-  g_hash_table_destroy (evt->updated_items);
-
-  g_hash_table_destroy (evt->orphan_items);
-
-  g_list_free (evt->new_sources);
-  g_list_free (evt->old_sources);
-
-  if (evt->cursor != NULL)
-    g_object_unref (evt->cursor);
-
-  g_slice_free (tracker_evt_update_t, evt);
-}
-
-static void
-tracker_evt_update_source_add (tracker_evt_update_t *evt,
-			       const gchar *id,
-			       const gchar *source_name)
-{
-  GrlTrackerSource *source;
-  GrlTrackerSourcePriv *priv;
-
-  source = g_hash_table_lookup (grl_tracker_modified_sources, id);
-  if (!source) {
-    source = g_object_new (GRL_TRACKER_SOURCE_TYPE,
-			   "source-id", id,
-			   "source-name", source_name,
-			   "source-desc", GRL_TRACKER_SOURCE_DESC,
-			   "tracker-connection", grl_tracker_connection,
-			   NULL);
-    g_hash_table_insert (grl_tracker_modified_sources,
-			 (gpointer) grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)),
-			 source);
-  }
-
-  priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-  priv->state = GRL_TRACKER_SOURCE_STATE_INSERTING;
-  priv->notification_ref++;
-
-  evt->new_sources = g_list_append (evt->new_sources, source);
-
-  GRL_DEBUG ("Preadd source p=%p name=%s id=%s count=%u",
-             source, source_name, id, priv->notification_ref);
-}
-
-static void
-tracker_evt_update_source_del (tracker_evt_update_t *evt,
-			       GrlTrackerSource *source)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  priv->notification_ref++;
-  priv->state = GRL_TRACKER_SOURCE_STATE_DELETING;
-
-  evt->old_sources = g_list_append (evt->old_sources, source);
-
-  GRL_DEBUG ("Predel source p=%p name=%s id=%s count=%u", source,
-             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
-             grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)),
-             priv->notification_ref);
-}
-
-static void
-tracker_evt_postupdate_sources (tracker_evt_update_t *evt)
-{
-  GList *source;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  source = evt->old_sources;
-  while (source != NULL) {
-    grl_tracker_del_source (GRL_TRACKER_SOURCE (source->data));
-    source = source->next;
-  }
-
-  source = evt->new_sources;
-  while (source != NULL) {
-    grl_tracker_add_source (GRL_TRACKER_SOURCE (source->data));
-    source = source->next;
-  }
-
-  tracker_evt_update_free (evt);
-}
-
-static void
-tracker_evt_update_orphan_item_cb (GObject              *object,
-                                   GAsyncResult         *result,
-                                   tracker_evt_update_t *evt)
-{
-  guint id;
-  const gchar *type, *datasource;
-  GrlTrackerSource *source = NULL;
-  GError *error = NULL;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (!tracker_sparql_cursor_next_finish (evt->cursor, result, &error)) {
-    if (error != NULL) {
-      GRL_DEBUG ("\terror in parsing : %s", error->message);
-      g_error_free (error);
-    } else {
-      GRL_DEBUG ("\tend of parsing...");
-    }
-
-    if (grl_tracker_per_device_source) {
-      /* Once all items have been processed, add new sources and we're
-	 done. */
-      tracker_evt_postupdate_sources (evt);
-    }
-
-    return;
-  }
-
-  type = tracker_sparql_cursor_get_string (evt->cursor, 0, NULL);
-  id = tracker_sparql_cursor_get_integer (evt->cursor, 1);
-  datasource = tracker_sparql_cursor_get_string (evt->cursor, 2, NULL);
-
-  GRL_DEBUG ("\tOrphan item: id=%u datasource=%s", id, datasource);
-
-  if (datasource)
-    source = grl_tracker_source_find (datasource);
-
-  if (source && GRL_IS_TRACKER_SOURCE (source)) {
-    GrlMedia *media;
-
-    GRL_DEBUG (" \tAdding to cache id=%u", id);
-    grl_tracker_cache_add_item (grl_tracker_item_cache, id, source);
-
-    if (grl_tracker_source_can_notify (source)) {
-      media = grl_tracker_build_grilo_media (type);
-      if (media) {
-        gchar *str_id = g_strdup_printf ("%i", id);
-        gint change_type =
-          GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
-                                                GSIZE_TO_POINTER (id)));
-
-        grl_media_set_id (media, str_id);
-        g_free (str_id);
-
-        GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
-                   grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
-                   source);
-        grl_media_source_notify_change (GRL_MEDIA_SOURCE (source), media,
-                                        change_type, FALSE);
-
-        g_object_unref (media);
-      }
-    }
-  }
-
-  tracker_sparql_cursor_next_async (evt->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_evt_update_orphan_item_cb,
-                                    (gpointer) evt);
-}
-
-static void
-tracker_evt_update_orphans_cb (GObject              *object,
-                               GAsyncResult         *result,
-                               tracker_evt_update_t *evt)
-{
-  GError *error = NULL;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (evt->cursor != NULL)
-    g_object_unref (evt->cursor);
-  evt->cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
-                                                        result, &error);
-
-  if (error != NULL) {
-    GRL_WARNING ("Could not execute sparql query: %s", error->message);
-
-    g_error_free (error);
-    tracker_evt_postupdate_sources (evt);
-    return;
-  }
-
-  tracker_sparql_cursor_next_async (evt->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_evt_update_orphan_item_cb,
-                                    (gpointer) evt);
-}
-
-static void
-tracker_evt_update_orphans (tracker_evt_update_t *evt)
-{
-  guint id;
-  gchar *str_id;
-  GString *request_str;
-  GList *subject, *subjects;
-  GrlMedia *media;
-  GList *source, *sources;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (g_hash_table_size (evt->orphan_items) < 1) {
-    tracker_evt_postupdate_sources (evt);
-    return;
-  }
-
-  sources = grl_plugin_registry_get_sources (grl_plugin_registry_get_default (),
-					     FALSE);
-
-  request_str = g_string_new (TRACKER_SOURCE_ITEM_START);
-  subjects = g_hash_table_get_keys (evt->orphan_items);
-
-  subject = subjects;
-  while (subject != NULL) {
-    id = GPOINTER_TO_INT (subject->data);
-    if (GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
-					      subject->data)) != GRL_CONTENT_REMOVED) {
-      g_string_append_printf (request_str, "%u", id);
-      break;
-    } else {
-      /* Notify all sources that a been removed */
-      media = grl_media_new ();
-      str_id = g_strdup_printf ("%u", id);
-      grl_media_set_id (media, str_id);
-      g_free (str_id);
-
-      source = sources;
-      while (source != NULL) {
-	if (GRL_IS_TRACKER_SOURCE (source->data)) {
-	  GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
-                     grl_metadata_source_get_name (GRL_METADATA_SOURCE (source->data)),
-                     source->data);
-	  if (grl_tracker_source_can_notify (GRL_TRACKER_SOURCE (source->data)))
-	    grl_media_source_notify_change (GRL_MEDIA_SOURCE (source->data),
-					    media, GRL_CONTENT_REMOVED, FALSE);
-	}
-	source = source->next;
-      }
-      g_object_unref (media);
-    }
-    subject = subject->next;
-  }
-
-  if (subject != NULL) {
-    subject = subject->next;
-    while (subject != NULL) {
-      id = GPOINTER_TO_INT (subject->data);
-      if (GPOINTER_TO_INT (g_hash_table_lookup (evt->orphan_items,
-						subject->data)) != GRL_CONTENT_REMOVED) {
-	g_string_append_printf (request_str, ", %u", id);
-      } else {
-	/* Notify all sources that a been removed */
-        media = grl_media_new ();
-	str_id = g_strdup_printf ("%u", id);
-	grl_media_set_id (media, str_id);
-	g_free (str_id);
-
-	source = sources;
-	while (source != NULL) {
-	  if (GRL_IS_TRACKER_SOURCE (source->data)) {
-	    GRL_DEBUG ("\tNotify id=%u source=%s p=%p", id,
-                       grl_metadata_source_get_name (GRL_METADATA_SOURCE (source->data)),
-                       source->data);
-	    if (grl_tracker_source_can_notify (GRL_TRACKER_SOURCE (source->data)))
-              grl_media_source_notify_change (GRL_MEDIA_SOURCE (source->data),
-                                              media, GRL_CONTENT_REMOVED, FALSE);
-	  }
-	  source = source->next;
-	}
-        g_object_unref (media);
-      }
-      subject = subject->next;
-    }
-    g_list_free (subjects);
-
-    g_string_append (request_str, TRACKER_SOURCE_ITEM_END);
-
-    GRL_DEBUG ("\trequest : '%s'", request_str->str);
-
-    tracker_sparql_connection_query_async (grl_tracker_connection,
-                                           request_str->str,
-					   NULL,
-                                           (GAsyncReadyCallback) tracker_evt_update_orphans_cb,
-					   evt);
-  } else {
-    tracker_evt_postupdate_sources (evt);
-  }
-
-  g_string_free (request_str, TRUE);
-}
-
-static void
-tracker_evt_update_items_cb (gpointer              key,
-                             gpointer              value,
-                             tracker_evt_update_t *evt)
-{
-  guint id = GPOINTER_TO_INT (key);
-  gchar *str_id;
-  GrlTrackerSource *source = (GrlTrackerSource *) value;
-  GrlMedia *media;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (!source) {
-    g_assert ("\tnot in cache ???");
-    return;
-  }
-
-  if (!grl_tracker_source_can_notify (source)) {
-    GRL_DEBUG ("\tno notification for source %s...",
-	       grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)));
-    return;
-  }
-
-  media = grl_media_new ();
-  str_id = g_strdup_printf ("%i", id);
-  grl_media_set_id (media, str_id);
-  g_free (str_id);
-
-  GRL_DEBUG ("\tNotify id=%u source=%s", id,
-             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)));
-  grl_media_source_notify_change (GRL_MEDIA_SOURCE (source), media,
-                                  evt->change_type, FALSE);
-
-  g_object_unref (media);
-}
-
-static void
-tracker_evt_update_items (tracker_evt_update_t *evt)
-{
-  evt->change_type = GRL_CONTENT_REMOVED;
-  g_hash_table_foreach (evt->deleted_items,
-                        (GHFunc) tracker_evt_update_items_cb, evt);
-  evt->change_type = GRL_CONTENT_ADDED;
-  g_hash_table_foreach (evt->inserted_items,
-                        (GHFunc) tracker_evt_update_items_cb, evt);
-  evt->change_type = GRL_CONTENT_CHANGED;
-  g_hash_table_foreach (evt->updated_items,
-                        (GHFunc) tracker_evt_update_items_cb, evt);
-}
-
-static void
-tracker_evt_preupdate_sources_item_cb (GObject              *object,
-                                       GAsyncResult         *result,
-                                       tracker_evt_update_t *evt)
-{
-  const gchar *type, *datasource, *uri, *datasource_name;
-  gboolean source_available;
-  GrlTrackerSource *source;
-  GError *error = NULL;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (!tracker_sparql_cursor_next_finish (evt->cursor, result, &error)) {
-    if (error != NULL) {
-      GRL_DEBUG ("\terror in parsing : %s", error->message);
-      g_error_free (error);
-    } else {
-      GRL_DEBUG ("\tend of parsing... start notifying sources");
-    }
-
-    /* Once all sources have been preupdated, start items
-       updates. */
-    tracker_evt_update_items (evt);
-    tracker_evt_update_orphans (evt);
-
-    return;
-  }
-
-  type = tracker_sparql_cursor_get_string (evt->cursor, 0, NULL);
-  datasource = tracker_sparql_cursor_get_string (evt->cursor, 1, NULL);
-  datasource_name = tracker_sparql_cursor_get_string (evt->cursor, 2, NULL);
-  uri = tracker_sparql_cursor_get_string (evt->cursor, 3, NULL);
-  source_available = tracker_sparql_cursor_get_boolean (evt->cursor, 4);
-
-  source = grl_tracker_source_find (datasource);
-
-  GRL_DEBUG ("\tdatasource=%s uri=%s available=%i source=%p",
-             datasource, uri, source_available, source);
-
-  if (source_available) {
-    if (source == NULL) {
-      gchar *source_name = grl_tracker_get_source_name (type, uri, datasource,
-                                                        datasource_name);
-      /* Defer source creation until we have processed all sources */
-      tracker_evt_update_source_add (evt, datasource, source_name);
-      g_free (source_name);
-    } else {
-      GRL_DEBUG ("\tChanges on source %p / %s", source, datasource);
-    }
-  } else if (!source_available && source != NULL) {
-    tracker_evt_update_source_del (evt, GRL_TRACKER_SOURCE (source));
-  }
-
-  tracker_sparql_cursor_next_async (evt->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_evt_preupdate_sources_item_cb,
-                                    (gpointer) evt);
-}
-
-static void
-tracker_evt_preupdate_sources_cb (GObject              *object,
-                                  GAsyncResult         *result,
-                                  tracker_evt_update_t *evt)
-{
-  GError *error = NULL;
-
-  GRL_DEBUG ("%s: evt=%p", __FUNCTION__, evt);
-
-  if (evt->cursor != NULL)
-    g_object_unref (evt->cursor);
-  evt->cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
-                                                        result, &error);
-
-  if (error != NULL) {
-    GRL_WARNING ("\tCannot handle datasource request : %s", error->message);
-
-    g_error_free (error);
-    tracker_evt_update_free (evt);
-    return;
-  }
-
-  tracker_sparql_cursor_next_async (evt->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_evt_preupdate_sources_item_cb,
-                                    (gpointer) evt);
-}
-
-static void
-tracker_evt_preupdate_sources (tracker_evt_update_t *evt)
-{
-  tracker_sparql_connection_query_async (grl_tracker_connection,
-                                         TRACKER_DATASOURCES_REQUEST,
-                                         NULL,
-                                         (GAsyncReadyCallback) tracker_evt_preupdate_sources_cb,
-                                         evt);
-}
-
-static void
-tracker_dbus_signal_cb (GDBusConnection *connection,
-                        const gchar     *sender_name,
-                        const gchar     *object_path,
-                        const gchar     *interface_name,
-                        const gchar     *signal_name,
-                        GVariant        *parameters,
-                        gpointer         user_data)
-
-{
-  gchar *class_name;
-  gint graph = 0, subject = 0, predicate = 0, object = 0;
-  GVariantIter *iter1, *iter2;
-  tracker_evt_update_t *evt = tracker_evt_update_new ();
-
-  g_variant_get (parameters, "(&sa(iiii)a(iiii))", &class_name, &iter1, &iter2);
-
-  GRL_DEBUG ("\tTracker update event for class=%s ins=%lu del=%lu evt=%p",
-             class_name,
-             (unsigned long) g_variant_iter_n_children (iter1),
-             (unsigned long) g_variant_iter_n_children (iter2),
-	     evt);
-
-  /* Avoid processing item from uninteresting classes */
-  if (g_str_has_suffix (class_name, RDF_TYPE_MUSIC) ||
-      g_str_has_suffix (class_name, RDF_TYPE_AUDIO) ||
-      g_str_has_suffix (class_name, RDF_TYPE_VIDEO) ||
-      g_str_has_suffix (class_name, RDF_TYPE_IMAGE)) {
-
-    /* Process deleted items */
-    while (g_variant_iter_loop (iter1, "(iiii)", &graph,
-                                &subject, &predicate, &object)) {
-      gpointer psubject = GSIZE_TO_POINTER (subject);
-      GrlTrackerSource *source =
-        grl_tracker_cache_get_source (grl_tracker_item_cache, subject);
-
-      /* GRL_DEBUG ("\tdelete=> subject=%i", subject); */
-
-      if (source) {
-        g_hash_table_insert (evt->deleted_items, psubject,
-                             g_object_ref (source));
-      } else {
-        g_hash_table_insert (evt->orphan_items, psubject,
-                             GSIZE_TO_POINTER (GRL_CONTENT_REMOVED));
-      }
-    }
-
-    /* Process inserted items */
-    while (g_variant_iter_loop (iter2, "(iiii)", &graph,
-                              &subject, &predicate, &object)) {
-      gpointer psubject = GSIZE_TO_POINTER (subject);
-      GrlTrackerSource *source =
-        grl_tracker_cache_get_source (grl_tracker_item_cache, subject);
-
-      /* GRL_DEBUG ("\tinsert=> subject=%i", subject); */
-
-      if (source) {
-        /* Removed & inserted items are probably just renamed items... */
-        if (g_hash_table_lookup (evt->deleted_items, psubject)) {
-          g_hash_table_remove (evt->deleted_items, psubject);
-          g_hash_table_insert (evt->updated_items, psubject,
-                               g_object_ref (source));
-        } else if (!g_hash_table_lookup (evt->updated_items, psubject)) {
-          g_hash_table_insert (evt->inserted_items, psubject,
-                               g_object_ref (source));
-        }
-      } else {
-        gpointer state;
-
-        if (g_hash_table_lookup_extended (evt->orphan_items, psubject,
-                                          NULL, &state) &&
-            (GPOINTER_TO_INT (state) == GRL_CONTENT_REMOVED)) {
-          g_hash_table_insert (evt->orphan_items, psubject,
-                               GSIZE_TO_POINTER (GRL_CONTENT_CHANGED));
-        } else {
-          g_hash_table_insert (evt->orphan_items, psubject,
-                               GSIZE_TO_POINTER (GRL_CONTENT_ADDED));
-        }
-      }
-    }
-  }
-
-  g_variant_iter_free (iter1);
-  g_variant_iter_free (iter2);
-
-  GRL_DEBUG ("\tinserted=%i deleted=%i updated=%i orphan=%i",
-             g_hash_table_size (evt->inserted_items),
-             g_hash_table_size (evt->deleted_items),
-             g_hash_table_size (evt->updated_items),
-	     g_hash_table_size (evt->orphan_items));
-
-  if (grl_tracker_per_device_source) {
-    tracker_evt_preupdate_sources (evt);
-  } else {
-    tracker_evt_update_items (evt);
-    tracker_evt_update_orphans (evt);
-  }
-}
-
-void
-grl_tracker_dbus_start_watch (void)
-{
-  GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
-
-  tracker_dbus_signal_id = g_dbus_connection_signal_subscribe (connection,
-                                                               TRACKER_DBUS_SERVICE,
-                                                               TRACKER_DBUS_INTERFACE_RESOURCES,
-                                                               "GraphUpdated",
-                                                               TRACKER_DBUS_OBJECT_RESOURCES,
-                                                               NULL,
-                                                               G_DBUS_SIGNAL_FLAGS_NONE,
-                                                               tracker_dbus_signal_cb,
-                                                               NULL,
-                                                               NULL);
-}
-
-void
-grl_tracker_init_notifs (void)
-{
-  GRL_LOG_DOMAIN_INIT (tracker_notif_log_domain, "tracker-notif");
-}
diff --git a/src/media/tracker/grl-tracker-notif.h b/src/media/tracker/grl-tracker-notif.h
deleted file mode 100644
index a288fc3..0000000
--- a/src/media/tracker/grl-tracker-notif.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_NOTIF_H_
-#define _GRL_TRACKER_NOTIF_H_
-
-#include "grl-tracker.h"
-
-/* ------- Definitions ------- */
-
-#define TRACKER_DATASOURCES_REQUEST                                     \
-  "SELECT "                                                             \
-  "(SELECT GROUP_CONCAT(rdf:type(?source), \":\") "                     \
-  " WHERE { ?urn nie:dataSource ?source }) "                            \
-  "nie:dataSource(?urn) "                                               \
-  "(SELECT GROUP_CONCAT(nie:title(?source), \":\") "                    \
-  " WHERE { ?urn nie:dataSource ?source }) "                            \
-  "(SELECT GROUP_CONCAT(nie:url(tracker:mountPoint(?source)), \":\") "  \
-  " WHERE { ?urn nie:dataSource ?source }) "                            \
-  "tracker:available(?urn) "                                            \
-  "WHERE "                                                              \
-  "{ "                                                                  \
-  "?urn a nfo:FileDataObject . FILTER (bound(nie:dataSource(?urn)))"    \
-  "} "                                                                  \
-  "GROUP BY (nie:dataSource(?urn))"
-
-/**/
-
-void grl_tracker_dbus_start_watch (void);
-
-void grl_tracker_init_notifs (void);
-
-#endif /* _GRL_TRACKER_NOTIF_H_ */
diff --git a/src/media/tracker/grl-tracker-priv.h b/src/media/tracker/grl-tracker-priv.h
deleted file mode 100644
index 8b9bbe0..0000000
--- a/src/media/tracker/grl-tracker-priv.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2011 Intel Corporation.
- *
- * Contact: Iago Toral Quiroga <itoral igalia com>
- *
- * Authors: Lionel Landwerlin <lionel g landwerlin linux intel 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_PRIV_H_
-#define _GRL_TRACKER_PRIV_H_
-
-#include "grl-tracker.h"
-#include "grl-tracker-cache.h"
-
-#include <tracker-sparql.h>
-
-/* ---- Plugin information --- */
-
-#define GRL_TRACKER_PLUGIN_ID   TRACKER_PLUGIN_ID
-
-#define GRL_TRACKER_SOURCE_ID   "grl-tracker"
-#define GRL_TRACKER_SOURCE_NAME "Tracker"
-#define GRL_TRACKER_SOURCE_DESC                 \
-  "A plugin for searching multimedia "          \
-  "content using Tracker"
-
-#define GRL_TRACKER_AUTHOR  "Igalia S.L."
-#define GRL_TRACKER_LICENSE "LGPL"
-#define GRL_TRACKER_SITE    "http://www.igalia.com";
-
-/**/
-
-#define GRL_TRACKER_SOURCE_GET_PRIVATE(object)		\
-  (G_TYPE_INSTANCE_GET_PRIVATE((object),                \
-                               GRL_TRACKER_SOURCE_TYPE,	\
-                               GrlTrackerSourcePriv))
-
-typedef enum {
-  GRL_TRACKER_SOURCE_STATE_INSERTING,
-  GRL_TRACKER_SOURCE_STATE_RUNNING,
-  GRL_TRACKER_SOURCE_STATE_DELETING,
-  GRL_TRACKER_SOURCE_STATE_DELETED,
-} GrlTrackerSourceState;
-
-struct _GrlTrackerSourcePriv {
-  TrackerSparqlConnection *tracker_connection;
-
-  GHashTable *operations;
-
-  gchar *tracker_datasource;
-  gboolean notify_changes;
-
-  GrlTrackerSourceState state;
-  guint notification_ref;
-};
-
-/**/
-
-extern TrackerSparqlConnection *grl_tracker_connection;
-extern const GrlPluginInfo *grl_tracker_plugin;
-
-/* shared data across  */
-extern GrlTrackerCache *grl_tracker_item_cache;
-extern GHashTable *grl_tracker_modified_sources;
-
-/* tracker plugin config */
-extern gboolean grl_tracker_per_device_source;
-extern gboolean grl_tracker_browse_filesystem;
-
-#endif /* _GRL_TRACKER_PRIV_H_ */
diff --git a/src/media/tracker/grl-tracker-utils.c b/src/media/tracker/grl-tracker-utils.c
index ef06b5b..bc77ed1 100644
--- a/src/media/tracker/grl-tracker-utils.c
+++ b/src/media/tracker/grl-tracker-utils.c
@@ -23,7 +23,6 @@
  */
 
 #include "grl-tracker-utils.h"
-#include "grl-tracker-priv.h"
 
 /**/
 
@@ -165,7 +164,7 @@ get_mapping_from_grl (const GrlKeyID key)
 /**/
 
 gchar *
-grl_tracker_source_get_device_constraint (GrlTrackerSourcePriv *priv)
+grl_tracker_media_get_device_constraint (GrlTrackerMediaPriv *priv)
 {
   if (priv->tracker_datasource == NULL)
     return g_strdup ("");
@@ -175,8 +174,8 @@ grl_tracker_source_get_device_constraint (GrlTrackerSourcePriv *priv)
 }
 
 gchar *
-grl_tracker_source_get_select_string (GrlMediaSource *source,
-                                      const GList *keys)
+grl_tracker_media_get_select_string (GrlMediaSource *source,
+                                     const GList *keys)
 {
   const GList *key = keys;
   GString *gstr = g_string_new ("");
@@ -295,10 +294,10 @@ get_tracker_upnp_name (const gchar *datasource_name)
 }
 
 gchar *
-grl_tracker_get_source_name (const gchar *rdf_type,
-                             const gchar *uri,
-                             const gchar *datasource,
-                             const gchar *datasource_name)
+grl_tracker_get_media_name (const gchar *rdf_type,
+                            const gchar *uri,
+                            const gchar *datasource,
+                            const gchar *datasource_name)
 {
   gchar *source_name = NULL;
   gchar **rdf_single_type;
@@ -323,7 +322,7 @@ grl_tracker_get_source_name (const gchar *rdf_type,
 
   if (!source_name)
     source_name = g_strdup_printf  ("%s %s",
-                                    GRL_TRACKER_SOURCE_NAME,
+                                    GRL_TRACKER_MEDIA_NAME,
                                     datasource);
 
   return source_name;
diff --git a/src/media/tracker/grl-tracker-utils.h b/src/media/tracker/grl-tracker-utils.h
index 09cc679..881828e 100644
--- a/src/media/tracker/grl-tracker-utils.h
+++ b/src/media/tracker/grl-tracker-utils.h
@@ -25,7 +25,7 @@
 #ifndef _GRL_TRACKER_UTILS_H_
 #define _GRL_TRACKER_UTILS_H_
 
-#include "grl-tracker.h"
+#include "grl-tracker-media-priv.h"
 
 /* ------- Definitions ------- */
 
@@ -57,14 +57,14 @@ tracker_grl_sparql_t *grl_tracker_get_mapping_from_sparql (const gchar *key);
 
 GrlMedia *grl_tracker_build_grilo_media (const gchar *rdf_type);
 
-gchar *grl_tracker_source_get_device_constraint (GrlTrackerSourcePriv *priv);
+gchar *grl_tracker_media_get_device_constraint (GrlTrackerMediaPriv *priv);
 
-gchar *grl_tracker_source_get_select_string (GrlMediaSource *source,
-                                             const GList *keys);
+gchar *grl_tracker_media_get_select_string (GrlMediaSource *source,
+                                            const GList *keys);
 
-gchar *grl_tracker_get_source_name (const gchar *rdf_type,
-                                    const gchar *uri,
-                                    const gchar *datasource,
-                                    const gchar *datasource_name);
+gchar *grl_tracker_get_media_name (const gchar *rdf_type,
+                                   const gchar *uri,
+                                   const gchar *datasource,
+                                   const gchar *datasource_name);
 
 #endif /* _GRL_TRACKER_UTILS_H_ */
diff --git a/src/media/tracker/grl-tracker.c b/src/media/tracker/grl-tracker.c
deleted file mode 100644
index f862e9b..0000000
--- a/src/media/tracker/grl-tracker.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2011 Igalia S.L.
- * Copyright (C) 2011 Intel Corporation.
- *
- * 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"
-#include "grl-tracker-priv.h"
-#include "grl-tracker-api.h"
-#include "grl-tracker-cache.h"
-#include "grl-tracker-notif.h"
-#include "grl-tracker-utils.h"
-
-/* --------- Logging  -------- */
-
-#define GRL_LOG_DOMAIN_DEFAULT tracker_general_log_domain
-GRL_LOG_DOMAIN_STATIC(tracker_general_log_domain);
-
-/* ------- Definitions ------- */
-
-#define MEDIA_TYPE "grilo-media-type"
-
-#define TRACKER_ITEM_CACHE_SIZE (10000)
-
-/* --- Other --- */
-
-enum {
-  PROP_0,
-  PROP_TRACKER_CONNECTION,
-};
-
-static GrlTrackerSource *grl_tracker_source_new (TrackerSparqlConnection *connection);
-
-static void grl_tracker_source_set_property (GObject      *object,
-                                             guint         propid,
-                                             const GValue *value,
-                                             GParamSpec   *pspec);
-
-static void grl_tracker_source_constructed (GObject *object);
-
-static void grl_tracker_source_finalize (GObject *object);
-
-gboolean grl_tracker_plugin_init (GrlPluginRegistry *registry,
-                                  const GrlPluginInfo *plugin,
-                                  GList *configs);
-
-/* ===================== Globals  ================= */
-
-TrackerSparqlConnection *grl_tracker_connection = NULL;
-const GrlPluginInfo *grl_tracker_plugin;
-
-/* shared data across  */
-GrlTrackerCache *grl_tracker_item_cache;
-GHashTable *grl_tracker_modified_sources;
-
-/* tracker plugin config */
-gboolean grl_tracker_per_device_source = FALSE;
-gboolean grl_tracker_browse_filesystem = FALSE;
-
-/* =================== Tracker Plugin  =============== */
-
-void
-grl_tracker_add_source (GrlTrackerSource *source)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  GRL_DEBUG ("====================>add source '%s' count=%u",
-             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
-             priv->notification_ref);
-
-  if (priv->notification_ref > 0) {
-    priv->notification_ref--;
-  }
-  if (priv->notification_ref == 0) {
-    g_hash_table_remove (grl_tracker_modified_sources,
-                         grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)));
-    priv->state = GRL_TRACKER_SOURCE_STATE_RUNNING;
-    grl_plugin_registry_register_source (grl_plugin_registry_get_default (),
-                                         grl_tracker_plugin,
-                                         GRL_MEDIA_PLUGIN (source),
-                                         NULL);
-  }
-}
-
-void
-grl_tracker_del_source (GrlTrackerSource *source)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  GRL_DEBUG ("==================>del source '%s' count=%u",
-             grl_metadata_source_get_name (GRL_METADATA_SOURCE (source)),
-             priv->notification_ref);
-  if (priv->notification_ref > 0) {
-    priv->notification_ref--;
-  }
-  if (priv->notification_ref == 0) {
-    g_hash_table_remove (grl_tracker_modified_sources,
-                         grl_metadata_source_get_id (GRL_METADATA_SOURCE (source)));
-    grl_tracker_cache_del_source (grl_tracker_item_cache, source);
-    priv->state = GRL_TRACKER_SOURCE_STATE_DELETED;
-    grl_plugin_registry_unregister_source (grl_plugin_registry_get_default (),
-                                           GRL_MEDIA_PLUGIN (source),
-                                           NULL);
-  }
-}
-
-gboolean
-grl_tracker_source_can_notify (GrlTrackerSource *source)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  if (priv->state == GRL_TRACKER_SOURCE_STATE_RUNNING)
-    return priv->notify_changes;
-
-  return FALSE;
-}
-
-GrlTrackerSource *
-grl_tracker_source_find (const gchar *id)
-{
-  GrlMediaPlugin *source;
-
-  source = grl_plugin_registry_lookup_source (grl_plugin_registry_get_default (),
-					      id);
-
-  if (source && GRL_IS_TRACKER_SOURCE (source)) {
-    return (GrlTrackerSource *) source;
-  }
-
-  return
-    (GrlTrackerSource *) g_hash_table_lookup (grl_tracker_modified_sources,
-                                              id);
-}
-
-static void
-tracker_get_datasource_cb (GObject             *object,
-                           GAsyncResult        *result,
-                           TrackerSparqlCursor *cursor)
-{
-  const gchar *type, *datasource, *datasource_name, *uri;
-  gboolean source_available;
-  GError *error = NULL;
-  GrlTrackerSource *source;
-
-  GRL_DEBUG ("%s", __FUNCTION__);
-
-  if (!tracker_sparql_cursor_next_finish (cursor, result, &error)) {
-    if (error == NULL) {
-      GRL_DEBUG ("\tEnd of parsing of devices");
-    } else {
-      GRL_WARNING ("\tError while parsing devices: %s", error->message);
-      g_error_free (error);
-    }
-    g_object_unref (G_OBJECT (cursor));
-    return;
-  }
-
-  type = tracker_sparql_cursor_get_string (cursor, 0, NULL);
-  datasource = tracker_sparql_cursor_get_string (cursor, 1, NULL);
-  datasource_name = tracker_sparql_cursor_get_string (cursor, 2, NULL);
-  uri = tracker_sparql_cursor_get_string (cursor, 3, NULL);
-  source_available = tracker_sparql_cursor_get_boolean (cursor, 4);
-
-  source = grl_tracker_source_find (datasource);
-
-  if ((source == NULL) && source_available) {
-    gchar *source_name = grl_tracker_get_source_name (type, uri, datasource,
-                                                      datasource_name);
-    GRL_DEBUG ("\tnew datasource: urn=%s name=%s uri=%s\n",
-	       datasource, datasource_name, uri);
-    source = g_object_new (GRL_TRACKER_SOURCE_TYPE,
-                           "source-id", datasource,
-                           "source-name", source_name,
-                           "source-desc", GRL_TRACKER_SOURCE_DESC,
-                           "tracker-connection", grl_tracker_connection,
-                           NULL);
-    grl_tracker_add_source (source);
-    g_free (source_name);
-  }
-
-  tracker_sparql_cursor_next_async (cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_get_datasource_cb,
-                                    cursor);
-}
-
-static void
-tracker_get_datasources_cb (GObject      *object,
-                            GAsyncResult *result,
-                            gpointer      data)
-{
-  GError *error = NULL;
-  TrackerSparqlCursor *cursor;
-
-  GRL_DEBUG ("%s", __FUNCTION__);
-
-  cursor = tracker_sparql_connection_query_finish (grl_tracker_connection,
-                                                   result, &error);
-
-  if (error) {
-    GRL_WARNING ("Cannot handle datasource request : %s", error->message);
-    g_error_free (error);
-    return;
-  }
-
-  tracker_sparql_cursor_next_async (cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_get_datasource_cb,
-                                    cursor);
-}
-
-static void
-tracker_get_connection_cb (GObject             *object,
-                           GAsyncResult        *res,
-                           const GrlPluginInfo *plugin)
-{
-  /* GrlTrackerSource *source; */
-
-  GRL_DEBUG ("%s", __FUNCTION__);
-
-  grl_tracker_connection = tracker_sparql_connection_get_finish (res, NULL);
-
-  if (grl_tracker_connection != NULL) {
-    grl_tracker_dbus_start_watch ();
-
-    if (grl_tracker_per_device_source == TRUE) {
-      /* Let's discover available data sources. */
-      GRL_DEBUG ("\tper device source mode request: '"
-                 TRACKER_DATASOURCES_REQUEST "'");
-
-      tracker_sparql_connection_query_async (grl_tracker_connection,
-                                             TRACKER_DATASOURCES_REQUEST,
-                                             NULL,
-                                             (GAsyncReadyCallback) tracker_get_datasources_cb,
-                                             NULL);
-    } else {
-      /* One source to rule them all. */
-      grl_tracker_add_source (grl_tracker_source_new (grl_tracker_connection));
-    }
-  }
-}
-
-gboolean
-grl_tracker_plugin_init (GrlPluginRegistry *registry,
-                         const GrlPluginInfo *plugin,
-                         GList *configs)
-{
-  GrlConfig *config;
-  gint config_count;
-
-  GRL_DEBUG ("%s", __FUNCTION__);
-
-  GRL_LOG_DOMAIN_INIT (tracker_general_log_domain, "tracker-general");
-  grl_tracker_init_notifs ();
-  grl_tracker_init_requests ();
-
-  grl_tracker_plugin = plugin;
-  grl_tracker_item_cache = grl_tracker_cache_new (TRACKER_ITEM_CACHE_SIZE);
-  grl_tracker_modified_sources = g_hash_table_new (g_str_hash, g_str_equal);
-
-  if (!configs) {
-    GRL_WARNING ("\tConfiguration not provided! Using default configuration.");
-  } else {
-    config_count = g_list_length (configs);
-    if (config_count > 1) {
-      GRL_WARNING ("\tProvided %i configs, but will only use one", config_count);
-    }
-
-    config = GRL_CONFIG (configs->data);
-
-    grl_tracker_per_device_source =
-      grl_config_get_boolean (config, "per-device-source");
-    grl_tracker_browse_filesystem =
-      grl_config_get_boolean (config, "browse-filesystem");
-  }
-
-  tracker_sparql_connection_get_async (NULL,
-                                       (GAsyncReadyCallback) tracker_get_connection_cb,
-                                       (gpointer) plugin);
-  return TRUE;
-}
-
-GRL_PLUGIN_REGISTER (grl_tracker_plugin_init,
-                     NULL,
-                     GRL_TRACKER_PLUGIN_ID);
-
-/* ================== Tracker GObject ================ */
-
-static GrlTrackerSource *
-grl_tracker_source_new (TrackerSparqlConnection *connection)
-{
-  GRL_DEBUG ("%s", __FUNCTION__);
-
-  return g_object_new (GRL_TRACKER_SOURCE_TYPE,
-                       "source-id", GRL_TRACKER_SOURCE_ID,
-                       "source-name", GRL_TRACKER_SOURCE_NAME,
-                       "source-desc", GRL_TRACKER_SOURCE_DESC,
-                       "tracker-connection", connection,
-                       NULL);
-}
-
-G_DEFINE_TYPE (GrlTrackerSource, grl_tracker_source, GRL_TYPE_MEDIA_SOURCE);
-
-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;
-  source_class->metadata            = grl_tracker_source_metadata;
-  source_class->search              = grl_tracker_source_search;
-  source_class->browse              = grl_tracker_source_browse;
-  source_class->cancel              = grl_tracker_source_cancel;
-  source_class->notify_change_start = grl_tracker_source_change_start;
-  source_class->notify_change_stop  = grl_tracker_source_change_stop;
-
-  metadata_class->supported_keys = grl_tracker_source_supported_keys;
-
-  g_class->finalize     = grl_tracker_source_finalize;
-  g_class->set_property = grl_tracker_source_set_property;
-  g_class->constructed  = grl_tracker_source_constructed;
-
-  g_object_class_install_property (g_class,
-                                   PROP_TRACKER_CONNECTION,
-                                   g_param_spec_object ("tracker-connection",
-                                                        "tracker connection",
-                                                        "A Tracker connection",
-                                                        TRACKER_SPARQL_TYPE_CONNECTION,
-                                                        G_PARAM_WRITABLE
-                                                        | G_PARAM_CONSTRUCT_ONLY
-                                                        | G_PARAM_STATIC_NAME));
-
-  g_type_class_add_private (klass, sizeof (GrlTrackerSourcePriv));
-
-  grl_tracker_setup_key_mappings ();
-}
-
-static void
-grl_tracker_source_init (GrlTrackerSource *source)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (source);
-
-  source->priv = priv;
-
-  priv->operations = g_hash_table_new (g_direct_hash, g_direct_equal);
-}
-
-static void
-grl_tracker_source_constructed (GObject *object)
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (object);
-
-  if (grl_tracker_per_device_source)
-    g_object_get (object, "source-id", &priv->tracker_datasource, NULL);
-}
-
-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_set_property (GObject      *object,
-                                 guint         propid,
-                                 const GValue *value,
-                                 GParamSpec   *pspec)
-
-{
-  GrlTrackerSourcePriv *priv = GRL_TRACKER_SOURCE_GET_PRIVATE (object);
-
-  switch (propid) {
-  case PROP_TRACKER_CONNECTION:
-    if (priv->tracker_connection != NULL)
-      g_object_unref (G_OBJECT (priv->tracker_connection));
-    priv->tracker_connection = g_object_ref (g_value_get_object (value));
-    break;
-
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
-  }
-}
-
diff --git a/src/media/tracker/grl-tracker.h b/src/media/tracker/grl-tracker.h
deleted file mode 100644
index 2d9cd47..0000000
--- a/src/media/tracker/grl-tracker.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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_H_
-#define _GRL_TRACKER_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);
-
-gboolean grl_tracker_source_can_notify (GrlTrackerSource *source);
-
-/**/
-void grl_tracker_add_source (GrlTrackerSource *source);
-
-void grl_tracker_del_source (GrlTrackerSource *source);
-
-GrlTrackerSource *grl_tracker_source_find (const gchar *id);
-
-
-#endif /* _GRL_TRACKER_H_ */
-- 
1.7.4.1



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