tracker-0.16.2/src/libtracker-miner/tracker-thumbnailer.c

No issues found

  1 /*
  2  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the Free Software
 16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 17  * 02110-1301  USA
 18  */
 19 
 20 #include "config.h"
 21 
 22 #include <string.h>
 23 
 24 #include <libtracker-common/tracker-dbus.h>
 25 
 26 #include "tracker-thumbnailer.h"
 27 
 28 /**
 29  * SECTION:tracker-thumbnailer
 30  * @title: Thumbnailer management
 31  * @short_description: Request the thumbnailer service creates or
 32  * updates thumbnails.
 33  * @include: libtracker-miner/tracker-miner.h
 34  *
 35  * This is a convenience API using D-Bus for creating and updating
 36  * thumbnails for files being mined. It is also used to create
 37  * thumbnails for album art found embedded in some medias.
 38  *
 39  * This follows the thumbnailer specification:
 40  * http://live.gnome.org/ThumbnailerSpec
 41  **/
 42 
 43 #define THUMBCACHE_SERVICE      "org.freedesktop.thumbnails.Cache1"
 44 #define THUMBCACHE_PATH         "/org/freedesktop/thumbnails/Cache1"
 45 #define THUMBCACHE_INTERFACE    "org.freedesktop.thumbnails.Cache1"
 46 
 47 #define THUMBMAN_SERVICE        "org.freedesktop.thumbnails.Thumbnailer1"
 48 #define THUMBMAN_PATH           "/org/freedesktop/thumbnails/Thumbnailer1"
 49 #define THUMBMAN_INTERFACE      "org.freedesktop.thumbnails.Thumbnailer1"
 50 
 51 typedef struct {
 52 	GDBusProxy *cache_proxy;
 53 	GDBusProxy *manager_proxy;
 54 	GDBusConnection *connection;
 55 
 56 	GStrv supported_mime_types;
 57 
 58 	GSList *removes;
 59 	GSList *moves_to;
 60 	GSList *moves_from;
 61 
 62 	guint request_id;
 63 	gboolean service_is_available;
 64 } TrackerThumbnailerPrivate;
 65 
 66 #if GLIB_CHECK_VERSION (2,31,0)
 67 static void private_free (gpointer data);
 68 static GPrivate private_key = G_PRIVATE_INIT (private_free);
 69 #else
 70 static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
 71 #endif
 72 
 73 static void
 74 private_free (gpointer data)
 75 {
 76 	TrackerThumbnailerPrivate *private;
 77 
 78 	private = data;
 79 
 80 	if (private->cache_proxy) {
 81 		g_object_unref (private->cache_proxy);
 82 	}
 83 
 84 	if (private->manager_proxy) {
 85 		g_object_unref (private->manager_proxy);
 86 	}
 87 
 88 	if (private->connection) {
 89 		g_object_unref (private->connection);
 90 	}
 91 
 92 	g_strfreev (private->supported_mime_types);
 93 
 94 	g_slist_foreach (private->removes, (GFunc) g_free, NULL);
 95 	g_slist_free (private->removes);
 96 
 97 	g_slist_foreach (private->moves_to, (GFunc) g_free, NULL);
 98 	g_slist_free (private->moves_to);
 99 
100 	g_slist_foreach (private->moves_from, (GFunc) g_free, NULL);
101 	g_slist_free (private->moves_from);
102 
103 	g_free (private);
104 }
105 
106 inline static gboolean
107 should_be_thumbnailed (GStrv        list,
108                        const gchar *mime)
109 {
110 	gboolean should_thumbnail;
111 	guint i;
112 
113 	if (!list) {
114 		return TRUE;
115 	}
116 
117 	for (should_thumbnail = FALSE, i = 0;
118 	     should_thumbnail == FALSE && list[i] != NULL;
119 	     i++) {
120 		if (g_ascii_strcasecmp (list[i], mime) == 0) {
121 			should_thumbnail = TRUE;
122 		}
123 	}
124 
125 	return should_thumbnail;
126 }
127 
128 /**
129  * tracker_thumbnailer_init:
130  *
131  * Initializes the thumbnailer connection.
132  *
133  * Returns: #TRUE if connection was successfully initialized, #FALSE otherwise.
134  *
135  * Since: 0.8
136  */
137 gboolean
138 tracker_thumbnailer_init (void)
139 {
140 	TrackerThumbnailerPrivate *private;
141 	GError *error = NULL;
142 	GVariant *v;
143 
144 	private = g_new0 (TrackerThumbnailerPrivate, 1);
145 
146 	/* Don't start at 0, start at 1. */
147 	private->request_id = 1;
148 
149 #if GLIB_CHECK_VERSION (2,31,0)
150 	g_private_replace (&private_key, private);
151 #else
152 	g_static_private_set (&private_key, private, private_free);
153 #endif
154 
155 	g_message ("Thumbnailer connections being set up...");
156 
157 	private->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
158 
159 	if (!private->connection) {
160 		g_critical ("Could not connect to the D-Bus session bus, %s",
161 		            error ? error->message : "no error given.");
162 		g_clear_error (&error);
163 
164 		private->service_is_available = FALSE;
165 
166 		return FALSE;
167 	}
168 
169 	private->cache_proxy = g_dbus_proxy_new_sync (private->connection,
170 	                                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
171 	                                              NULL,
172 	                                              THUMBCACHE_SERVICE,
173 	                                              THUMBCACHE_PATH,
174 	                                              THUMBCACHE_INTERFACE,
175 	                                              NULL,
176 	                                              &error);
177 
178 	if (error) {
179 		goto error_handler;
180 	}
181 
182 	private->manager_proxy = g_dbus_proxy_new_sync (private->connection,
183 	                                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
184 	                                                NULL,
185 	                                                THUMBMAN_SERVICE,
186 	                                                THUMBMAN_PATH,
187 	                                                THUMBMAN_INTERFACE,
188 	                                                NULL,
189 	                                                &error);
190 
191 	if (error) {
192 		goto error_handler;
193 	}
194 
195 	v = g_dbus_proxy_call_sync (private->manager_proxy,
196 	                            "GetSupported",
197 	                            NULL,
198 	                            G_DBUS_CALL_FLAGS_NONE,
199 	                            -1,
200 	                            NULL,
201 	                            &error);
202 
203 error_handler:
204 
205 	if (error) {
206 		g_message ("Thumbnailer service did not return supported mime types, %s",
207 		           error->message);
208 
209 		g_error_free (error);
210 
211 		if (private->cache_proxy) {
212 			g_object_unref (private->cache_proxy);
213 			private->cache_proxy = NULL;
214 		}
215 
216 		if (private->manager_proxy) {
217 			g_object_unref (private->manager_proxy);
218 			private->manager_proxy = NULL;
219 		}
220 
221 		return FALSE;
222 	} else if (v) {
223 		GStrv mime_types = NULL;
224 		GStrv uri_schemes = NULL;
225 
226 		g_variant_get (v, "(^a&s^a&s)", &uri_schemes, &mime_types);
227 
228 		if (mime_types) {
229 			GHashTable *hash;
230 			GHashTableIter iter;
231 			gpointer key, value;
232 			guint i;
233 
234 			/* The table that you receive may contain duplicate mime-types, because
235 			 * they are grouped against the uri_schemes table */
236 
237 			hash = g_hash_table_new (g_str_hash, g_str_equal);
238 
239 			for (i = 0; mime_types[i] != NULL; i++) {
240 				g_hash_table_insert (hash, mime_types[i], NULL);
241 			}
242 
243 			i = g_hash_table_size (hash);
244 			g_message ("Thumbnailer supports %d mime types", i);
245 
246 			g_hash_table_iter_init (&iter, hash);
247 			private->supported_mime_types = (GStrv) g_new0 (gchar *, i + 1);
248 
249 			i = 0;
250 			while (g_hash_table_iter_next (&iter, &key, &value)) {
251 				private->supported_mime_types[i] = g_strdup (key);
252 				i++;
253 			}
254 
255 			g_hash_table_unref (hash);
256 
257 			private->service_is_available = TRUE;
258 		}
259 
260 		g_free (mime_types);
261 		g_free (uri_schemes);
262 
263 		g_variant_unref (v);
264 	}
265 
266 	return TRUE;
267 }
268 
269 /**
270  * tracker_thumbnailer_shutdown:
271  *
272  * Shuts down the thumbnailer connection.
273  *
274  * Since: 0.8
275  */
276 void
277 tracker_thumbnailer_shutdown (void)
278 {
279 #if GLIB_CHECK_VERSION (2,31,0)
280 	g_private_replace (&private_key, NULL);
281 #else
282 	g_static_private_set (&private_key, NULL, NULL);
283 #endif
284 }
285 
286 /**
287  * tracker_thumbnailer_move_add:
288  * @from_uri: URI of the file before the move
289  * @mime_type: mime-type of the file
290  * @to_uri: URI of the file after the move
291  *
292  * Adds a new request to tell the thumbnailer that @from_uri was moved to
293  * @to_uri. Stored requests can be sent with tracker_thumbnailer_send().
294  *
295  * Returns: #TRUE if successfully stored to be reported, #FALSE otherwise.
296  *
297  * Since: 0.8
298  */
299 gboolean
300 tracker_thumbnailer_move_add (const gchar *from_uri,
301                               const gchar *mime_type,
302                               const gchar *to_uri)
303 {
304 
305 	TrackerThumbnailerPrivate *private;
306 
307 	/* mime_type can be NULL */
308 
309 	g_return_val_if_fail (from_uri != NULL, FALSE);
310 	g_return_val_if_fail (to_uri != NULL, FALSE);
311 
312 #if GLIB_CHECK_VERSION (2,31,0)
313 	private = g_private_get (&private_key);
314 #else
315 	private = g_static_private_get (&private_key);
316 #endif
317 	g_return_val_if_fail (private != NULL, FALSE);
318 
319 	if (!private->service_is_available) {
320 		return FALSE;
321 	}
322 
323 	if (mime_type && !should_be_thumbnailed (private->supported_mime_types, mime_type)) {
324 		return FALSE;
325 	}
326 
327 	private->moves_from = g_slist_prepend (private->moves_from, g_strdup (from_uri));
328 	private->moves_to = g_slist_prepend (private->moves_to, g_strdup (to_uri));
329 
330 	g_debug ("Thumbnailer request to move uri from:'%s' to:'%s' queued",
331 	         from_uri,
332 	         to_uri);
333 
334 	return TRUE;
335 }
336 
337 /**
338  * tracker_thumbnailer_remove_add:
339  * @uri: URI of the file
340  * @mime_type: mime-type of the file
341  *
342  * Adds a new request to tell the thumbnailer that @uri was removed.
343  * Stored requests can be sent with tracker_thumbnailer_send().
344  *
345  * Returns: #TRUE if successfully stored to be reported, #FALSE otherwise.
346  *
347  * Since: 0.8
348  */
349 gboolean
350 tracker_thumbnailer_remove_add (const gchar *uri,
351                                 const gchar *mime_type)
352 {
353 	TrackerThumbnailerPrivate *private;
354 
355 	/* mime_type can be NULL */
356 
357 	g_return_val_if_fail (uri != NULL, FALSE);
358 
359 #if GLIB_CHECK_VERSION (2,31,0)
360 	private = g_private_get (&private_key);
361 #else
362 	private = g_static_private_get (&private_key);
363 #endif
364 	g_return_val_if_fail (private != NULL, FALSE);
365 
366 	if (!private->service_is_available) {
367 		return FALSE;
368 	}
369 
370 	if (mime_type && !should_be_thumbnailed (private->supported_mime_types, mime_type)) {
371 		return FALSE;
372 	}
373 
374 	private->removes = g_slist_prepend (private->removes, g_strdup (uri));
375 
376 	g_debug ("Thumbnailer request to remove uri:'%s', appended to queue", uri);
377 
378 	return TRUE;
379 }
380 
381 /**
382  * tracker_thumbnailer_cleanup:
383  * @uri_prefix: URI prefix
384  *
385  * Tells thumbnailer to cleanup all thumbnails under @uri_prefix.
386  *
387  * Returns: #TRUE if successfully reported, #FALSE otherwise.
388  *
389  * Since: 0.8
390  */
391 gboolean
392 tracker_thumbnailer_cleanup (const gchar *uri_prefix)
393 {
394 	TrackerThumbnailerPrivate *private;
395 
396 	g_return_val_if_fail (uri_prefix != NULL, FALSE);
397 
398 #if GLIB_CHECK_VERSION (2,31,0)
399 	private = g_private_get (&private_key);
400 #else
401 	private = g_static_private_get (&private_key);
402 #endif
403 	g_return_val_if_fail (private != NULL, FALSE);
404 
405 	if (!private->service_is_available) {
406 		return FALSE;
407 	}
408 
409 	private->request_id++;
410 
411 	g_debug ("Thumbnailer cleaning up uri:'%s', request_id:%d...",
412 	         uri_prefix,
413 	         private->request_id);
414 
415 	g_dbus_proxy_call (private->cache_proxy,
416 	                   "Cleanup",
417 	                   g_variant_new ("(s)", uri_prefix),
418 	                   G_DBUS_CALL_FLAGS_NONE,
419 	                   -1,
420 	                   NULL,
421 	                   NULL,
422 	                   NULL);
423 
424 	return TRUE;
425 }
426 
427 /**
428  * tracker_thumbnailer_send:
429  *
430  * Sends to the thumbnailer all stored requests.
431  *
432  * Since: 0.8
433  */
434 void
435 tracker_thumbnailer_send (void)
436 {
437 	TrackerThumbnailerPrivate *private;
438 	guint list_len;
439 
440 #if GLIB_CHECK_VERSION (2,31,0)
441 	private = g_private_get (&private_key);
442 #else
443 	private = g_static_private_get (&private_key);
444 #endif
445 	g_return_if_fail (private != NULL);
446 
447 	if (!private->service_is_available) {
448 		return;
449 	}
450 
451 	list_len = g_slist_length (private->removes);
452 
453 	if (list_len > 0) {
454 		GStrv uri_strv;
455 
456 		uri_strv = tracker_dbus_slist_to_strv (private->removes);
457 
458 		g_dbus_proxy_call (private->cache_proxy,
459 		                   "Delete",
460 		                   g_variant_new ("(^as)", uri_strv),
461 		                   G_DBUS_CALL_FLAGS_NONE,
462 		                   -1,
463 		                   NULL,
464 		                   NULL,
465 		                   NULL);
466 
467 		g_message ("Thumbnailer removes queue sent with %d items to thumbnailer daemon, request ID:%d...",
468 		           list_len,
469 		           private->request_id++);
470 
471 		/* Clean up newly created GStrv */
472 		g_strfreev (uri_strv);
473 
474 		/* Clean up privately held data */
475 		g_slist_foreach (private->removes, (GFunc) g_free, NULL);
476 		g_slist_free (private->removes);
477 		private->removes = NULL;
478 	}
479 
480 	list_len = g_slist_length (private->moves_from);
481 
482 	if (list_len > 0) {
483 		GStrv from_strv, to_strv;
484 
485 		g_assert (list_len == g_slist_length (private->moves_to));
486 
487 		from_strv = tracker_dbus_slist_to_strv (private->moves_from);
488 		to_strv = tracker_dbus_slist_to_strv (private->moves_to);
489 
490 		g_dbus_proxy_call (private->cache_proxy,
491 		                   "Move",
492 		                   g_variant_new ("(^as^as)", from_strv, to_strv),
493 		                   G_DBUS_CALL_FLAGS_NONE,
494 		                   -1,
495 		                   NULL,
496 		                   NULL,
497 		                   NULL);
498 
499 		g_message ("Thumbnailer moves queue sent with %d items to thumbnailer daemon, request ID:%d...",
500 		           list_len,
501 		           private->request_id++);
502 
503 		/* Clean up newly created GStrv */
504 		g_strfreev (from_strv);
505 		g_strfreev (to_strv);
506 
507 		/* Clean up privately held data */
508 		g_slist_foreach (private->moves_from, (GFunc) g_free, NULL);
509 		g_slist_free (private->moves_from);
510 		private->moves_from = NULL;
511 
512 		g_slist_foreach (private->moves_to, (GFunc) g_free, NULL);
513 		g_slist_free (private->moves_to);
514 		private->moves_to = NULL;
515 	}
516 }