diff options
-rw-r--r-- | libmediaart/extract.c | 895 | ||||
-rw-r--r-- | libmediaart/extract.h | 98 | ||||
-rw-r--r-- | tests/mediaarttest.c | 493 |
3 files changed, 1062 insertions, 424 deletions
diff --git a/libmediaart/extract.c b/libmediaart/extract.c index faaf994..a82b007 100644 --- a/libmediaart/extract.c +++ b/libmediaart/extract.c @@ -103,6 +103,21 @@ typedef enum { IMAGE_MATCH_TYPE_COUNT } ImageMatchType; +typedef struct { + MediaArtType type; + MediaArtProcessFlags flags; + + GFile *file; + gchar *uri; + + unsigned char *buffer; + size_t len; + gchar *mime; + + gchar *artist; + gchar *title; +} ProcessData; + static void media_art_queue_cb (GObject *source_object, GAsyncResult *res, gpointer user_data); @@ -304,63 +319,86 @@ file_get_checksum_if_exists (GChecksumType checksum_type, const gchar *path, gchar **md5, gboolean check_jpeg, - gboolean *is_jpeg) + gboolean *is_jpeg, + GError **error) { - GFile *file = g_file_new_for_path (path); + GFile *file; GFileInputStream *stream; GChecksum *checksum; - gboolean retval; + GError *local_error = NULL; + gssize rsize; + guchar buffer[1024]; + gboolean stop; + + file = g_file_new_for_path (path); + stream = g_file_read (file, NULL, &local_error); + + if (local_error) { + g_object_unref (file); + g_propagate_error (error, local_error); + return FALSE; + } + + if (!stream) { + g_set_error (error, + g_io_error_quark (), + G_IO_ERROR_FAILED, + "Could not calculate MD5 checksum for '%s', g_file_read() gave no error either?!", + path); + g_object_unref (file); + return FALSE; + } checksum = g_checksum_new (checksum_type); if (!checksum) { - g_debug ("Can't create checksum engine"); + g_set_error (error, + g_io_error_quark (), + G_IO_ERROR_FAILED, + "Could not calculate MD5 checksum for '%s', g_checksum_new() failed", + path); g_object_unref (file); + g_object_unref (stream); return FALSE; } - stream = g_file_read (file, NULL, NULL); - - if (stream) { - gssize rsize; - guchar buffer[1024]; - - /* File exists & readable always means true retval */ - retval = TRUE; - - if (check_jpeg) { - if (g_input_stream_read_all (G_INPUT_STREAM (stream), - buffer, - 3, - (gsize *) &rsize, - NULL, - NULL)) { - if (rsize >= 3 && - buffer[0] == 0xff && - buffer[1] == 0xd8 && - buffer[2] == 0xff) { - if (is_jpeg) { - *is_jpeg = TRUE; - } - - /* Add the read bytes to the checksum */ - g_checksum_update (checksum, buffer, rsize); - } else { - /* Larger than 3 bytes but incorrect jpeg header */ - if (is_jpeg) { - *is_jpeg = FALSE; - } - goto end; + /* File exists & readable always means true retval */ + if (check_jpeg) { + if (g_input_stream_read_all (G_INPUT_STREAM (stream), + buffer, + 3, + (gsize *) &rsize, + NULL, + NULL)) { + if (rsize >= 3 && + buffer[0] == 0xff && + buffer[1] == 0xd8 && + buffer[2] == 0xff) { + if (is_jpeg) { + *is_jpeg = TRUE; } + + /* Add the read bytes to the checksum */ + g_checksum_update (checksum, buffer, rsize); } else { - /* Smaller than 3 bytes, not a jpeg */ + /* Larger than 3 bytes but incorrect jpeg header */ if (is_jpeg) { *is_jpeg = FALSE; } - goto end; + + stop = TRUE; } + } else { + /* Smaller than 3 bytes, not a jpeg */ + if (is_jpeg) { + *is_jpeg = FALSE; + } + + stop = TRUE; } + } + if (!stop) { while ((rsize = g_input_stream_read (G_INPUT_STREAM (stream), buffer, 1024, @@ -372,22 +410,13 @@ file_get_checksum_if_exists (GChecksumType checksum_type, if (md5) { *md5 = g_strdup (g_checksum_get_string (checksum)); } - - } else { - g_debug ("%s isn't readable while calculating MD5 checksum", path); - /* File doesn't exist or isn't readable */ - retval = FALSE; - } - -end: - if (stream) { - g_object_unref (stream); } + g_object_unref (stream); g_checksum_free (checksum); g_object_unref (file); - return retval; + return TRUE; } static gboolean @@ -397,17 +426,24 @@ convert_from_other_format (const gchar *found, const gchar *artist, GError **error) { + GError *local_error = NULL; gboolean retval; gchar *sum1 = NULL; + gchar *sum2 = NULL; gchar *target_temp; target_temp = g_strdup_printf ("%s-tmp", target); - if (!media_art_file_to_jpeg (found, target_temp, error)) { + media_art_file_to_jpeg (found, target_temp, &local_error); + + if (local_error) { + g_propagate_error (error, local_error); + g_unlink (target_temp); g_free (target_temp); return FALSE; } + /* If artist doesn't exist, try to rename temp file to album path */ if (artist == NULL || g_strcmp0 (artist, " ") == 0) { retval = g_rename (target_temp, album_path) == 0; @@ -419,72 +455,68 @@ convert_from_other_format (const gchar *found, target_temp, album_path, g_strerror (errno)); + g_unlink (target_temp); } - g_debug ("rename(%s, %s) error: %s", + g_debug ("Renaming ('%s' --> '%s'), %s", target_temp, album_path, - g_strerror (errno)); - } else if (file_get_checksum_if_exists (G_CHECKSUM_MD5, - target_temp, - &sum1, - FALSE, - NULL)) { - gchar *sum2 = NULL; - - if (file_get_checksum_if_exists (G_CHECKSUM_MD5, - album_path, - &sum2, - FALSE, - NULL)) { - if (g_strcmp0 (sum1, sum2) == 0) { - - /* If album-space-md5.jpg is the same as found, - * make a symlink */ - retval = symlink (album_path, target) == 0; - - if (!retval) { - g_set_error (error, - media_art_error_quark (), - MEDIA_ART_ERROR_RENAME_FAILED, - "Could not rename '%s' to '%s': %s", - album_path, - target, - g_strerror (errno)); - } + !retval ? g_strerror (errno) : "no error given"); - g_debug ("symlink(%s, %s) error: %s", - album_path, - target, - g_strerror (errno)); + g_free (target_temp); - g_unlink (target_temp); - } else { + return retval; + } - /* If album-space-md5.jpg isn't the same as found, - * make a new album-md5-md5.jpg (found -> target) */ - retval = g_rename (target_temp, album_path) == 0; - - if (!retval) { - g_set_error (error, - media_art_error_quark (), - MEDIA_ART_ERROR_RENAME_FAILED, - "Could not rename '%s' to '%s': %s", - target_temp, - album_path, - g_strerror (errno)); - } + /* Checksum both temp file and album path and decide what to + * do base on what we find... + */ + file_get_checksum_if_exists (G_CHECKSUM_MD5, + target_temp, + &sum1, + FALSE, + NULL, + &local_error); + + if (local_error) { + g_propagate_error (error, local_error); + g_unlink (target_temp); + g_free (target_temp); + return FALSE; + } + + file_get_checksum_if_exists (G_CHECKSUM_MD5, + album_path, + &sum2, + FALSE, + NULL, + &local_error); - g_debug ("rename(%s, %s) error: %s", - target_temp, - album_path, - g_strerror (errno)); + if (!local_error) { + if (g_strcmp0 (sum1, sum2) == 0) { + /* If album-space-md5.jpg is the same as found, + * make a symlink */ + retval = symlink (album_path, target) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_RENAME_FAILED, + "Could not rename '%s' to '%s': %s", + album_path, + target, + g_strerror (errno)); } - g_free (sum2); + g_debug ("Creating symlink ('%s' --> '%s'), %s", + album_path, + target, + !retval ? g_strerror (errno) : "no error given"); + + g_unlink (target_temp); } else { - /* If there's not yet a album-space-md5.jpg, make one, - * and symlink album-md5-md5.jpg to it */ + /* If album-space-md5.jpg isn't the same as found, + * make a new album-md5-md5.jpg (found -> target) */ retval = g_rename (target_temp, album_path) == 0; if (!retval) { @@ -492,36 +524,56 @@ convert_from_other_format (const gchar *found, media_art_error_quark (), MEDIA_ART_ERROR_RENAME_FAILED, "Could not rename '%s' to '%s': %s", + target_temp, album_path, - target, g_strerror (errno)); - } else { - retval = symlink (album_path, target) == 0; - - if (!retval) { - g_set_error (error, - media_art_error_quark (), - MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not rename '%s' to '%s': %s", - album_path, - target, - g_strerror (errno)); - } - - g_debug ("symlink(%s,%s) error: %s", - album_path, - target, - g_strerror (errno)); } + + g_debug ("Renaming ('%s' --> '%s'), %s", + target_temp, + album_path, + !retval ? g_strerror (errno) : "no error given"); } - g_free (sum1); + g_free (sum2); } else { - g_debug ("Can't read %s while calculating checksum", target_temp); - /* Can't read the file that it was converted to, strange ... */ - g_unlink (target_temp); + g_clear_error (&local_error); + + /* If there's not yet a album-space-md5.jpg, make one, + * and symlink album-md5-md5.jpg to it */ + retval = g_rename (target_temp, album_path) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_RENAME_FAILED, + "Could not rename '%s' to '%s': %s", + album_path, + target, + g_strerror (errno)); + + g_unlink (target_temp); + } else { + retval = symlink (album_path, target) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_SYMLINK_FAILED, + "Could not rename '%s' to '%s': %s", + album_path, + target, + g_strerror (errno)); + } + + g_debug ("Creating symlink ('%s' --> '%s'), %s", + album_path, + target, + !retval ? g_strerror (errno) : "no error given"); + } } + g_free (sum1); g_free (target_temp); return retval; @@ -798,6 +850,7 @@ get_heuristic (MediaArtType type, if (g_str_has_suffix (art_file_path, "jpeg") || g_str_has_suffix (art_file_path, "jpg")) { + GError *local_error = NULL; gboolean is_jpeg = FALSE; gchar *sum1 = NULL; @@ -805,7 +858,6 @@ get_heuristic (MediaArtType type, (artist == NULL || g_strcmp0 (artist, " ") == 0)) { GFile *art_file; GFile *target_file; - GError *local_error = NULL; g_debug ("Album art (JPEG) found in same directory being used:'%s'", art_file_path); @@ -832,7 +884,8 @@ get_heuristic (MediaArtType type, art_file_path, &sum1, TRUE, - &is_jpeg)) { + &is_jpeg, + &local_error)) { /* Avoid duplicate artwork for each track in an album */ media_art_get_path (NULL, title_stripped, @@ -850,7 +903,8 @@ get_heuristic (MediaArtType type, album_art_file_path, &sum2, FALSE, - NULL)) { + NULL, + &local_error)) { if (g_strcmp0 (sum1, sum2) == 0) { /* If album-space-md5.jpg is the same as found, * make a symlink */ @@ -860,13 +914,13 @@ get_heuristic (MediaArtType type, g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not link '%s' to '%s': %s", + "Could not symlink '%s' to '%s', %s", album_art_file_path, target, g_strerror (errno)); } - g_debug ("symlink(%s, %s) error: %s", + g_debug ("symlink('%s' --> '%s'), %s", album_art_file_path, target, g_strerror (errno)); @@ -884,7 +938,11 @@ get_heuristic (MediaArtType type, NULL, NULL, NULL, - error); + &local_error); + + if (local_error) { + g_propagate_error (error, local_error); + } g_object_unref (art_file); g_object_unref (target_file); @@ -895,6 +953,8 @@ get_heuristic (MediaArtType type, GFile *art_file; GFile *album_art_file; + g_clear_error (&local_error); + /* If there's not yet a album-space-md5.jpg, make one, * and symlink album-md5-md5.jpg to it */ album_art_file = g_file_new_for_path (album_art_file_path); @@ -905,22 +965,24 @@ get_heuristic (MediaArtType type, NULL, NULL, NULL, - error); + &local_error); - if (retval) { + if (local_error) { + g_propagate_error (error, local_error); + } else { retval = symlink (album_art_file_path, target) == 0; if (!retval) { g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not link '%s' to '%s': %s", + "Could not symlink '%s' to '%s', %s", album_art_file_path, target, g_strerror (errno)); } - g_debug ("symlink(%s, %s) error: %s", + g_debug ("symlink('%s' --> '%s'), %s", album_art_file_path, target, g_strerror (errno)); } @@ -940,6 +1002,7 @@ get_heuristic (MediaArtType type, g_free (sum1); } else { /* Can't read contents of the cover.jpg file ... */ + g_propagate_error (error, local_error); retval = FALSE; } } else if (g_str_has_suffix (art_file_path, "png")) { @@ -1002,6 +1065,7 @@ media_art_set (const unsigned char *buffer, const gchar *title, GError **error) { + GError *local_error = NULL; gchar *local_path; gchar *album_path; gchar *md5_album = NULL; @@ -1048,10 +1112,19 @@ media_art_set (const unsigned char *buffer, * i) save buffer to jpeg only. */ if (type != MEDIA_ART_ALBUM || (artist == NULL || g_strcmp0 (artist, " ") == 0)) { - retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, error); - g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, local_path); + retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, &local_error); + + g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s', %s", + len, + local_path, + local_error ? local_error->message : "no error given"); g_free (local_path); + if (local_error) { + g_propagate_error (error, local_error); + return FALSE; + } + return retval; } @@ -1067,11 +1140,17 @@ media_art_set (const unsigned char *buffer, NULL); if (!g_file_test (album_path, G_FILE_TEST_EXISTS)) { - retval = TRUE; + media_art_buffer_to_jpeg (buffer, len, mime, album_path, &local_error); - if (media_art_buffer_to_jpeg (buffer, len, mime, album_path, error)) { - g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, album_path); + g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s', %s", + len, + local_path, + local_error ? local_error->message : "no error given"); + if (local_error) { + g_propagate_error (error, local_error); + retval = FALSE; + } else { /* If album-space-md5.jpg doesn't * exist, make one and make a symlink * to album-md5-md5.jpg @@ -1082,7 +1161,7 @@ media_art_set (const unsigned char *buffer, g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not link '%s' to '%s': %s", + "Could not symlink '%s' to '%s', %s", album_path, local_path, g_strerror (errno)); @@ -1100,16 +1179,21 @@ media_art_set (const unsigned char *buffer, return retval; } - if (!file_get_checksum_if_exists (G_CHECKSUM_MD5, - album_path, - &md5_album, - FALSE, - NULL)) { - g_debug ("No MD5 checksum found for album path:'%s'", album_path); + file_get_checksum_if_exists (G_CHECKSUM_MD5, + album_path, + &md5_album, + FALSE, + NULL, + &local_error); + + if (local_error) { + g_debug ("%s", local_error->message); + g_propagate_error (error, local_error); g_free (album_path); g_free (local_path); + /* FIXME: Is it right to return TRUE here ?*/ return TRUE; } @@ -1133,7 +1217,7 @@ media_art_set (const unsigned char *buffer, g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not link '%s' to '%s': %s", + "Could not symlink '%s' to '%s', %s", album_path, local_path, g_strerror (errno)); @@ -1147,8 +1231,17 @@ media_art_set (const unsigned char *buffer, /* If album-space-md5.jpg isn't the same as * buffer, make a new album-md5-md5.jpg */ - retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, error); - g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, local_path); + retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, &local_error); + + g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s', %s", + len, + local_path, + local_error ? local_error->message : "no error given"); + + if (local_error) { + g_propagate_error (error, local_error); + retval = FALSE; + } } g_free (md5_data); @@ -1166,10 +1259,18 @@ media_art_set (const unsigned char *buffer, * cache, unlink it... */ temp = g_strdup_printf ("%s-tmp", album_path); + media_art_buffer_to_jpeg (buffer, len, mime, temp, &local_error); - /* If buffer isn't a JPEG */ - if (!media_art_buffer_to_jpeg (buffer, len, mime, temp, error)) { - /* Can't read temp file ... */ + g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s', %s", + len, + local_path, + local_error ? local_error->message : "no error given"); + + if (local_error) { + g_propagate_error (error, local_error); + + /* Unlink in case there was some error and half the + * job was done. */ g_unlink (temp); g_free (temp); @@ -1180,11 +1281,14 @@ media_art_set (const unsigned char *buffer, return FALSE; } - if (file_get_checksum_if_exists (G_CHECKSUM_MD5, - temp, - &md5_tmp, - FALSE, - NULL)) { + file_get_checksum_if_exists (G_CHECKSUM_MD5, + temp, + &md5_tmp, + FALSE, + NULL, + &local_error); + + if (!local_error) { if (g_strcmp0 (md5_tmp, md5_album) == 0) { /* If album-space-md5.jpg is the same as * buffer, make a symlink to album-md5-md5.jpg @@ -1195,7 +1299,7 @@ media_art_set (const unsigned char *buffer, g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_SYMLINK_FAILED, - "Could not link '%s' to '%s': %s", + "Could not symlink '%s' to '%s', %s", album_path, local_path, g_strerror (errno)); @@ -1215,7 +1319,7 @@ media_art_set (const unsigned char *buffer, g_set_error (error, media_art_error_quark (), MEDIA_ART_ERROR_RENAME_FAILED, - "Could not rename '%s' to '%s': %s", + "Could not rename '%s' to '%s', %s", temp, local_path, g_strerror (errno)); @@ -1228,6 +1332,10 @@ media_art_set (const unsigned char *buffer, } g_free (md5_tmp); + } else { + g_debug ("%s", local_error->message); + g_propagate_error (error, local_error); + retval = FALSE; } /* Clean up */ @@ -1507,6 +1615,113 @@ get_heuristic_for_parent_path (GFile *file, return key; } +static ProcessData * +process_data_new (MediaArtType type, + MediaArtProcessFlags flags, + GFile *file, + const gchar *uri, + const unsigned char *buffer, + size_t len, + const gchar *mime, + const gchar *artist, + const gchar *title) +{ + ProcessData *data; + + data = g_slice_new0 (ProcessData); + data->type = type; + data->flags = flags; + + if (file) { + data->file = g_object_ref (file); + } + + data->uri = g_strdup (uri); + + data->buffer = g_memdup (buffer, data->len); + data->len = len; + data->mime = g_strdup (mime); + + data->artist = g_strdup (artist); + data->title = g_strdup (title); + + return data; +} + +static void +process_data_free (ProcessData *data) +{ + if (!data) { + return; + } + + if (data->file) { + g_object_unref (data->file); + } + + g_free (data->uri); + + g_free (data->buffer); + g_free (data->mime); + + g_free (data->artist); + g_free (data->title); + + g_slice_free (ProcessData, data); +} + +static void +process_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + MediaArtProcess *process = MEDIA_ART_PROCESS (source_object); + ProcessData *data = task_data; + GError *error = NULL; + gboolean success = FALSE; + + if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) { + if (data->file) { + success = media_art_process_file (process, + data->type, + data->flags, + data->file, + data->artist, + data->title, + cancellable, + &error); + } else if (data->uri) { + success = media_art_process_uri (process, + data->type, + data->flags, + data->uri, + data->artist, + data->title, + cancellable, + &error); + } else { + success = media_art_process_buffer (process, + data->type, + data->flags, + data->file, + data->buffer, + data->len, + data->mime, + data->artist, + data->title, + cancellable, + &error); + } + } + + if (error) { + g_task_return_error (task, error); + } else { + g_task_return_boolean (task, success); + } +} + /** * media_art_process_buffer: * @process: Media art process object @@ -1518,7 +1733,10 @@ get_heuristic_for_parent_path (GFile *file, * @mime: MIME type of @buffer, or %NULL * @artist: (allow-none): The artist name @file or %NULL * @title: (allow-none): The title for @file or %NULL - * @error: Pointer to potential GLib / MediaArt error, or %NULL + * @cancellable: (allow-none): optional #GCancellable object, %NULL to + * ignore + * @error: a #GError location to store the error occurring, or %NULL + * to ignore. * * Processes a memory buffer represented by @buffer and @len. If you * have extracted any embedded media art and passed this in as @@ -1544,6 +1762,7 @@ media_art_process_buffer (MediaArtProcess *process, const gchar *mime, const gchar *artist, const gchar *title, + GCancellable *cancellable, GError **error) { GFile *cache_art_file, *local_art_file; @@ -1591,6 +1810,11 @@ media_art_process_buffer (MediaArtProcess *process, cache_mtime = get_mtime (cache_art_file, &local_error); + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + g_free (uri); + return FALSE; + } + if (local_error && local_error->domain == g_io_error_quark () && local_error->code == G_IO_ERROR_NOT_FOUND) { @@ -1636,16 +1860,18 @@ media_art_process_buffer (MediaArtProcess *process, processed = TRUE; } - if (local_art_file && !g_file_query_exists (local_art_file, NULL)) { - /* We can't reuse art_exists here because the - * situation might have changed - */ - if (g_file_query_exists (cache_art_file, NULL)) { - gchar *local_art_uri; + if (!g_cancellable_set_error_if_cancelled (cancellable, error)) { + if (local_art_file && !g_file_query_exists (local_art_file, NULL)) { + /* We can't reuse art_exists here because the + * situation might have changed + */ + if (g_file_query_exists (cache_art_file, NULL)) { + gchar *local_art_uri; - local_art_uri = g_file_get_uri (local_art_file); - media_art_copy_to_local (process, cache_art_path, local_art_uri); - g_free (local_art_uri); + local_art_uri = g_file_get_uri (local_art_file); + media_art_copy_to_local (process, cache_art_path, local_art_uri); + g_free (local_art_uri); + } } } @@ -1660,10 +1886,102 @@ media_art_process_buffer (MediaArtProcess *process, g_free (cache_art_path); g_free (uri); + if (g_cancellable_is_cancelled (cancellable)) { + processed = FALSE; + } + return processed; } /** + * media_art_process_buffer_async: + * @process: Media art process object + * @type: The type of media + * @flags: The options given for how to process the media art + * @related_file: File related to the media art + * @buffer: (array length=len)(allow-none): a buffer containing @file + * data, or %NULL + * @len: length of @buffer, or 0 + * @mime: MIME type of @buffer, or %NULL + * @artist: (allow-none): The artist name @file or %NULL + * @title: (allow-none): The title for @file or %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 + * + * Processes media art. Precisely the same operation as + * media_art_process_buffer() 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. + * + * Dbufferng 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_process_buffer_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *related_file, + const guchar *buffer, + gsize len, + const gchar *mime, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (process, cancellable, callback, user_data); + g_task_set_task_data (task, process_data_new (type, flags, related_file, NULL, buffer, len, mime, artist, title), (GDestroyNotify) process_data_free); + g_task_set_priority (task, io_priority); + g_task_run_in_thread (task, process_thread); + g_object_unref (task); +} + +/** + * media_art_process_buffer_finish: + * @process: the #MediaArtProcess + * @result: a #GAsyncResult. + * @error: a #GError location to store the error occurring, or %NULL + * to ignore. + * + * Finishes the asynchronous operation started with + * media_art_process_file_async(). + * + * Returns: %TRUE on success, otherwise %FALSE when @error will be set. + * + * Since: 0.7.0 + **/ +gboolean +media_art_process_buffer_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, process), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); + +} + +/** * media_art_process_file: * @process: Media art process object * @type: The type of media @@ -1671,7 +1989,10 @@ media_art_process_buffer (MediaArtProcess *process, * @file: File to be processed * @artist: (allow-none): The artist name @file or %NULL * @title: (allow-none): The title for @file or %NULL - * @error: Pointer to potential GLib / MediaArt error, or %NULL + * @cancellable: (allow-none): optional #GCancellable object, %NULL to + * ignore + * @error: a #GError location to store the error occurring, or %NULL + * to ignore. * * Process @file and check if media art exists and if it is up to date * with @artist and @title provided. Either @artist OR @title can be @@ -1712,6 +2033,7 @@ media_art_process_file (MediaArtProcess *process, GFile *file, const gchar *artist, const gchar *title, + GCancellable *cancellable, GError **error) { MediaArtProcessPrivate *private; @@ -1747,6 +2069,11 @@ media_art_process_file (MediaArtProcess *process, return FALSE; } + if (g_cancellable_set_error_if_cancelled (cancellable, error)) { + g_free (uri); + return FALSE; + } + media_art_get_file (artist, title, media_art_type_name[type], @@ -1766,32 +2093,37 @@ media_art_process_file (MediaArtProcess *process, key = get_heuristic_for_parent_path (file, type, artist, title); if (!g_hash_table_lookup (private->media_art_cache, key)) { - gchar *local_art_uri; - - local_art_uri = g_file_get_uri (local_art_file); - - if (!get_heuristic (type, uri, local_art_uri, artist, title, error)) { - /* If the heuristic failed, we - * request the download the - * media-art to the media-art - * downloaders - */ - media_art_request_download (process, - type, - artist, - title, - local_art_uri, - cache_art_path); - - /* FIXME: Should return TRUE or FALSE? */ - } + /* Check we're not cancelled before + * potentially trying a download operation. + */ + if (!g_cancellable_set_error_if_cancelled (cancellable, error)) { + gchar *local_art_uri; + + local_art_uri = g_file_get_uri (local_art_file); + + if (!get_heuristic (type, uri, local_art_uri, artist, title, error)) { + /* If the heuristic failed, we + * request the download the + * media-art to the media-art + * downloaders + */ + media_art_request_download (process, + type, + artist, + title, + local_art_uri, + cache_art_path); + + /* FIXME: Should return TRUE or FALSE? */ + } - set_mtime (cache_art_path, mtime); + set_mtime (cache_art_path, mtime); - g_hash_table_insert (private->media_art_cache, - key, - GINT_TO_POINTER(TRUE)); - g_free (local_art_uri); + g_hash_table_insert (private->media_art_cache, + key, + GINT_TO_POINTER(TRUE)); + g_free (local_art_uri); + } } else { g_free (key); } @@ -1812,7 +2144,89 @@ media_art_process_file (MediaArtProcess *process, g_free (cache_art_path); g_free (uri); - return TRUE; + return !g_cancellable_is_cancelled (cancellable); +} + + +/** + * media_art_process_file_async: + * @process: Media art process object + * @type: The type of media + * @flags: The options given for how to process the media art + * @file: File to be processed + * @artist: (allow-none): The artist name @file or %NULL + * @title: (allow-none): The title for @file or %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 + * + * Processes media art. Precisely the same operation as + * media_art_process_file() 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_process_file_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *file, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (process, cancellable, callback, user_data); + g_task_set_task_data (task, process_data_new (type, flags, file, NULL, NULL, 0, NULL, artist, title), (GDestroyNotify) process_data_free); + g_task_set_priority (task, io_priority); + g_task_run_in_thread (task, process_thread); + g_object_unref (task); +} + +/** + * media_art_process_file_finish: + * @process: the #MediaArtProcess + * @result: a #GAsyncResult. + * @error: a #GError location to store the error occurring, or %NULL + * to ignore. + * + * Finishes the asynchronous operation started with + * media_art_process_file_async(). + * + * Returns: %TRUE on success, otherwise %FALSE when @error will be set. + * + * Since: 0.7.0 + **/ +gboolean +media_art_process_file_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, process), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); + } /** @@ -1823,6 +2237,8 @@ media_art_process_file (MediaArtProcess *process, * @uri: URI of the media file that contained the data * @artist: (allow-none): The artist name @uri or %NULL * @title: (allow-none): The title for @uri or %NULL + * @cancellable: (allow-none): optional #GCancellable object, %NULL to + * ignore * @error: Pointer to potential GLib / MediaArt error, or %NULL * * This function calls media_art_process_file(), but takes the @uri as @@ -1840,6 +2256,7 @@ media_art_process_uri (MediaArtProcess *process, const gchar *uri, const gchar *artist, const gchar *title, + GCancellable *cancellable, GError **error) { GFile *file; @@ -1858,9 +2275,91 @@ media_art_process_uri (MediaArtProcess *process, file, artist, title, + cancellable, error); g_object_unref (file); return result; } + +/** + * media_art_process_uri_async: + * @process: Media art process object + * @type: The type of media + * @flags: The options given for how to process the media art + * @uri: A string representing a URI to be processed + * @artist: (allow-none): The artist name @file or %NULL + * @title: (allow-none): The title for @file or %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 + * + * Processes media art. Precisely the same operation as + * media_art_process_uri() 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_process_uri_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + const gchar *uri, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (process, cancellable, callback, user_data); + g_task_set_task_data (task, process_data_new (type, flags, NULL, uri, NULL, 0, NULL, artist, title), (GDestroyNotify) process_data_free); + g_task_set_priority (task, io_priority); + g_task_run_in_thread (task, process_thread); + g_object_unref (task); +} + +/** + * media_art_process_uri_finish: + * @process: the #MediaArtProcess + * @result: a #GAsyncResult. + * @error: a #GError location to store the error occurring, or %NULL + * to ignore. + * + * Finishes the asynchronous operation started with + * media_art_process_file_async(). + * + * Returns: %TRUE on success, otherwise %FALSE when @error will be set. + * + * Since: 0.7.0 + **/ +gboolean +media_art_process_uri_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, process), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); + +} diff --git a/libmediaart/extract.h b/libmediaart/extract.h index 2356790..c01d2cb 100644 --- a/libmediaart/extract.h +++ b/libmediaart/extract.h @@ -129,32 +129,78 @@ struct _MediaArtProcessClass { }; -GType media_art_process_get_type (void) G_GNUC_CONST; -MediaArtProcess *media_art_process_new (GError **error); -gboolean media_art_process_uri (MediaArtProcess *process, - MediaArtType type, - MediaArtProcessFlags flags, - const gchar *uri, - const gchar *artist, - const gchar *title, - GError **error); -gboolean media_art_process_file (MediaArtProcess *process, - MediaArtType type, - MediaArtProcessFlags flags, - GFile *file, - const gchar *artist, - const gchar *title, - GError **error); -gboolean media_art_process_buffer (MediaArtProcess *process, - MediaArtType type, - MediaArtProcessFlags flags, - GFile *related_file, - const guchar *buffer, - gsize len, - const gchar *mime, - const gchar *artist, - const gchar *title, - GError **error); +GType media_art_process_get_type (void) G_GNUC_CONST; + +MediaArtProcess *media_art_process_new (GError **error); +gboolean media_art_process_uri (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + const gchar *uri, + const gchar *artist, + const gchar *title, + GCancellable *cancellable, + GError **error); +void media_art_process_uri_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + const gchar *uri, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean media_art_process_uri_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error); +gboolean media_art_process_file (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *file, + const gchar *artist, + const gchar *title, + GCancellable *cancellable, + GError **error); +void media_art_process_file_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *file, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean media_art_process_file_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error); +gboolean media_art_process_buffer (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *related_file, + const guchar *buffer, + gsize len, + const gchar *mime, + const gchar *artist, + const gchar *title, + GCancellable *cancellable, + GError **error); +void media_art_process_buffer_async (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *related_file, + const guchar *buffer, + gsize len, + const gchar *mime, + const gchar *artist, + const gchar *title, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean media_art_process_buffer_finish (MediaArtProcess *process, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/tests/mediaarttest.c b/tests/mediaarttest.c index 22694b6..f93845c 100644 --- a/tests/mediaarttest.c +++ b/tests/mediaarttest.c @@ -36,23 +36,23 @@ typedef struct { static TestInfo strip_test_cases [] = { { "nothing-to-strip", "nothing to strip here", NULL, "nothing to strip here" }, - { "case-strip", "Upper Case gOEs dOwN", NULL, "upper case goes down" }, + { "case-strip", "Upper Case gOEs dOwN", NULL, "upper case goes down" }, { "single-char", "o", NULL, "o" }, - { "single-char-case", "A", NULL, "a" }, - { "remove-parenthesis-round", "cool album (CD1)", NULL, "cool album" }, + { "single-char-case", "A", NULL, "a" }, + { "remove-parenthesis-round", "cool album (CD1)", NULL, "cool album" }, { "remove-parenthesis-square", "cool album [CD1]", NULL, "cool album" }, - { "remove-parenthesis-squirly", "cool album {CD1}", NULL, "cool album" }, - { "remove-parenthesis-gt-lt", "cool album <CD1>", NULL, "cool album" }, - { "whitespace", " ", NULL, "" }, - { "whitespace-with-content", " a ", NULL, "a" }, - { "messy-title", "messy #title & stuff?", NULL, "messy title stuff" }, + { "remove-parenthesis-squirly", "cool album {CD1}", NULL, "cool album" }, + { "remove-parenthesis-gt-lt", "cool album <CD1>", NULL, "cool album" }, + { "whitespace", " ", NULL, "" }, + { "whitespace-with-content", " a ", NULL, "a" }, + { "messy-title", "messy #title & stuff?", NULL, "messy title stuff" }, { "unbalanced-brackets-square-start", "Unbalanced [brackets", NULL, "unbalanced brackets" }, - { "unbalanced-brackets-round-start", "Unbalanced (brackets", NULL, "unbalanced brackets" }, - { "unbalanced-brackets-gt-lt-start", "Unbalanced <brackets", NULL, "unbalanced brackets" }, - { "unbalanced-brackets-round-end", "Unbalanced brackets)", NULL, "unbalanced brackets" }, - { "unbalanced-brackets-square-end", "Unbalanced brackets]", NULL, "unbalanced brackets" }, - { "unbalanced-brackets-gt-lt-end", "Unbalanced brackets>", NULL, "unbalanced brackets" }, - { "messy-title-punctuation", "Live at *WEMBLEY* dude!", NULL, "live at wembley dude" }, + { "unbalanced-brackets-round-start", "Unbalanced (brackets", NULL, "unbalanced brackets" }, + { "unbalanced-brackets-gt-lt-start", "Unbalanced <brackets", NULL, "unbalanced brackets" }, + { "unbalanced-brackets-round-end", "Unbalanced brackets)", NULL, "unbalanced brackets" }, + { "unbalanced-brackets-square-end", "Unbalanced brackets]", NULL, "unbalanced brackets" }, + { "unbalanced-brackets-gt-lt-end", "Unbalanced brackets>", NULL, "unbalanced brackets" }, + { "messy-title-punctuation", "Live at *WEMBLEY* dude!", NULL, "live at wembley dude" }, { "crap-brackets-everywhere", "met[xX[x]alli]ca", NULL, "metallica" }, { NULL, NULL, NULL, NULL } }; @@ -60,20 +60,20 @@ static TestInfo strip_test_cases [] = { static TestInfo location_test_cases [] = { { "normal-case", "Beatles", "Sgt. Pepper", - "album-2a9ea35253dbec60e76166ec8420fbda-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, + "album-2a9ea35253dbec60e76166ec8420fbda-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, { "empty-artist", "", "sgt. pepper", - "album-d41d8cd98f00b204e9800998ecf8427e-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, + "album-d41d8cd98f00b204e9800998ecf8427e-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, { "whitespace-artist", " ", "sgt. pepper", - "album-d41d8cd98f00b204e9800998ecf8427e-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, + "album-d41d8cd98f00b204e9800998ecf8427e-cfba4326a32b44b8760b3a2fc827a634.jpeg" }, { "null-artist", NULL, "sgt. pepper", - "album-cfba4326a32b44b8760b3a2fc827a634-7215ee9c7d9dc229d2921a40e899ec5f.jpeg" }, + "album-cfba4326a32b44b8760b3a2fc827a634-7215ee9c7d9dc229d2921a40e899ec5f.jpeg" }, { "null-title", "Beatles", NULL, - "album-2a9ea35253dbec60e76166ec8420fbda-7215ee9c7d9dc229d2921a40e899ec5f.jpeg" }, - { NULL, NULL, NULL, NULL } + "album-2a9ea35253dbec60e76166ec8420fbda-7215ee9c7d9dc229d2921a40e899ec5f.jpeg" }, + { NULL, NULL, NULL, NULL } }; static void @@ -93,29 +93,14 @@ teardown (TestInfo *info, } static void -test_mediaart_new (TestInfo *test_info, - gconstpointer context) -{ - MediaArtProcess *process; - GError *error = NULL; - - /* Test: creation of object */ - process = media_art_process_new (&error); - g_assert_no_error (error); - g_assert (process != NULL); - - g_object_unref (process); -} - -static void test_mediaart_stripping (TestInfo *test_info, gconstpointer context) { - gchar *result; + gchar *result; - result = media_art_strip_invalid_entities (test_info->input1); - g_assert_cmpstr (result, ==, test_info->expected); - g_free (result); + result = media_art_strip_invalid_entities (test_info->input1); + g_assert_cmpstr (result, ==, test_info->expected); + g_free (result); } static void @@ -132,9 +117,9 @@ test_mediaart_stripping_failures (void) /* a. Return NULL for NULL (subprocess) * b. Return NULL for "" */ - stripped = media_art_strip_invalid_entities (""); - g_assert (stripped); - g_assert_cmpstr (stripped, ==, ""); + stripped = media_art_strip_invalid_entities (""); + g_assert (stripped); + g_assert_cmpstr (stripped, ==, ""); g_test_trap_subprocess ("/mediaart/stripping_failures/subprocess", 0, 0); g_test_trap_assert_failed (); @@ -146,75 +131,151 @@ static void test_mediaart_location (TestInfo *test_info, gconstpointer context) { - gchar *path = NULL, *local_uri = NULL; - gchar *expected; - - media_art_get_path (test_info->input1, - test_info->input2, - "album", - "file:///home/test/a.mp3", - &path, - &local_uri); - expected = g_build_path (G_DIR_SEPARATOR_S, - g_get_user_cache_dir (), - "media-art", - test_info->expected, - NULL); - g_assert_cmpstr (path, ==, expected); - - g_free (expected); - g_free (path); - g_free (local_uri); + gchar *path = NULL, *local_uri = NULL; + gchar *expected; + + media_art_get_path (test_info->input1, + test_info->input2, + "album", + "file:///home/test/a.mp3", + &path, + &local_uri); + expected = g_build_path (G_DIR_SEPARATOR_S, + g_get_user_cache_dir (), + "media-art", + test_info->expected, + NULL); + g_assert_cmpstr (path, ==, expected); + + g_free (expected); + g_free (path); + g_free (local_uri); } static void test_mediaart_location_null (void) { - gchar *path = NULL, *local_uri = NULL; + gchar *path = NULL, *local_uri = NULL; - /* NULL parameters */ - media_art_get_path (NULL, "some-title", "album", "file:///a/b/c.mp3", &path, &local_uri); - g_assert (path != NULL); - g_assert (local_uri != NULL); + /* NULL parameters */ + media_art_get_path (NULL, "some-title", "album", "file:///a/b/c.mp3", &path, &local_uri); + g_assert (path != NULL); + g_assert (local_uri != NULL); - media_art_get_path ("some-artist", NULL, "album", "file:///a/b/c.mp3", &path, &local_uri); - g_assert (path != NULL); - g_assert (local_uri != NULL); + media_art_get_path ("some-artist", NULL, "album", "file:///a/b/c.mp3", &path, &local_uri); + g_assert (path != NULL); + g_assert (local_uri != NULL); } static void test_mediaart_location_path (void) { - gchar *path = NULL, *local_uri = NULL; - gchar *expected; - - /* Use path instead of URI */ - media_art_get_path (location_test_cases[0].input1, - location_test_cases[0].input2, - "album", - "/home/test/a.mp3", - &path, - &local_uri); - expected = g_build_path (G_DIR_SEPARATOR_S, - g_get_user_cache_dir (), - "media-art", - location_test_cases[0].expected, - NULL); - g_assert_cmpstr (path, ==, expected); - - g_free (expected); - g_free (path); - g_free (local_uri); + gchar *path = NULL, *local_uri = NULL; + gchar *expected; + + /* Use path instead of URI */ + media_art_get_path (location_test_cases[0].input1, + location_test_cases[0].input2, + "album", + "/home/test/a.mp3", + &path, + &local_uri); + expected = g_build_path (G_DIR_SEPARATOR_S, + g_get_user_cache_dir (), + "media-art", + location_test_cases[0].expected, + NULL); + g_assert_cmpstr (path, ==, expected); + + g_free (expected); + g_free (path); + g_free (local_uri); +} + +static void +test_mediaart_process_new (void) +{ + MediaArtProcess *process; + GError *error = NULL; + gchar *dir; + + dir = g_build_filename (g_get_user_cache_dir (), "media-art", NULL); + g_assert_false (g_file_test (dir, G_FILE_TEST_EXISTS)); + + /* Creates media-art cache dir if it doesn't exist ... */ + process = media_art_process_new (&error); + g_assert_no_error (error); + + g_assert_true (g_file_test (dir, G_FILE_TEST_EXISTS)); + + g_free (dir); + + g_object_unref (process); +} + +static void +test_mediaart_remove_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + GMainLoop *ml = user_data; + gboolean success; + + success = media_art_remove_finish (source_object, result, &error); + g_assert_no_error (error); + g_assert_true (success); + + g_main_loop_quit (ml); +} + +static void +test_mediaart_remove (const gchar *artist, + const gchar *title, + gpointer user_data) +{ + GCancellable *cancellable; + + cancellable = g_cancellable_new (); + + /* Remove album art */ + media_art_remove_async (artist, + title, + G_PRIORITY_DEFAULT, + NULL, + cancellable, + test_mediaart_remove_cb, + user_data); + + g_object_unref (cancellable); +} + +static void +test_mediaart_process_file_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + MediaArtProcess *process = MEDIA_ART_PROCESS (source_object); + GError *error = NULL; + GMainLoop *ml = user_data; + gboolean success; + + success = media_art_process_file_finish (process, result, &error); + g_assert_no_error (error); + g_assert_true (success); + + test_mediaart_remove ("King Kilo", "Radium", ml); } static void -test_mediaart_embedded_mp3 (void) +test_mediaart_process_file (void) { MediaArtProcess *process; + GMainLoop *ml; + GCancellable *cancellable; GError *error = NULL; GFile *file = NULL; gchar *path; - gboolean retval; path = g_build_filename (G_DIR_SEPARATOR_S, TOP_SRCDIR, "tests", "543249_King-Kilo---Radium.mp3", NULL); file = g_file_new_for_path (path); @@ -223,135 +284,166 @@ test_mediaart_embedded_mp3 (void) process = media_art_process_new (&error); g_assert_no_error (error); - retval = media_art_process_file (process, - MEDIA_ART_ALBUM, - MEDIA_ART_PROCESS_FLAGS_FORCE, - file, - "King Kilo", /* artist */ - "Radium", /* title */ - &error); + ml = g_main_loop_new (NULL, FALSE); + cancellable = g_cancellable_new (); - g_assert_no_error (error); - g_assert_true (retval); + media_art_process_file_async (process, + MEDIA_ART_ALBUM, + MEDIA_ART_PROCESS_FLAGS_FORCE, + file, + "King Kilo", /* artist */ + "Radium", /* title */ + G_PRIORITY_DEFAULT, + cancellable, + test_mediaart_process_file_cb, + ml); - g_object_unref (file); + g_main_loop_run (ml); + g_main_loop_unref (ml); + g_object_unref (cancellable); g_object_unref (process); } static void -test_mediaart_remove_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) +test_mediaart_process_buffer_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { GError *error = NULL; - GFile *file = user_data; + GFile *file; + gchar *path; + gchar *expected; + gchar *out_path = NULL; + gchar *out_uri = NULL; gboolean success; - success = media_art_remove_finish (source_object, result, &error); - g_assert_no_error (error); - g_assert_true (success); + success = media_art_process_buffer_finish (MEDIA_ART_PROCESS (source_object), result, &error); + g_assert_no_error (error); + g_assert_true (success); - success = media_art_remove ("Lanedo", NULL, NULL, &error); - g_assert_no_error (error); - g_assert_true (success); + /* Check cache exists */ + path = g_build_filename (G_DIR_SEPARATOR_S, TOP_SRCDIR, "tests", "cover.png", NULL); + file = g_file_new_for_path (path); - g_object_unref (file); + media_art_get_path ("Lanedo", /* artist / title */ + NULL, /* album */ + NULL, /* prefix */ + path, + &out_path, + &out_uri); + g_free (path); + g_object_unref (file); + + expected = g_build_path (G_DIR_SEPARATOR_S, + g_get_user_cache_dir (), + "media-art", + "album-be60c84852d9762b0a896ba9ba24245e-7215ee9c7d9dc229d2921a40e899ec5f.jpeg", + NULL); + g_assert_cmpstr (out_path, ==, expected); + /* FIXME: Why is out_uri NULL? */ + /* FIXME: Why does this next test fail - i.e. file does not + * exist if we've processed it? + */ + g_assert (g_file_test (out_path, G_FILE_TEST_EXISTS) == TRUE); + + test_mediaart_remove ("Lanedo", NULL, user_data); + + g_free (out_path); + g_free (out_uri); + g_free (expected); } static void test_mediaart_process_buffer (void) { MediaArtProcess *process; - GCancellable *cancellable; + GMainLoop *ml; + GCancellable *cancellable; + GFile *file; GError *error = NULL; - GFile *file = NULL; - gchar *dir; gchar *path; gchar *out_path = NULL; gchar *out_uri = NULL; - gchar *expected; - gboolean retval; + unsigned char *buffer = NULL; + size_t length = 0; + const gchar *mime; + + cancellable = g_cancellable_new (); path = g_build_filename (G_DIR_SEPARATOR_S, TOP_SRCDIR, "tests", "cover.png", NULL); - file = g_file_new_for_path (path); /* Check data is not cached currently */ media_art_get_path ("Lanedo", /* artist / title */ NULL, /* album */ NULL, /* prefix */ - path, - &out_path, - &out_uri); + path, + &out_path, + &out_uri); g_assert_false (g_file_test (out_path, G_FILE_TEST_EXISTS)); g_free (out_path); g_free (out_uri); - /* Creates media-art cache dir if it doesn't exist ... */ process = media_art_process_new (&error); g_assert_no_error (error); + g_assert_nonnull (process); - dir = g_build_filename (g_get_user_cache_dir (), "media-art", NULL); - g_assert_true (g_file_test (dir, G_FILE_TEST_EXISTS)); - g_free (dir); + ml = g_main_loop_new (NULL, FALSE); /* Process data */ - retval = media_art_process_file (process, - MEDIA_ART_ALBUM, - MEDIA_ART_PROCESS_FLAGS_NONE, - file, - NULL, /* album */ - "Lanedo", /* title */ - &error); + mime = "image/png"; + g_file_get_contents (path, (gchar**) &buffer, &length, &error); g_assert_no_error (error); - g_assert_true (retval); - /* Check cache exists */ - media_art_get_path ("Lanedo", /* artist / title */ - NULL, /* album */ - NULL, /* prefix */ - path, - &out_path, - &out_uri); - - expected = g_build_path (G_DIR_SEPARATOR_S, - g_get_user_cache_dir (), - "media-art", - "album-be60c84852d9762b0a896ba9ba24245e-7215ee9c7d9dc229d2921a40e899ec5f.jpeg", - NULL); - g_assert_cmpstr (out_path, ==, expected); - /* FIXME: Why is out_uri NULL? */ - /* FIXME: Why does this next test fail - i.e. file does not - * exist if we've processed it? - */ - g_assert (g_file_test (out_path, G_FILE_TEST_EXISTS) == TRUE); - - g_free (out_path); - g_free (out_uri); - g_free (expected); - - /* Remove album art */ - cancellable = g_cancellable_new (); - media_art_remove_async ("Lanedo", - "", - G_PRIORITY_DEFAULT, - G_OBJECT (process), - cancellable, - test_mediaart_remove_cb, - file); - - g_object_unref (cancellable); - g_free (path); + file = g_file_new_for_path (path); + g_free (path); + + media_art_process_buffer_async (process, + MEDIA_ART_ALBUM, + MEDIA_ART_PROCESS_FLAGS_NONE, + file, + buffer, + length, + mime, + NULL, /* album */ + "Lanedo", /* title */ + G_PRIORITY_DEFAULT, + cancellable, + test_mediaart_process_buffer_cb, + ml); + + g_main_loop_run (ml); + g_main_loop_unref (ml); + + g_object_unref (file); + g_object_unref (cancellable); g_object_unref (process); } static void +test_mediaart_process_uri_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + gboolean success; + + success = media_art_process_uri_finish (MEDIA_ART_PROCESS (source_object), result, &error); + g_assert_false (success); + g_assert_error (error, g_io_error_quark(), G_IO_ERROR_NOT_FOUND); + g_clear_error (&error); +} + +static void test_mediaart_process_failures (void) { MediaArtProcess *process; GError *error = NULL; + GCancellable *cancellable; + + cancellable = g_cancellable_new (); - g_test_trap_subprocess ("/mediaart/process_failures/subprocess", 0, 0 /*G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR*/); + g_test_trap_subprocess ("/mediaart/process/failures/subprocess", 0, 0 /*G_TEST_SUBPROCESS_INHERIT_STDOUT | G_TEST_SUBPROCESS_INHERIT_STDERR*/); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*assertion 'uri != NULL' failed*"); @@ -359,16 +451,16 @@ test_mediaart_process_failures (void) g_assert_no_error (error); /* Test: invalid file */ - g_assert (!media_art_process_uri (process, - MEDIA_ART_ALBUM, - MEDIA_ART_PROCESS_FLAGS_NONE, - "file:///invalid/path.png", - "Foo", /* album */ - "Bar", /* title */ - &error)); - - g_assert_error (error, g_io_error_quark(), G_IO_ERROR_NOT_FOUND); - g_clear_error (&error); + media_art_process_uri_async (process, + MEDIA_ART_ALBUM, + MEDIA_ART_PROCESS_FLAGS_NONE, + "file:///invalid/path.png", + "Foo", /* album */ + "Bar", /* title */ + G_PRIORITY_DEFAULT, + cancellable, + test_mediaart_process_uri_cb, + NULL); /* Test: Invalid mime type */ /* g_assert (!media_art_process_uri (process, */ @@ -379,6 +471,7 @@ test_mediaart_process_failures (void) /* MEDIA_ART_ALBUM, */ /* "Foo", /\* album *\/ */ /* "Bar", /\* title *\/ */ + /* NULL, */ /* &error)); */ /* g_message ("code:%d, domain:%d, error:'%s'\n", error->code, error->domain, error->message); */ @@ -401,6 +494,7 @@ test_mediaart_process_failures_subprocess (void) NULL, "Foo", /* album */ "Bar", /* title */ + NULL, &error)); g_assert_no_error (error); @@ -412,18 +506,16 @@ main (int argc, char **argv) { const gchar *cache_home_originally; const gchar *test_dir; - gchar *dir; + gchar *dir; gint success; gint i; - g_test_init (&argc, &argv, NULL); + g_test_init (&argc, &argv, NULL); test_dir = g_test_get_dir (G_TEST_BUILT); cache_home_originally = g_getenv ("XDG_CACHE_HOME"); g_setenv ("XDG_CACHE_HOME", test_dir, TRUE); - g_test_add ("/mediaart/new", TestInfo, NULL, setup, test_mediaart_new, teardown); - for (i = 0; strip_test_cases[i].test_name; i++) { gchar *testpath; @@ -432,8 +524,8 @@ main (int argc, char **argv) g_free (testpath); } - g_test_add_func ("/mediaart/stripping_failures", test_mediaart_stripping_failures); - g_test_add_func ("/mediaart/stripping_failures/subprocess", test_mediaart_stripping_failures_subprocess); + g_test_add_func ("/mediaart/stripping_failures", test_mediaart_stripping_failures); + g_test_add_func ("/mediaart/stripping_failures/subprocess", test_mediaart_stripping_failures_subprocess); for (i = 0; location_test_cases[i].test_name; i++) { gchar *testpath; @@ -443,25 +535,26 @@ main (int argc, char **argv) g_free (testpath); } - g_test_add_func ("/mediaart/location_null", test_mediaart_location_null); - g_test_add_func ("/mediaart/location_path", test_mediaart_location_path); - g_test_add_func ("/mediaart/embedded_mp3", test_mediaart_embedded_mp3); - g_test_add_func ("/mediaart/process_buffer", test_mediaart_process_buffer); - g_test_add_func ("/mediaart/process_failures", test_mediaart_process_failures); - g_test_add_func ("/mediaart/process_failures/subprocess", test_mediaart_process_failures_subprocess); + g_test_add_func ("/mediaart/location_null", test_mediaart_location_null); + g_test_add_func ("/mediaart/location_path", test_mediaart_location_path); + g_test_add_func ("/mediaart/process/new", test_mediaart_process_new); + g_test_add_func ("/mediaart/process/file", test_mediaart_process_file); + g_test_add_func ("/mediaart/process/buffer", test_mediaart_process_buffer); + g_test_add_func ("/mediaart/process/failures", test_mediaart_process_failures); + g_test_add_func ("/mediaart/process/failures/subprocess", test_mediaart_process_failures_subprocess); - success = g_test_run (); + success = g_test_run (); - /* Clean up */ + /* Clean up */ dir = g_build_filename (g_get_user_cache_dir (), "media-art", NULL); g_rmdir (dir); g_free (dir); - if (cache_home_originally) { - g_setenv ("XDG_CACHE_HOME", cache_home_originally, TRUE); - } else { - g_unsetenv ("XDG_CACHE_HOME"); - } + if (cache_home_originally) { + g_setenv ("XDG_CACHE_HOME", cache_home_originally, TRUE); + } else { + g_unsetenv ("XDG_CACHE_HOME"); + } - return success; + return success; } |