I continued working on this today, so here's a better version.

Changes since last patch:

  o. Requests to copy-to-local are now also handled by the indexer,
     instead of by the extractor
  o. Heuristic scanner finds local media art first, and copies from it
     if found as first heuristic match
  o. Proper check in configure.ac for strcasestr 
  o. There were linking problems in the test-tools for tracker-extract,
     I fixed them in this patch (by providing dummy functions)
  o. Restored all necessary locations for requesting thumbnails of the
     newly created album art
  o. Eliminated the need for TrackerHal in tracker-extract (which will
     make Ivan as happy as a little boy who has just found Easter eggs),
     removed the construction of it from the main function and from the
     tests for tracker-extract.
  o. Cleaned up use of TrackerHal in the code that now runs in the
     indexer, it all uses hal from private->hal now instead. Made it
     cope with not HAVE_HAL too.

I'll notify you tomorrow about it if I change more things today, Martyn.
But feel free to start reviewing this one already.


On Fri, 2009-04-10 at 17:40 +0200, Philip Van Hoof wrote:
> Hackers!
> 
> Currently Tracker's media file extractor will on top of trying to
> extract embedded media art from files, perform a heuristic on the
> directory of the media file.
> 
> The reason why it does this heuristic is to find album art related to
> the media file.
> 
> Usually are media files grouped together in a directory, though. For
> example like this:
> 
> /location/Freaky Freak/The greatest 
> hits/Freaky-Freak_-_The-greatest-hits_-_I-can-sing.mp3
> /location/Freaky Freak/The greatest 
> hits/Freaky-Freak_-_The-greatest-hits_-_You-can-sing.mp3
> /location/Freaky Freak/The greatest 
> hits/Freaky-Freak_-_The-greatest-hits_-_We-can-sing.mp3
> /location/Freaky Freak/The greatest 
> hits/Freaky-Freak_-_The-greatest-hits_-_They-can-sing.mp3
> 
> Or whatever filenaming format the w3ird peoples on thiz planetz have
> used for their albums, songs, media files and etcetera.
> 
> Right now will the extractor foreach file in such a directory repeat the
> complete heuristic.
> 
> With this patch we'll throw the request for a heuristic back to the
> indexer. The indexer has a queue where it also merges the requests
> together. In the patch the indexer does this by forming a key using the
> dirname, album and artist.
> 
> Which means that if a request for a heuristic is made for ten files sang
> by the same artist, grouped into the same album, stored in the same
> directory, which is kinda common by the way, I'm again making my
> sentences too long, making it hard for people to read them, then the
> indexer will simply merge those ten together and perform just one
> heuristic instead. Saving precious computar cycles.
> 
> It's quite a refactor, and this close to a next 0.6.x release it would I
> think be good if a few extra couple of eyes would review and test the
> code before I push it.
> 
> Please review

-- 
Philip Van Hoof, freelance software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://pvanhoof.be/blog
http://codeminded.be
diff --git a/configure.ac b/configure.ac
index 3620111..8403846 100644
--- a/configure.ac
+++ b/configure.ac
@@ -108,6 +108,7 @@ AC_CHECK_DECLS(posix_fadvise, [], [], [
 # Checks for functions
 AC_CHECK_FUNCS([posix_fadvise])
 AC_CHECK_FUNCS([getline])
+AC_CHECK_FUNCS([strcasestr])
 
 # Check for defines we expect
 AC_TRY_COMPILE(,
diff --git a/data/dbus/tracker-extract.xml b/data/dbus/tracker-extract.xml
index 4d9de37..91b3e7b 100644
--- a/data/dbus/tracker-extract.xml
+++ b/data/dbus/tracker-extract.xml
@@ -21,5 +21,15 @@
       <arg type="s" name="mime" direction="in" />
       <arg type="a{ss}" name="values" direction="out" />
     </method>
+    <signal name="ToScanForAlbumart">
+      <arg type="s" name="dirname" />
+      <arg type="s" name="artist" />
+      <arg type="s" name="album" />
+      <arg type="s" name="count" />
+    </signal>
+    <signal name="ToCopyToLocalIf">
+      <arg type="s" name="filename" />
+      <arg type="s" name="dirname" />
+    </signal>
   </interface>
 </node>
diff --git a/src/libtracker-common/tracker-albumart.c b/src/libtracker-common/tracker-albumart.c
index fb0fe7e..5ed9da5 100644
--- a/src/libtracker-common/tracker-albumart.c
+++ b/src/libtracker-common/tracker-albumart.c
@@ -41,6 +41,8 @@
 #include <dbus/dbus-glib-bindings.h>
 
 #include <libtracker-common/tracker-common.h>
+#include <libtracker-common/tracker-hal.h>
+#include <libtracker-common/tracker-thumbnailer.h>
 
 
 #include "tracker-albumart.h"
@@ -54,62 +56,33 @@
 #define THUMBNAILER_PATH         "/org/freedesktop/thumbnailer/Generic"
 #define THUMBNAILER_INTERFACE    "org.freedesktop.thumbnailer.Generic"
 
+#define ALBUMART_HEURISTIC_SCAN_TIMEOUT	30
+
 typedef struct {
+	gboolean no_more_requesting;
+	GHashTable *queue;
+	guint queue_timeout;
 	TrackerHal *hal;
-	gchar      *art_path;
-	gchar      *local_uri;
-} GetFileInfo;
-
-static gboolean no_more_requesting = FALSE;
+} TrackerAlbumArtPrivate;
 
-static gchar *
-my_compute_checksum_for_data (GChecksumType  checksum_type,
-                              const guchar  *data,
-                              gsize          length)
-{
-	GChecksum *checksum;
-	gchar *retval;
-	
-	checksum = g_checksum_new (checksum_type);
-	if (!checksum)
-		return NULL;
-	
-	g_checksum_update (checksum, data, length);
-	retval = g_strdup (g_checksum_get_string (checksum));
-	g_checksum_free (checksum);
-	
-	return retval;
-}
-
-#ifndef HAVE_STRCASESTR
-
-static gchar *
-strcasestr (const gchar *haystack, 
-	    const gchar *needle)
-{
-	gchar *p;
-	gchar *startn = NULL;
-	gchar *np = NULL;
+typedef struct {
+	gchar *dirname;
+	gchar *album;
+	gchar *artist;
+	gchar *count;
+} QueuedAlbumArtScanRequest;
 
-	for (p = (gchar *) haystack; *p; p++) {
-		if (np) {
-			if (toupper (*p) == toupper (*np)) {
-				if (!*++np) {
-					return startn;
-				}
-			} else {
-				np = 0;
-			}
-		} else if (toupper (*p) == toupper (*needle)) {
-			np = (gchar *) needle + 1;
-			startn = p;
-		}
-	}
+typedef struct {
+	gchar *album;
+	gchar *artist;
+	gchar *dirname;
+} GetFileInfo;
 
-	return NULL;
-}
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
 
-#endif /* HAVE_STRCASESTR */
+#ifdef HAVE_STRCASESTR
+gchar * strcasestr (const gchar *haystack, const gchar *needle);
+#endif
 
 /* NOTE: This function was stolen from GLib 2.18.x. Since upstream and
  * the Maemo branch don't have this in circulation yet, we have copied
@@ -175,6 +148,180 @@ make_directory_with_parents (GFile         *file,
   return g_file_make_directory (file, cancellable, error);
 }
 
+void 
+tracker_albumart_copy_to_local_if (const gchar *album_art_file,
+				   const gchar *dirname)
+{
+	GList *removable_roots, *l;
+	gboolean on_removable_device = FALSE;
+	TrackerAlbumArtPrivate *private;
+	guint flen = dirname ? strlen (dirname) : 0;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	/* Determining if we are on a removable device */
+#ifdef HAVE_HAL
+	removable_roots = tracker_hal_get_removable_device_roots (private->hal);
+#else
+	removable_roots = g_list_append (removable_roots, "/media");
+	removable_roots = g_list_append (removable_roots, "/mnt");
+#endif
+
+	for (l = removable_roots; l; l = l->next) {
+		guint len;
+
+		len = strlen (l->data);
+
+		if (flen >= len && strncmp (dirname, l->data, len) == 0) {
+			on_removable_device = TRUE;
+			break;
+		}
+	}
+
+#ifdef HAVE_HAL
+	g_list_foreach (removable_roots, (GFunc) g_free, NULL);
+#endif
+
+	g_list_free (removable_roots);
+
+	/* Going to copy to .mediaartlocal if file is on a removable device */
+
+	if (on_removable_device) {
+		GError *error = NULL;
+		gchar *local_dir, *basename, *local_uri;
+		GFile *file, *parent;
+
+		/* album_art_file points to the newly made album-art */
+		file = g_file_new_for_path (album_art_file); 
+		basename = g_file_get_basename (file);
+
+		/* dirname points to the dir where the album is located */
+		parent = g_file_new_for_path (dirname);
+		local_dir = g_file_get_uri (parent);
+		g_object_unref (parent);
+
+		local_uri = g_strdup_printf ("%s/.mediaartlocal", local_dir);
+		parent = g_file_new_for_uri (local_uri);
+
+		g_free (local_uri);
+
+		/* Ensure directory is made */
+		make_directory_with_parents (parent, NULL, &error);
+
+		if (!error) {
+			GFile *local_file;
+
+			/* This is a URI, don't use g_build_filename here */
+			local_uri = g_strdup_printf ("%s/.mediaartlocal/%s", 
+						     local_dir, basename);
+			local_file = g_file_new_for_uri (local_uri);
+			g_free (local_uri);
+
+			g_file_copy_async (file, local_file, 0, 0, 
+					   NULL, NULL, NULL, NULL, NULL);
+
+			g_object_unref (local_file);
+		} else {
+			/* Removable media probably not writable, ignore */
+			g_error_free (error);
+		}
+
+		g_free (local_dir);
+		g_free (basename);
+		g_object_unref (file);
+	}
+}
+
+
+static gboolean 
+tracker_albumart_copy_from_local_if (const gchar *album_art_file,
+				     const gchar *dirname)
+{
+	gboolean retval = FALSE;
+	gchar *basename, *local_dir, *local_uri;
+	GFile *file, *parent, *local_file;
+
+	file = g_file_new_for_path (album_art_file); 
+	basename = g_file_get_basename (file);
+
+	parent = g_file_new_for_path (dirname);
+	local_dir = g_file_get_uri (parent);
+	g_object_unref (parent);
+
+	/* This is a URI, don't use g_build_filename here */
+	local_uri = g_strdup_printf ("%s/.mediaartlocal/%s", local_dir, basename);
+	local_file = g_file_new_for_uri (local_uri);
+	g_free (local_uri);
+
+	if (g_file_query_exists (local_file, NULL)) {
+		g_file_copy_async (local_file, file, 0, 0, 
+				   NULL, NULL, NULL, NULL, NULL);
+
+		tracker_thumbnailer_queue_file (album_art_file, "image/jpeg");
+
+		retval = TRUE;
+	}
+
+	g_object_unref (local_file);
+
+	g_free (local_dir);
+	g_free (basename);
+	g_object_unref (file);
+
+	return retval;
+}
+
+static gchar *
+my_compute_checksum_for_data (GChecksumType  checksum_type,
+                              const guchar  *data,
+                              gsize          length)
+{
+	GChecksum *checksum;
+	gchar *retval;
+	
+	checksum = g_checksum_new (checksum_type);
+	if (!checksum)
+		return NULL;
+	
+	g_checksum_update (checksum, data, length);
+	retval = g_strdup (g_checksum_get_string (checksum));
+	g_checksum_free (checksum);
+	
+	return retval;
+}
+
+#ifndef HAVE_STRCASESTR
+
+static gchar *
+strcasestr (const gchar *haystack, 
+	    const gchar *needle)
+{
+	gchar *p;
+	gchar *startn = NULL;
+	gchar *np = NULL;
+
+	for (p = (gchar *) haystack; *p; p++) {
+		if (np) {
+			if (toupper (*p) == toupper (*np)) {
+				if (!*++np) {
+					return startn;
+				}
+			} else {
+				np = 0;
+			}
+		} else if (toupper (*p) == toupper (*needle)) {
+			np = (gchar *) needle + 1;
+			startn = p;
+		}
+	}
+
+	return NULL;
+}
+
+#endif /* HAVE_STRCASESTR */
+
+
 static gchar*
 strip_characters (const gchar *original)
 {
@@ -242,162 +389,73 @@ strip_characters (const gchar *original)
 	return retval;
 }
 
-void
-tracker_albumart_copy_to_local (TrackerHal  *hal,
-				const gchar *filename, 
-				const gchar *local_uri)
-{
-	GList *removable_roots, *l;
-	gboolean on_removable_device = FALSE;
-	guint flen;
-
-	g_return_if_fail (filename != NULL);
-	g_return_if_fail (local_uri != NULL);
-
-	flen = strlen (filename);
-
-	/* Determining if we are on a removable device */
-#ifdef HAVE_HAL
-	g_return_if_fail (hal != NULL);
 
-	removable_roots = tracker_hal_get_removable_device_roots (hal);
-#else
-	removable_roots = g_list_append (removable_roots, "/media");
-	removable_roots = g_list_append (removable_roots, "/mnt");
-#endif
-
-	for (l = removable_roots; l; l = l->next) {
-		guint len;
-		
-		len = strlen (l->data);
-
-		if (flen >= len && strncmp (filename, l->data, len)) {
-			on_removable_device = TRUE;
-			break;
-		}
-	}
-
-#ifdef HAVE_HAL
-	g_list_foreach (removable_roots, (GFunc) g_free, NULL);
-#endif
-
-	g_list_free (removable_roots);
-
-	if (on_removable_device) {
-		GFile *local_file, *from;
-
-		from = g_file_new_for_path (filename);
-		local_file = g_file_new_for_uri (local_uri);
-
-		/* We don't try to overwrite, but we also ignore all errors.
-		 * Such an error could be that the removable device is 
-		 * read-only. Well that's fine then ... ignore */
-
-		if (!g_file_query_exists (local_file, NULL)) {
-			GFile *dirf;
-
-			dirf = g_file_get_parent (local_file);
-			make_directory_with_parents (dirf, NULL, NULL);
-			g_object_unref (dirf);
-
-			g_file_copy_async (from, local_file, 0, 0, 
-					   NULL, NULL, NULL, NULL, NULL);
-		}
-
-		g_object_unref (local_file);
-		g_object_unref (from);
-	}
-}
-
-gboolean 
+static gboolean 
 tracker_albumart_heuristic (const gchar *artist_,  
 			    const gchar *album_, 
 			    const gchar *tracks_str, 
-			    const gchar *filename,
-			    const gchar *local_uri,
-			    gboolean    *copied)
+			    const gchar *dirname)
 {
-	GFile *file;
 	GDir *dir;
 	struct stat st;
 	gchar *target = NULL;
-	gchar *basename;
 	const gchar *name;
 	gboolean retval;
 	gint tracks;
 	gint count;
 	gchar *artist = NULL;
 	gchar *album = NULL;
+	GFile *file;
 
-	/* Copy from local album art (.mediaartlocal) to spec */
-	if (local_uri) {
-		GFile *local_file;
-		
-		local_file = g_file_new_for_uri (local_uri);
-		
-		if (g_file_query_exists (local_file, NULL)) {
-			tracker_albumart_get_path (artist, album, 
-						   "album", NULL, 
-						   &target, NULL);
-			
-			file = g_file_new_for_path (target);
-			
-			g_file_copy_async (local_file, file, 0, 0, 
-					   NULL, NULL, NULL, NULL, NULL);
-			
-			g_object_unref (file);
-			g_object_unref (local_file);
-			
-			*copied = TRUE;
-			g_free (target);
-			
-			return TRUE;
-		}
-		
-		g_object_unref (local_file);
-	}
+	dir = g_dir_open (dirname, 0, NULL);
 
-	*copied = FALSE;
+	if (!dir) {
+		return FALSE;
+	}
 
-	file = g_file_new_for_path (filename);
-	basename = g_file_get_basename (file);
-	g_object_unref (file);
+	if (artist_) {
+		artist = strip_characters (artist_);
+	}
 
-	if (!basename) {
-		return FALSE;
+	if (album_) {
+		album = strip_characters (album_);
 	}
 
-	dir = g_dir_open (basename, 0, NULL);
+	tracker_albumart_get_path (artist, album, "album", &target);
 
-	if (!dir) {
-		g_free (basename);
+	if (!target) {
+		g_dir_close (dir);
+		g_free (artist);
+		g_free (album);
 		return FALSE;
 	}
 
+	if (tracker_albumart_copy_from_local_if (target, dirname)) {
+		g_dir_close (dir);
+		g_free (target);
+		g_free (artist);
+		g_free (album);
+		return TRUE;
+	}
+
 	retval = FALSE;
 	file = NULL;
 
-	g_stat (basename, &st);
-	count = st.st_nlink;
-	
+	g_stat (dirname, &st);
+	count = st.st_nlink + st.st_ino;
+
 	if (tracks_str) {
 		tracks = atoi (tracks_str);
+		if (tracks == 0)
+			tracks = -1;
 	} else {
 		tracks = -1;
 	}
 
-	if (artist_) {
-		artist = strip_characters (artist_);
-	}
-
-	if (album_) {
-		album = strip_characters (album_);
-	}
-
 	/* If amount of files and amount of tracks in the album somewhat match */
 
 	if ((tracks != -1 && tracks < count + 3 && tracks > count - 3) || 
-	    (tracks == -1 && count > 8 && count < 50)) {
+	    (tracks == -1 && count >= 8 && count < 50)) {
 		gchar *found = NULL;
 
 		/* Try to find cover art in the directory */
@@ -410,22 +468,16 @@ tracker_albumart_heuristic (const gchar *artist_,
 				if (g_str_has_suffix (name, "jpeg") || 
 				    g_str_has_suffix (name, "jpg")) {
 					GFile *file_found;
-					
-					if (!target) {
-						tracker_albumart_get_path (artist, album, 
-									   "album", NULL, 
-									   &target, NULL);
-					}
-					
+
 					if (!file) {
 						file = g_file_new_for_path (target);
 					}
 					
-					found = g_build_filename (basename, name, NULL);
+					found = g_build_filename (dirname, name, NULL);
 					file_found = g_file_new_for_path (found);
-					
+
 					g_file_copy (file_found, file, 0, NULL, NULL, NULL, &error);
-					
+
 					if (!error) {
 						retval = TRUE;
 					} else {
@@ -439,7 +491,7 @@ tracker_albumart_heuristic (const gchar *artist_,
 #ifdef HAVE_GDKPIXBUF
 					GdkPixbuf *pixbuf;
 					
-					found = g_build_filename (basename, name, NULL);
+					found = g_build_filename (dirname, name, NULL);
 					pixbuf = gdk_pixbuf_new_from_file (found, &error);
 					
 					if (error) {
@@ -447,16 +499,12 @@ tracker_albumart_heuristic (const gchar *artist_,
 						retval = FALSE;
 					} else {
 						if (!target) {
-							tracker_albumart_get_path (artist, 
-										   album, 
-										   "album", 
-										   NULL, 
-										   &target, 
-										   NULL);
+							tracker_albumart_get_path (artist, album, 
+										   "album", &target);
 						}
 						
 						gdk_pixbuf_save (pixbuf, target, "jpeg", &error, NULL);
-						
+
 						if (!error) {
 							retval = TRUE;
 						} else {
@@ -472,21 +520,22 @@ tracker_albumart_heuristic (const gchar *artist_,
 				}
 
 				if (retval) {
+					tracker_thumbnailer_queue_file (target, "image/jpeg");
+					tracker_albumart_copy_to_local_if (target, dirname);
 					break;
 				}
 			}
 		}
 		
 	}
-	
+
 	g_dir_close (dir);
-	
+
 	if (file) {
 		g_object_unref (file);
 	}
 
 	g_free (target);
-	g_free (basename);
 	g_free (artist);
 	g_free (album);
 
@@ -525,6 +574,11 @@ tracker_albumart_queue_cb (DBusGProxy     *proxy,
 	GError      *error = NULL;
 	guint        handle;
 	GetFileInfo *info;
+	gchar       *art_path;
+	TrackerAlbumArtPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
 
 	info = user_data;
 
@@ -534,43 +588,43 @@ tracker_albumart_queue_cb (DBusGProxy     *proxy,
 
 	if (error) {
 		if (error->code == DBUS_GERROR_SERVICE_UNKNOWN)
-			no_more_requesting = TRUE;
+			private->no_more_requesting = TRUE;
 		else
 			g_warning ("%s", error->message);
 		g_clear_error (&error);
+
+		return;
 	}
 
-	if (info->art_path &&
-	    g_file_test (info->art_path, G_FILE_TEST_EXISTS)) {
+	tracker_albumart_get_path (info->artist, info->album, 
+				   "album", &art_path);
+
+	if (art_path && g_file_test (art_path, G_FILE_TEST_EXISTS)) {
 		gchar *uri;
-		
-		uri = g_filename_to_uri (info->art_path, NULL, NULL);
+
+		uri = g_filename_to_uri (art_path, NULL, NULL);
 		tracker_thumbnailer_queue_file (uri, "image/jpeg");
 		g_free (uri);
 
-		tracker_albumart_copy_to_local (info->hal,
-						info->art_path, 
-						info->local_uri);
+		tracker_albumart_copy_to_local_if (art_path, info->dirname);
 	}
 
-	g_free (info->art_path);
-	g_free (info->local_uri);
+	g_free (art_path);
 
-	if (info->hal) {
-		g_object_unref (info->hal);
-	}
+	g_free (info->artist);
+	g_free (info->album);
+	g_free (info->dirname);
 
 	g_slice_free (GetFileInfo, info);
 }
 
 void
-tracker_albumart_get_path (const gchar  *a, 
-			   const gchar  *b, 
+tracker_albumart_get_path (const gchar  *album, 
+			   const gchar  *artist, 
 			   const gchar  *prefix, 
-			   const gchar  *uri,
-			   gchar       **path,
-			   gchar       **local_uri)
+			   gchar       **path)
 {
+	const gchar *a = album, *b = artist;
 	gchar *art_filename;
 	gchar *dir;
 	gchar *down1, *down2;
@@ -583,10 +637,6 @@ tracker_albumart_get_path (const gchar  *a,
 		*path = NULL;
 	}
 
-	if (local_uri) {
-		*local_uri = NULL;
-	}
-
 	if (!a && !b) {
 		return;
 	}
@@ -628,58 +678,32 @@ tracker_albumart_get_path (const gchar  *a,
 
 	*path = g_build_filename (dir, art_filename, NULL);
 
-	if (local_uri) {
-		gchar *local_dir;
-		GFile *file, *parent;
-
-		if (strchr (uri, ':')) {
-			file = g_file_new_for_uri (uri);
-		} else {
-			file = g_file_new_for_path (uri); 
-		}
-
-		parent = g_file_get_parent (file);
-		local_dir = g_file_get_uri (parent);
-
-		/* This is a URI, don't use g_build_filename here */
-		*local_uri = g_strdup_printf ("%s/.mediaartlocal/%s", local_dir, art_filename);
-
-		g_free (local_dir);
-		g_object_unref (file);
-		g_object_unref (parent);
-	}
-
 	g_free (dir);
 	g_free (art_filename);
 	g_free (str1);
 	g_free (str2);
 }
 
-void
-tracker_albumart_request_download (TrackerHal  *hal,
-				   const gchar *album, 
-				   const gchar *artist, 
-				   const gchar *local_uri, 
-				   const gchar *art_path)
+static void
+tracker_albumart_request_download (const gchar *album, 
+				   const gchar *artist,
+				   const gchar *dirname)
 {
 	GetFileInfo *info;
+	TrackerAlbumArtPrivate *private;
 
-	g_return_if_fail (hal != NULL);
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
 
-	if (no_more_requesting) {
+	if (private->no_more_requesting) {
 		return;
 	}
 
 	info = g_slice_new (GetFileInfo);
 
-#ifdef HAVE_HAL
-	info->hal = g_object_ref (hal);
-#else 
-	info->hal = NULL;
-#endif
-
-	info->local_uri = g_strdup (local_uri);
-	info->art_path = g_strdup (art_path);
+	info->album = g_strdup (album);
+	info->artist = g_strdup (artist);
+	info->dirname = g_strdup (dirname);
 
 	dbus_g_proxy_begin_call (get_albumart_requester (),
 				 "Queue",
@@ -691,3 +715,154 @@ tracker_albumart_request_download (TrackerHal  *hal,
 				 G_TYPE_UINT, 0,
 				 G_TYPE_INVALID);
 }
+
+
+static void
+queued_album_art_scan_request_free (QueuedAlbumArtScanRequest *info)
+{
+	g_free (info->dirname);
+	g_free (info->album);
+	g_free (info->artist);
+	g_free (info->count);
+	g_slice_free (QueuedAlbumArtScanRequest, info);
+}
+
+static gboolean
+on_queue_timeout (gpointer user_data)
+{
+	if (!g_source_is_destroyed (g_main_current_source ())) {
+		TrackerAlbumArtPrivate *private;
+		GHashTableIter iter;
+		gpointer key, value;
+
+		private = g_static_private_get (&private_key);
+		g_return_val_if_fail (private != NULL, FALSE);
+
+		g_hash_table_iter_init (&iter, private->queue);
+
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			QueuedAlbumArtScanRequest *info = value;
+
+			if (!tracker_albumart_heuristic (info->artist,
+							 info->album,
+							 info->count,
+							 info->dirname)) {
+
+				/* If the heuristic failed, we request the download 
+				 * of the media-art to the media-art downloaders */
+
+				tracker_albumart_request_download (info->artist, 
+								   info->album,
+								   info->dirname);
+			}
+
+			/* Once handled, we remove from the queue */
+			g_hash_table_iter_remove (&iter);
+		}
+
+	}
+
+	return FALSE;
+}
+
+void 
+tracker_albumart_heuristic_queue (const gchar *dirname, 
+				  const gchar *artist, 
+				  const gchar *album,
+				  const gchar *count)
+{
+	TrackerAlbumArtPrivate *private;
+	gchar *key;
+	QueuedAlbumArtScanRequest *info;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	key = g_strdup_printf ("%s%s%s", dirname, album, artist);
+	info = g_slice_new (QueuedAlbumArtScanRequest);
+
+	/* This method is typically called-for by the extractors. It's a request
+	 * for us (we're the delegate here) to do a heuristic scan for album-art.
+	 * 
+	 * This is a non-urgent request and these can happen rapidly with the 
+	 * same directory/album/artist combination many times in a row. 
+	 *
+	 * We are allowed to merge such requests together and perform it delayed */
+
+	info->dirname = g_strdup (dirname);
+	info->album   = g_strdup (album);
+	info->artist  = g_strdup (artist);
+	info->count   = g_strdup (count);
+
+	g_hash_table_replace (private->queue, key, info);
+
+	/* If there's a queue-run already enqueued, then we'll remove that one 
+	 * and we'll start a new one. */
+
+	if (private->queue_timeout != 0) {
+		g_source_remove (private->queue_timeout);
+	}
+
+	/* We hope to collect all requests for a album-art heuristic scan for
+	 * a given combination of album, artist and directory within 30 seconds.
+	 *
+	 * If a request comes after 30 seconds then that's too bad, we'll just 
+	 * do a new heuristic scan in that case.*/
+
+	private->queue_timeout = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
+							     ALBUMART_HEURISTIC_SCAN_TIMEOUT,
+							     on_queue_timeout, NULL,
+							     NULL);
+}
+
+
+static void
+private_free (gpointer data)
+{
+	TrackerAlbumArtPrivate *private;
+
+	private = data;
+
+	if (private->queue_timeout != 0) {
+		g_source_remove (private->queue_timeout);
+	}
+
+	on_queue_timeout (private->queue);
+
+	g_hash_table_destroy (private->queue);
+	g_object_unref (private->hal);
+
+	g_free (private);
+}
+
+
+void
+tracker_albumart_init (void)
+{
+	TrackerAlbumArtPrivate *private;
+
+	private = g_new0 (TrackerAlbumArtPrivate, 1);
+
+	private->queue_timeout = 0;
+	private->no_more_requesting = FALSE;
+
+#ifdef HAVE_HAL
+	private->hal = tracker_hal_new ();
+#else
+	private->hal = NULL;
+#endif
+
+	private->queue = g_hash_table_new_full (g_str_hash, g_str_equal,
+						(GDestroyNotify) g_free,
+						(GDestroyNotify) queued_album_art_scan_request_free);
+
+	g_static_private_set (&private_key,
+			      private,
+			      private_free);
+}
+
+void
+tracker_albumart_shutdown (void)
+{
+	g_static_private_set (&private_key, NULL, NULL);
+}
diff --git a/src/libtracker-common/tracker-albumart.h b/src/libtracker-common/tracker-albumart.h
index 9e7e15a..152dd35 100644
--- a/src/libtracker-common/tracker-albumart.h
+++ b/src/libtracker-common/tracker-albumart.h
@@ -32,26 +32,22 @@ G_BEGIN_DECLS
 
 #include "tracker-hal.h"
 
-gboolean tracker_albumart_heuristic        (const gchar *artist_,  
-					    const gchar *album_, 
-					    const gchar *tracks_str, 
-					    const gchar *filename,
-					    const gchar *local_uri,
-					    gboolean    *copied);
-void     tracker_albumart_copy_to_local    (TrackerHal  *hal,
-					    const gchar *filename, 
-					    const gchar *local_uri);
-void     tracker_albumart_get_path         (const gchar  *a, 
-					    const gchar  *b, 
+void     tracker_albumart_heuristic_queue (const gchar *dirname, 
+					   const gchar *artist, 
+					   const gchar *album,
+					   const gchar *count);
+
+void     tracker_albumart_get_path         (const gchar  *album, 
+					    const gchar  *artist, 
 					    const gchar  *prefix, 
-					    const gchar  *uri,
-					    gchar       **path,
-					    gchar       **local);
-void     tracker_albumart_request_download (TrackerHal  *hal,
-					    const gchar *album, 
-					    const gchar *artist, 
-					    const gchar *local_uri, 
-					    const gchar *art_path);
+					    gchar       **path);
+
+void     tracker_albumart_copy_to_local_if (const gchar *album_art_file,
+					    const gchar *dirname);
+
+void     tracker_albumart_init             (void);
+void     tracker_albumart_shutdown         (void);
+
 
 G_END_DECLS
 
diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index 0a660cb..7ad0a70 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -211,6 +211,7 @@ libextract_playlist_la_LIBADD = $(GLIB2_LIBS) $(TOTEM_PL_PARSER_LIBS) $(GCOV_LIB
 libexec_PROGRAMS = tracker-extract
 
 tracker_extract_SOURCES = 						\
+	tracker-marshal-main.c						\
 	tracker-dbus.c							\
 	tracker-dbus.h							\
 	tracker-extract.c						\
@@ -231,7 +232,23 @@ dbus_sources = 								\
 %-glue.h: $(top_srcdir)/data/dbus/%.xml
 	$(DBUSBINDINGTOOL) --mode=glib-server --output=$@ --prefix=$(subst -,_,$*) $^
 
+tracker-marshal.h: tracker-marshal.list
+	$(GLIB_GENMARSHAL) $< --prefix=tracker_marshal --header > $@
+
+tracker-marshal.c: tracker-marshal.list
+	$(GLIB_GENMARSHAL) $< --prefix=tracker_marshal --body > $@
+
+tracker-marshal-main.c: tracker-marshal.c tracker-marshal.h
+
+marshal_sources =                                         		\
+        tracker-marshal.h                             			\
+        tracker-marshal.c
+
 BUILT_SOURCES = 							\
-	$(dbus_sources)
+	$(dbus_sources)							\
+	$(marshal_sources)
 
 CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = tracker-marshal.list
+
diff --git a/src/tracker-extract/tracker-extract-albumart.c b/src/tracker-extract/tracker-extract-albumart.c
index 206a836..92b13ca 100644
--- a/src/tracker-extract/tracker-extract-albumart.c
+++ b/src/tracker-extract/tracker-extract-albumart.c
@@ -42,6 +42,7 @@
 
 #include "tracker-main.h"
 #include "tracker-extract-albumart.h"
+#include "tracker-extract.h"
 
 #ifdef HAVE_GDKPIXBUF
 
@@ -64,7 +65,7 @@ set_albumart (const unsigned char *buffer,
 		return FALSE;
 	}
 
-	tracker_albumart_get_path (artist, album, "album", NULL, &filename, NULL);
+	tracker_albumart_get_path (artist, album, "album", &filename);
 
 	loader = gdk_pixbuf_loader_new ();
 
@@ -99,6 +100,7 @@ set_albumart (const unsigned char *buffer,
 	}
 
 	tracker_thumbnailer_queue_file (filename, "image/jpeg");
+	
 	g_free (filename);
 
 	return TRUE;
@@ -116,89 +118,34 @@ tracker_process_albumart (const unsigned char *buffer,
 {
 	gchar *art_path;
 	gboolean retval = TRUE;
-	gchar *local_uri = NULL;
-	gchar *filename_uri;
-	gboolean lcopied = FALSE;
-
-	if (strchr (filename, ':')) {
-		filename_uri = g_strdup (filename);
-	} else {
-		filename_uri = g_filename_to_uri (filename, NULL, NULL);
-	}
 
-	tracker_albumart_get_path (artist, 
-				   album, 
-				   "album", 
-				   filename_uri, 
-				   &art_path, 
-				   &local_uri);
+	tracker_albumart_get_path (artist, album, "album", &art_path);
 
 	if (!art_path) {
-		g_free (filename_uri);
-		g_free (local_uri);
-
 		return FALSE;
 	}
 
 	if (!g_file_test (art_path, G_FILE_TEST_EXISTS)) {
+		gchar *dirname = g_path_get_dirname (filename);
+
 #ifdef HAVE_GDKPIXBUF
 		/* If we have embedded album art */
 		if (buffer && len) {
-			retval = set_albumart (buffer, 
-					       len,
-					       artist,
-					       album,
-					       filename);
-
-			lcopied = !retval;
-
+			retval = set_albumart (buffer, len, artist, album, filename);
+			tracker_extract_emit_copy_to_local_if (filename, dirname);
 		} else {
 #endif /* HAVE_GDK_PIXBUF */
-			/* If not, we perform a heuristic on the dir */
-			if (!tracker_albumart_heuristic (artist, album, 
-			                                 trackercnt_str, 
-			                                 filename, 
-			                                 local_uri, 
-			                                 &lcopied)) {
-
-				/* If the heuristic failed, we request the download 
-				 * of the media-art to the media-art downloaders */
-				lcopied = TRUE;
-				tracker_albumart_request_download (tracker_main_get_hal (), 
-								   artist,
-								   album,
-								   local_uri,
-								   art_path);
-			}
+			tracker_extract_emit_scan_for_albumart (dirname, artist,
+								album, trackercnt_str);
 #ifdef HAVE_GDKPIXBUF
 		}
 #endif /* HAVE_GDKPIXBUF */
 
-		/* If the heuristic didn't copy from the .mediaartlocal, then 
-		 * we'll perhaps copy it to .mediaartlocal (perhaps because this
-		 * only copies in case the media is located on a removable 
-		 * device */
-
-		if (g_file_test (art_path, G_FILE_TEST_EXISTS)) {
-			gchar *as_uri;
-
-			as_uri = g_filename_to_uri (art_path, NULL, NULL);
-			tracker_thumbnailer_queue_file (as_uri, "image/jpeg");
-			g_free (as_uri);
-		}
-
-	}
+		g_free (dirname);
 
-	if (local_uri && !g_file_test (local_uri, G_FILE_TEST_EXISTS)) {
-		if (g_file_test (art_path, G_FILE_TEST_EXISTS))
-			tracker_albumart_copy_to_local (tracker_main_get_hal (),
-							art_path, 
-							local_uri);
 	}
 
 	g_free (art_path);
-	g_free (filename_uri);
-	g_free (local_uri);
 
 	return retval;
 }
diff --git a/src/tracker-extract/tracker-extract.c b/src/tracker-extract/tracker-extract.c
index 648ed8b..25392f4 100644
--- a/src/tracker-extract/tracker-extract.c
+++ b/src/tracker-extract/tracker-extract.c
@@ -30,7 +30,11 @@
 
 #include "tracker-main.h"
 #include "tracker-dbus.h"
+#include "tracker-marshal.h"
+
+#define TRACKER_EXTRACT_C
 #include "tracker-extract.h"
+#undef TRACKER_EXTRACT_C
 
 #define MAX_EXTRACT_TIME 5
 #define TRACKER_EXTRACT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_EXTRACT, TrackerExtractPrivate))
@@ -39,10 +43,22 @@ typedef struct {
 	GArray *extractors;
 } TrackerExtractPrivate;
 
+
+enum {
+	TO_SCAN_FOR_ALBUMART,
+	TO_COPY_TO_LOCAL_IF,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+
 static void tracker_extract_finalize (GObject *object);
 
 G_DEFINE_TYPE(TrackerExtract, tracker_extract, G_TYPE_OBJECT)
 
+TrackerExtract *dbus_object = NULL;
+
 static void
 tracker_extract_class_init (TrackerExtractClass *klass)
 {
@@ -50,6 +66,32 @@ tracker_extract_class_init (TrackerExtractClass *klass)
 
 	object_class = G_OBJECT_CLASS (klass);
 
+	signals[TO_SCAN_FOR_ALBUMART] =
+		g_signal_new ("to-scan-for-albumart",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (TrackerExtractClass, to_scan_for_albumart),
+			      NULL, NULL,
+			      tracker_marshal_VOID__STRING_STRING_STRING_STRING,
+			      G_TYPE_NONE,
+			      4,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING);
+
+	signals[TO_COPY_TO_LOCAL_IF] =
+		g_signal_new ("to-copy-to-local-if",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (TrackerExtractClass, to_copy_to_local_if),
+			      NULL, NULL,
+			      tracker_marshal_VOID__STRING_STRING,
+			      G_TYPE_NONE,
+			      2,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING);
+
 	object_class->finalize = tracker_extract_finalize;
 
 	g_type_class_add_private (object_class, sizeof (TrackerExtractPrivate));
@@ -60,6 +102,29 @@ tracker_extract_init (TrackerExtract *object)
 {
 }
 
+void
+tracker_extract_emit_scan_for_albumart (const gchar *dirname,
+					const gchar *artist,
+					const gchar *album,
+					const gchar *count)
+{
+	if (dbus_object) {
+		g_signal_emit (dbus_object, signals[TO_SCAN_FOR_ALBUMART], 0,
+			       dirname, artist, album, count);
+	}
+}
+
+
+void
+tracker_extract_emit_copy_to_local_if (const gchar *filename,
+				       const gchar *dirname)
+{
+	if (dbus_object) {
+		g_signal_emit (dbus_object, signals[TO_COPY_TO_LOCAL_IF], 0,
+			       filename, dirname);
+	}
+}
+
 static void
 tracker_extract_finalize (GObject *object)
 {
@@ -166,6 +231,8 @@ tracker_extract_new (void)
 
 	priv->extractors = extractors;
 
+	dbus_object = object;
+
 	return object;
 }
 
diff --git a/src/tracker-extract/tracker-extract.h b/src/tracker-extract/tracker-extract.h
index 8cc031f..5837ed2 100644
--- a/src/tracker-extract/tracker-extract.h
+++ b/src/tracker-extract/tracker-extract.h
@@ -47,6 +47,13 @@ struct TrackerExtract {
 
 struct TrackerExtractClass {
 	GObjectClass parent;
+
+	void (*to_scan_for_albumart)                    (const gchar *dirname,
+							 const gchar *artist,
+							 const gchar *album,
+							 const gchar *count);
+	void (*to_copy_to_local_if)                     (const gchar *filename,
+							 const gchar *dirname);
 };
 
 GType           tracker_extract_get_type                (void);
@@ -60,11 +67,20 @@ void            tracker_extract_get_metadata            (TrackerExtract
 							 DBusGMethodInvocation  *context,
 							 GError                **error);
 
+void            tracker_extract_emit_scan_for_albumart  (const gchar            *dirname,
+							 const gchar            *artist,
+							 const gchar            *album,
+							 const gchar            *count);
+void            tracker_extract_emit_copy_to_local_if   (const gchar            *filename,
+							 const gchar            *dirname);
+
 /* Not DBus API, convenience for command line */
 void            tracker_extract_get_metadata_by_cmdline (TrackerExtract         *object,
 							 const gchar            *path,
 							 const gchar            *mime);
 
+
+
 G_END_DECLS
 
 #endif /* __TRACKERD_EXTRACT_H__ */
diff --git a/src/tracker-extract/tracker-main.c b/src/tracker-extract/tracker-main.c
index 45cb892..9f44018 100644
--- a/src/tracker-extract/tracker-main.c
+++ b/src/tracker-extract/tracker-main.c
@@ -68,7 +68,6 @@
 
 static GMainLoop  *main_loop;
 static guint       quit_timeout_id = 0;
-static TrackerHal *hal;
 
 static gboolean    version;
 static gint        verbosity = -1;
@@ -118,19 +117,6 @@ tracker_main_quit_timeout_reset (void)
 						 NULL);
 }
 
-TrackerHal *
-tracker_main_get_hal (void)
-{
-	if (!hal) {
-#ifdef HAVE_HAL
-		hal = tracker_hal_new ();
-#else 
-		hal = NULL;
-#endif
-	}
-
-	return hal;
-}
 
 static void
 initialize_priority (void)
@@ -354,9 +340,6 @@ main (int argc, char *argv[])
 	tracker_thumbnailer_shutdown ();
 	tracker_log_shutdown ();
 
-	if (hal) {
-		g_object_unref (hal);
-	}
 
 	g_free (log_filename);
 	g_object_unref (config);
diff --git a/src/tracker-extract/tracker-main.h b/src/tracker-extract/tracker-main.h
index ed23470..6d40d9d 100644
--- a/src/tracker-extract/tracker-main.h
+++ b/src/tracker-extract/tracker-main.h
@@ -24,8 +24,6 @@
 
 #include <glib.h>
 
-#include <libtracker-common/tracker-hal.h>
-
 #include "tracker-escape.h"
 
 G_BEGIN_DECLS
@@ -44,12 +42,6 @@ struct TrackerExtractData {
 /* This is defined in each extract */
 TrackerExtractData *tracker_get_extract_data        (void);
 
-/* Some modules need to use the albumart API which requires HAL. To
- * avoid creating new HAL objects constantly, we initialize it once
- * and it is available using this API.
- */
-TrackerHal *        tracker_main_get_hal            (void);
-
 /* This is used to not shutdown after the default of 30 seconds if we
  * get more work to do.
  */
diff --git a/src/tracker-extract/tracker-marshal.list b/src/tracker-extract/tracker-marshal.list
index 0e62e59..a3d054a 100644
--- a/src/tracker-extract/tracker-marshal.list
+++ b/src/tracker-extract/tracker-marshal.list
@@ -1 +1,2 @@
 VOID:STRING,STRING,STRING,STRING
+VOID:STRING,STRING
diff --git a/src/tracker-indexer/tracker-main.c b/src/tracker-indexer/tracker-main.c
index 8106af4..720c6cd 100644
--- a/src/tracker-indexer/tracker-main.c
+++ b/src/tracker-indexer/tracker-main.c
@@ -42,6 +42,7 @@
 #include <libtracker-common/tracker-module-config.h>
 #include <libtracker-common/tracker-file-utils.h>
 #include <libtracker-common/tracker-thumbnailer.h>
+#include <libtracker-common/tracker-albumart.h>
 
 #include <libtracker-db/tracker-db-manager.h>
 #include <libtracker-db/tracker-db-index-manager.h>
@@ -391,6 +392,7 @@ main (gint argc, gchar *argv[])
 
 	/* Set up connections to the thumbnailer if supported */
 	tracker_thumbnailer_init (config);
+	tracker_albumart_init ();
 
 	if (process_all) {
 		/* Tell the indexer to process all configured modules */
@@ -431,6 +433,7 @@ main (gint argc, gchar *argv[])
 
 	tracker_push_shutdown ();
 
+	tracker_albumart_shutdown ();
 	tracker_thumbnailer_shutdown ();
 	tracker_dbus_shutdown ();
 	tracker_db_index_manager_shutdown ();
diff --git a/src/tracker-indexer/tracker-marshal.list b/src/tracker-indexer/tracker-marshal.list
index f17b920..2cc716c 100644
--- a/src/tracker-indexer/tracker-marshal.list
+++ b/src/tracker-indexer/tracker-marshal.list
@@ -1,3 +1,5 @@
 VOID:DOUBLE,UINT,UINT,BOOL
 VOID:DOUBLE,STRING,UINT,UINT,UINT
 VOID:STRING,BOOL
+VOID:STRING,STRING,STRING,STRING
+VOID:STRING,STRING
diff --git a/src/tracker-indexer/tracker-module-metadata-utils.c b/src/tracker-indexer/tracker-module-metadata-utils.c
index b830efd..00c1fcd 100644
--- a/src/tracker-indexer/tracker-module-metadata-utils.c
+++ b/src/tracker-indexer/tracker-module-metadata-utils.c
@@ -37,10 +37,12 @@
 #include <libtracker-common/tracker-os-dependant.h>
 #include <libtracker-common/tracker-ontology.h>
 #include <libtracker-common/tracker-thumbnailer.h>
+#include <libtracker-common/tracker-albumart.h>
 
 #include "tracker-module-metadata-utils.h"
 #include "tracker-extract-client.h"
 #include "tracker-dbus.h"
+#include "tracker-marshal.h"
 
 #define METADATA_FILE_NAME_DELIMITED "File:NameDelimited"
 #define METADATA_FILE_EXT            "File:Ext"
@@ -73,6 +75,27 @@ typedef struct {
         GPid pid;
 } ExtractorContext;
 
+
+static void
+extractor_asks_to_scan_for_albumart (DBusGProxy  *proxy,
+				     const gchar *dirname,
+				     const gchar *artist,
+				     const gchar *album,
+				     const gchar *count,
+				     gpointer     user_data)
+{
+	tracker_albumart_heuristic_queue (dirname, artist, album, count);
+}
+
+static void
+extractor_asks_to_copy_to_local_if (DBusGProxy  *proxy,
+				     const gchar *filename,
+				     const gchar *dirname,
+				     gpointer     user_data)
+{
+	tracker_albumart_copy_to_local_if (filename, dirname);
+}
+
 static DBusGProxy *
 get_dbus_extract_proxy (void)
 {
@@ -104,6 +127,33 @@ get_dbus_extract_proxy (void)
                 g_critical ("Could not create a DBusGProxy to the extract service");
         }
 
+	dbus_g_object_register_marshaller (tracker_marshal_VOID__STRING_STRING_STRING_STRING,
+					   G_TYPE_NONE,
+					   G_TYPE_STRING,
+					   G_TYPE_STRING,
+					   G_TYPE_STRING,
+					   G_TYPE_STRING,
+					   G_TYPE_INVALID);
+
+	dbus_g_object_register_marshaller (tracker_marshal_VOID__STRING_STRING,
+					   G_TYPE_NONE,
+					   G_TYPE_STRING,
+					   G_TYPE_STRING,
+					   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (proxy,
+				 "ToCopyToLocalIf",
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal (proxy, "ToScanForAlbumart",
+				     G_CALLBACK (extractor_asks_to_scan_for_albumart),
+				     NULL, NULL);
+
+	dbus_g_proxy_connect_signal (proxy, "ToCopyToLocalIf",
+				     G_CALLBACK (extractor_asks_to_copy_to_local_if),
+				     NULL, NULL);
+
         return proxy;
 }
 
diff --git a/tests/tracker-extract/tracker-extract-test-utils.c b/tests/tracker-extract/tracker-extract-test-utils.c
index ba3cdd5..ef76ed7 100644
--- a/tests/tracker-extract/tracker-extract-test-utils.c
+++ b/tests/tracker-extract/tracker-extract-test-utils.c
@@ -327,11 +327,19 @@ tracker_test_extract_file_access (const TrackerExtractData *data,
 	}		
 }
 
-/* This is added because tracker-main.c includes this file and so
- * should we otherwise it is missing when we try to build the tests.
- */
-TrackerHal *
-tracker_main_get_hal (void)
+void
+tracker_extract_emit_scan_for_albumart (const gchar *dirname,
+					const gchar *artist,
+					const gchar *album,
+					const gchar *count)
 {
-	return NULL;
+	/* To avoid linking problems in the test tools during dlopen() */
+}
+
+
+void
+tracker_extract_emit_copy_to_local_if (const gchar *filename,
+				       const gchar *dirname)
+{
+	/* To avoid linking problems in the test tools during dlopen() */
 }
_______________________________________________
tracker-list mailing list
tracker-list@gnome.org
http://mail.gnome.org/mailman/listinfo/tracker-list

Reply via email to