summaryrefslogtreecommitdiff
path: root/libmediaart/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmediaart/cache.c')
-rw-r--r--libmediaart/cache.c271
1 files changed, 205 insertions, 66 deletions
diff --git a/libmediaart/cache.c b/libmediaart/cache.c
index 3492683..e89b3ab 100644
--- a/libmediaart/cache.c
+++ b/libmediaart/cache.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
@@ -271,6 +272,9 @@ media_art_checksum_for_data (GChecksumType checksum_type,
* When done, both #GFile<!-- -->s must be freed with g_object_unref() if
* non-%NULL.
*
+ * This operation should not use i/o, but it depends on the backend
+ * GFile implementation.
+ *
* Returns: %TRUE if @cache_file or @local_file were returned, otherwise %FALSE.
*
* Since: 0.2.0
@@ -332,10 +336,6 @@ media_art_get_file (const gchar *artist,
"media-art",
NULL);
- if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
- g_mkdir_with_parents (dir, 0770);
- }
-
if (artist) {
a = artist_checksum;
b = title ? title_checksum : space_checksum;
@@ -448,59 +448,45 @@ media_art_get_path (const gchar *artist,
return TRUE;
}
-static void
-media_art_remove_foreach (gpointer data,
- gpointer user_data)
-{
- gchar *filename = data;
- gboolean total_success = * (gboolean *) user_data;
- gboolean success;
-
- success = g_unlink (filename) == 0;
- total_success &= success;
-
- if (!success) {
- g_warning ("Could not delete file '%s'", filename);
- }
-
- g_free (filename);
-}
-
/**
* media_art_remove:
* @artist: artist the media art belongs to
* @album: (allow-none): album the media art belongs or %NULL
+ * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
+ * @error: location to store the error occurring, or %NULL to ignore
*
* Removes media art for given album/artist provided.
*
- * Returns: #TRUE on success, otherwise #FALSE.
+ * If @artist and @album are %NULL, ALL media art cache is removed.
+ *
+ * Returns: #TRUE on success, otherwise #FALSE where @error will be set.
*
* Since: 0.2.0
*/
gboolean
-media_art_remove (const gchar *artist,
- const gchar *album)
+media_art_remove (const gchar *artist,
+ const gchar *album,
+ GCancellable *cancellable,
+ GError **error)
{
- GError *error = NULL;
- GHashTable *table = NULL;
+ GError *local_error = NULL;
const gchar *name;
GDir *dir;
gchar *dirname;
- GList *to_remove = NULL;
- gchar *target = NULL;
gboolean success = TRUE;
g_return_val_if_fail (artist != NULL && artist[0] != '\0', FALSE);
dirname = g_build_filename (g_get_user_cache_dir (), "media-art", NULL);
- dir = g_dir_open (dirname, 0, &error);
- if (!dir || error) {
+ dir = g_dir_open (dirname, 0, &local_error);
+ if (!dir || local_error) {
/* Nothing to do if there is no directory in the first place. */
g_debug ("Removing media-art for artist:'%s', album:'%s': directory could not be opened, %s",
- artist, album, error ? error->message : "no error given");
+ artist, album, local_error ? local_error->message : "no error given");
+
+ g_clear_error (&local_error);
- g_clear_error (&error);
if (dir) {
g_dir_close (dir);
}
@@ -512,51 +498,204 @@ media_art_remove (const gchar *artist,
return TRUE;
}
- table = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) NULL);
-
- /* The get_path API does stripping itself */
- media_art_get_path (artist, album, "album", NULL, &target, NULL);
- if (target) {
- g_hash_table_replace (table, target, target);
- }
+ /* NOTE: We expect to not find some of these paths for
+ * artist/album conbinations, so don't error in those
+ * cases...
+ */
+ if (artist || album) {
+ gchar *target = NULL;
+ gint removed = 0;
- /* Add the album path also (to which the symlinks are made) */
- if (album) {
- media_art_get_path (NULL, album, "album", NULL, &target, NULL);
+ /* The get_path API does stripping itself */
+ media_art_get_path (artist, album, "album", NULL, &target, NULL);
if (target) {
- g_hash_table_replace (table, target, target);
+ if (g_unlink (target) != 0) {
+ g_debug ("Could not delete file '%s'", target);
+ } else {
+ g_message ("Removed media-art for artist:'%s', album:'%s': deleting file '%s'",
+ artist, album, target);
+ removed++;
+ }
+
+ g_free (target);
}
- }
- /* Perhaps we should have an internal list of media art files that we made,
- * instead of going over all the media art (which could also have been made
- * by other softwares) */
- for (name = g_dir_read_name (dir); name != NULL; name = g_dir_read_name (dir)) {
- gpointer value;
- gchar *full;
+ /* Add the album path also (to which the symlinks are made) */
+ if (album) {
+ media_art_get_path (NULL, album, "album", NULL, &target, NULL);
+ if (target) {
+ if (g_unlink (target) != 0) {
+ g_debug ("Could not delete file '%s'", target);
+ } else {
+ g_message ("Removed media-art for album:'%s': deleting file '%s'",
+ album, target);
+ removed++;
+ }
- full = g_build_filename (dirname, name, NULL);
- value = g_hash_table_lookup (table, full);
+ g_free (target);
+ }
+ }
- if (!value) {
- g_message ("Removing media-art for artist:'%s', album:'%s': deleting file '%s'",
- artist, album, name);
- to_remove = g_list_prepend (to_remove, (gpointer) full);
- } else {
- g_free (full);
+ success = removed > 0;
+ } else {
+ for (name = g_dir_read_name (dir);
+ name != NULL;
+ name = g_dir_read_name (dir)) {
+ gchar *target;
+
+ target = g_build_filename (dirname, name, NULL);
+
+ if (g_unlink (target) != 0) {
+ g_warning ("Could not delete file '%s'", target);
+ success = FALSE;
+ } else {
+ g_message ("Removing all media-art: deleted file '%s'", target);
+ }
+
+ g_free (target);
}
}
- g_list_foreach (to_remove, media_art_remove_foreach, &success);
- g_list_free (to_remove);
-
- g_hash_table_unref (table);
+ if (!success) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Could not remove one or more files from media art cache"));
+ }
g_dir_close (dir);
g_free (dirname);
return success;
}
+
+typedef struct {
+ gchar *artist;
+ gchar *album;
+} RemoveData;
+
+static RemoveData *
+remove_data_new (const gchar *artist,
+ const gchar *album)
+{
+ RemoveData *data;
+
+ data = g_slice_new0 (RemoveData);
+ data->artist = g_strdup (artist);
+ data->album = g_strdup (album);
+
+ return data;
+}
+
+static void
+remove_data_free (RemoveData *data)
+{
+ if (!data) {
+ return;
+ }
+
+ g_free (data->artist);
+ g_free (data->album);
+ g_slice_free (RemoveData, data);
+}
+
+static void
+remove_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ RemoveData *data = task_data;
+ GError *error = NULL;
+ gboolean success = FALSE;
+
+ if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ success = media_art_remove (data->artist,
+ data->album,
+ cancellable,
+ &error);
+ }
+
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, success);
+ }
+}
+
+/**
+ * media_art_remove_async:
+ * @artist: artist the media art belongs to
+ * @album: (allow-none): album the media art belongs or %NULL
+ * @source_object: (allow-none): the #GObject this task belongs to,
+ * can be %NULL.
+ * @io_priority: the [I/O priority][io-priority] of the request
+ * @cancellable: (allow-none): optional #GCancellable object, %NULL to
+ * ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Removes media art for given album/artist provided. Precisely the
+ * same operation as media_art_remove() is performing, but
+ * asynchronously.
+ *
+ * When all i/o for the operation is finished the @callback will be
+ * called.
+ *
+ * In case of a partial error the callback will be called with any
+ * succeeding items and no error, and on the next request the error
+ * will be reported. If a request is cancelled the callback will be
+ * called with %G_IO_ERROR_CANCELLED.
+ *
+ * During an async request no other sync and async calls are allowed,
+ * and will result in %G_IO_ERROR_PENDING errors.
+ *
+ * Any outstanding i/o request with higher priority (lower numerical
+ * value) will be executed before an outstanding request with lower
+ * priority. Default priority is %G_PRIORITY_DEFAULT.
+ *
+ * Since: 0.7.0
+ */
+void
+media_art_remove_async (const gchar *artist,
+ const gchar *album,
+ gint io_priority,
+ GObject *source_object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (source_object, cancellable, callback, user_data);
+ g_task_set_task_data (task, remove_data_new (artist, album), (GDestroyNotify) remove_data_free);
+ g_task_set_priority (task, io_priority);
+ g_task_run_in_thread (task, remove_thread);
+ g_object_unref (task);
+}
+
+/**
+ * media_art_remove_finish:
+ * @source_object: (allow-none): the #GObject this task belongs to,
+ * can be %NULL.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occurring, or %NULL
+ * to ignore.
+ *
+ * Finishes the asynchronous operation started with
+ * media_art_remove_async().
+ *
+ * Returns: %TRUE on success, otherwise %FALSE when @error will be set.
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+media_art_remove_finish (GObject *source_object,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, source_object), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}