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/data/dbus/tracker-extract.xml b/data/dbus/tracker-extract.xml
index 4d9de37..377ac59 100644
--- a/data/dbus/tracker-extract.xml
+++ b/data/dbus/tracker-extract.xml
@@ -21,5 +21,11 @@
       <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>
   </interface>
 </node>
diff --git a/src/libtracker-common/tracker-albumart.c b/src/libtracker-common/tracker-albumart.c
index fb0fe7e..4fa1d37 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,32 @@
 #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;
+} TrackerAlbumArtPrivate;
 
-static gboolean no_more_requesting = FALSE;
+typedef struct {
+	gchar *dirname;
+	gchar *album;
+	gchar *artist;
+	gchar *count;
+} QueuedAlbumArtScanRequest;
 
-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;
-}
+typedef struct {
+	TrackerHal *hal;
+	gchar *album;
+	gchar *artist;
+	gchar *dirname;
+} GetFileInfo;
 
-#ifndef HAVE_STRCASESTR
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
 
-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 */
 
 /* 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 +147,144 @@ make_directory_with_parents (GFile         *file,
   return g_file_make_directory (file, cancellable, error);
 }
 
+static 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
+	g_return_if_fail (private->hal != NULL);
+
+	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 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,146 +352,40 @@ 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);
-	}
-
-	*copied = FALSE;
-
-	file = g_file_new_for_path (filename);
-	basename = g_file_get_basename (file);
-	g_object_unref (file);
-
-	if (!basename) {
-		return FALSE;
-	}
-
-	dir = g_dir_open (basename, 0, NULL);
+	dir = g_dir_open (dirname, 0, NULL);
 
 	if (!dir) {
-		g_free (basename);
 		return FALSE;
 	}
 
 	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;
 	}
@@ -397,7 +401,7 @@ tracker_albumart_heuristic (const gchar *artist_,
 	/* 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 */
@@ -413,19 +417,18 @@ tracker_albumart_heuristic (const gchar *artist_,
 					
 					if (!target) {
 						tracker_albumart_get_path (artist, album, 
-									   "album", NULL, 
-									   &target, NULL);
+									   "album", &target);
 					}
 					
 					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 +442,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 +450,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,6 +471,7 @@ tracker_albumart_heuristic (const gchar *artist_,
 				}
 
 				if (retval) {
+					tracker_albumart_copy_to_local_if (target, dirname);
 					break;
 				}
 			}
@@ -486,7 +486,6 @@ tracker_albumart_heuristic (const gchar *artist_,
 	}
 
 	g_free (target);
-	g_free (basename);
 	g_free (artist);
 	g_free (album);
 
@@ -525,6 +524,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 +538,47 @@ 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 +591,6 @@ tracker_albumart_get_path (const gchar  *a,
 		*path = NULL;
 	}
 
-	if (local_uri) {
-		*local_uri = NULL;
-	}
-
 	if (!a && !b) {
 		return;
 	}
@@ -628,45 +632,27 @@ 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
+static void
 tracker_albumart_request_download (TrackerHal  *hal,
 				   const gchar *album, 
-				   const gchar *artist, 
-				   const gchar *local_uri, 
-				   const gchar *art_path)
+				   const gchar *artist,
+				   const gchar *dirname)
 {
 	GetFileInfo *info;
+	TrackerAlbumArtPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
 
 	g_return_if_fail (hal != NULL);
 
-	if (no_more_requesting) {
+	if (private->no_more_requesting) {
 		return;
 	}
 
@@ -678,8 +664,9 @@ tracker_albumart_request_download (TrackerHal  *hal,
 	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 +678,149 @@ 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 (private->hal, 
+								   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;
+	private->hal = tracker_hal_new ();
+	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..60fc017 100644
--- a/src/libtracker-common/tracker-albumart.h
+++ b/src/libtracker-common/tracker-albumart.h
@@ -32,26 +32,19 @@ 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_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..c8e2f42 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 ();
 
@@ -116,27 +117,10 @@ 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;
 	}
 
@@ -144,61 +128,21 @@ tracker_process_albumart (const unsigned char *buffer,
 #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);
 		} 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);
-			}
+			gchar *dirname = g_path_get_dirname (filename);
+			tracker_extract_emit_scan_for_albumart (dirname, artist,
+								album, trackercnt_str);
+			g_free (dirname);
+
 #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);
-		}
-
-	}
-
-	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..1cd673f 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,21 @@ typedef struct {
 	GArray *extractors;
 } TrackerExtractPrivate;
 
+
+enum {
+	TO_SCAN_FOR_ALBUMART,
+	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 +65,20 @@ 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);
+
 	object_class->finalize = tracker_extract_finalize;
 
 	g_type_class_add_private (object_class, sizeof (TrackerExtractPrivate));
@@ -60,6 +89,19 @@ 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);
+	}
+}
+
+
 static void
 tracker_extract_finalize (GObject *object)
 {
@@ -166,6 +208,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..33fc669 100644
--- a/src/tracker-extract/tracker-extract.h
+++ b/src/tracker-extract/tracker-extract.h
@@ -47,6 +47,11 @@ struct TrackerExtract {
 
 struct TrackerExtractClass {
 	GObjectClass parent;
+
+	void (*to_scan_for_albumart)                    (const gchar *dirname,
+							 const gchar *artist,
+							 const gchar *album,
+							 const gchar *count);
 };
 
 GType           tracker_extract_get_type                (void);
@@ -60,11 +65,18 @@ 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);
+
 /* 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-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..bca43c9 100644
--- a/src/tracker-indexer/tracker-marshal.list
+++ b/src/tracker-indexer/tracker-marshal.list
@@ -1,3 +1,4 @@
 VOID:DOUBLE,UINT,UINT,BOOL
 VOID:DOUBLE,STRING,UINT,UINT,UINT
 VOID:STRING,BOOL
+VOID:STRING,STRING,STRING,STRING
diff --git a/src/tracker-indexer/tracker-module-metadata-utils.c b/src/tracker-indexer/tracker-module-metadata-utils.c
index b830efd..2ee26b2 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,18 @@ 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 DBusGProxy *
 get_dbus_extract_proxy (void)
 {
@@ -104,6 +118,26 @@ 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_proxy_add_signal (proxy,
+				 "ToScanForAlbumart",
+				 G_TYPE_STRING,
+				 G_TYPE_STRING,
+				 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);
+
         return proxy;
 }
 
_______________________________________________
tracker-list mailing list
tracker-list@gnome.org
http://mail.gnome.org/mailman/listinfo/tracker-list

Reply via email to