diff options
author | Martyn Russell <martyn@lanedo.com> | 2014-07-28 09:25:22 +0100 |
---|---|---|
committer | Martyn Russell <martyn@lanedo.com> | 2014-07-28 09:25:22 +0100 |
commit | f868869ff93c56b4d5df0bcd00393adcb03af7a0 (patch) | |
tree | 8b503c859accd2e85f08374be51b7676041198f2 | |
parent | f7317f8fdc21e357393e355e937d98a1b1a769c1 (diff) | |
parent | 23f3c73c3c3153b670c36b4f74c2e57665f7f075 (diff) | |
download | libmediaart-f868869ff93c56b4d5df0bcd00393adcb03af7a0.tar.gz |
Merge branch 'api-cleanup'
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | docs/reference/libmediaart/Makefile.am | 9 | ||||
-rw-r--r-- | docs/reference/libmediaart/libmediaart-docs.sgml | 1 | ||||
-rw-r--r-- | docs/reference/libmediaart/libmediaart-sections.txt | 33 | ||||
-rw-r--r-- | libmediaart/cache.c | 43 | ||||
-rw-r--r-- | libmediaart/extract.c | 1200 | ||||
-rw-r--r-- | libmediaart/extract.h | 124 | ||||
-rw-r--r-- | libmediaart/extractdummy.c | 80 | ||||
-rw-r--r-- | libmediaart/extractgeneric.h | 17 | ||||
-rw-r--r-- | libmediaart/extractpixbuf.c | 75 | ||||
-rw-r--r-- | libmediaart/extractqt.cpp | 23 | ||||
-rw-r--r-- | libmediaart/storage.c | 22 | ||||
-rw-r--r-- | m4/.gitignore | 1 | ||||
-rw-r--r-- | m4/attributes.m4 | 288 | ||||
-rw-r--r-- | m4/local.m4 | 258 | ||||
-rw-r--r-- | tests/LanedoIconHKS43-64².png | bin | 1560 -> 0 bytes | |||
-rw-r--r-- | tests/mediaarttest.c | 157 |
17 files changed, 1734 insertions, 602 deletions
diff --git a/configure.ac b/configure.ac index 95a3b73..a0f7fb3 100644 --- a/configure.ac +++ b/configure.ac @@ -96,6 +96,8 @@ AC_SUBST(LT_REVISION) AC_SUBST(LT_AGE) AC_SUBST(LT_CURRENT_MINUS_AGE) +IDT_COMPILE_WARNINGS + # Checks for programs. AC_PROG_CXX AC_PROG_AWK @@ -151,6 +153,9 @@ PKG_CHECK_MODULES(LIBMEDIAART, [$LIBMEDIAART_REQUIRED]) GLIB_GENMARSHAL=`$PKG_CONFIG glib-2.0 --variable=glib_genmarshal` AC_SUBST(GLIB_GENMARSHAL) +GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`" +AC_SUBST(GLIB_PREFIX) + #################################################################### # General CFLAGS/LIBS #################################################################### diff --git a/docs/reference/libmediaart/Makefile.am b/docs/reference/libmediaart/Makefile.am index 60ab37f..6424e10 100644 --- a/docs/reference/libmediaart/Makefile.am +++ b/docs/reference/libmediaart/Makefile.am @@ -15,14 +15,14 @@ SCAN_OPTIONS= # SCANGOBJ_OPTIONS=--type-init-func="gtk_type_init(0)" # The directory containing the source code. Relative to $(srcdir) -DOC_SOURCE_DIR=../../../libmediaart +DOC_SOURCE_DIR=$(top_srcdir)/libmediaart # Used for dependencies HFILE_GLOB=$(top_srcdir)/libmediaart/*.h CFILE_GLOB=$(top_srcdir)/libmediaart/*.c # Header files to ignore when scanning -IGNORE_HFILES= +IGNORE_HFILES=$(top_srcdir)/libmediaart/storage.h # CFLAGS and LDFLAGS for compiling scan program. Only needed # if $(DOC_MODULE).types is non-empty. @@ -49,7 +49,10 @@ expand_content_files = HTML_IMAGES = # Extra options to supply to gtkdoc-fixref -FIXXREF_OPTIONS= +FIXXREF_OPTIONS=\ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gio include $(top_srcdir)/gtk-doc.make diff --git a/docs/reference/libmediaart/libmediaart-docs.sgml b/docs/reference/libmediaart/libmediaart-docs.sgml index 47e7abe..38a5021 100644 --- a/docs/reference/libmediaart/libmediaart-docs.sgml +++ b/docs/reference/libmediaart/libmediaart-docs.sgml @@ -32,6 +32,7 @@ <title>Reference</title> <xi:include href="xml/extract.xml"/> <xi:include href="xml/cache.xml"/> + <xi:include href="xml/plugins.xml"/> </chapter> </part> diff --git a/docs/reference/libmediaart/libmediaart-sections.txt b/docs/reference/libmediaart/libmediaart-sections.txt index cca4ecf..77bd1f7 100644 --- a/docs/reference/libmediaart/libmediaart-sections.txt +++ b/docs/reference/libmediaart/libmediaart-sections.txt @@ -1,30 +1,45 @@ <SECTION> <FILE>cache</FILE> -media_art_get_file media_art_get_path +media_art_get_file media_art_remove media_art_strip_invalid_entities </SECTION> <SECTION> <FILE>extract</FILE> +<TITLE>MediaArtProcess</TITLE> MediaArtType -media_art_init -media_art_shutdown +MediaArtError +MediaArtProcessFlags +MediaArtProcess +MediaArtProcessClass +media_art_error_quark +media_art_process_get_type +media_art_process_new +media_art_process_uri media_art_process_file -media_art_process +media_art_process_buffer +<SUBSECTION Standard> +MEDIA_ART_IS_PROCESS +MEDIA_ART_IS_PROCESS_CLASS +MEDIA_ART_PROCESS +MEDIA_ART_PROCESS_CLASS +MEDIA_ART_PROCESS_GET_CLASS +MEDIA_ART_TYPE_PROCESS </SECTION> <SECTION> -<FILE>extractgeneric</FILE> -media_art_buffer_to_jpeg -media_art_file_to_jpeg +<FILE>plugins</FILE> media_art_plugin_init media_art_plugin_shutdown +media_art_file_to_jpeg +media_art_buffer_to_jpeg </SECTION> <SECTION> -<FILE>mediaart</FILE> - +<FILE>marshal</FILE> +media_art_marshal_VOID__STRING_STRING +media_art_marshal_VOID__STRING_STRING_STRING_BOOLEAN_BOOLEAN </SECTION> diff --git a/libmediaart/cache.c b/libmediaart/cache.c index 7249b14..82286a4 100644 --- a/libmediaart/cache.c +++ b/libmediaart/cache.c @@ -29,22 +29,25 @@ /** * SECTION:cache - * @title: Caching and Management - * @short_description: Caching and management of stored media art. + * @title: Cache + * @short_description: Caching and lookup of stored media art. * @include: libmediaart/mediaart.h * - * These functions give you access to the media art that has been extracted - * and saved in the user's XDG_CACHE_HOME directory. + * These functions give you access to the media art that has been + * extracted and saved in the user's XDG_CACHE_HOME directory (usually + * ~/.cache/media-art/). * * To find the media art for a given media file, use the function - * media_art_get_file() (you can also use media_art_get_path(), which does the - * same thing but for path strings instead of #GFile objects). + * media_art_get_file() (you can also use media_art_get_path(), which + * does the same thing but for path strings instead of #GFile + * objects). * - * If media art for the file is not found in the cache, these functions will - * return %NULL. You may find some embedded media art upon loading the file, - * and you can use media_art_process() to convert it to the correct format and - * save it in the cache for next time. The media_art_process() function also - * supports searching for external media art images using a basic heuristic. + * If media art for the file is not found in the cache, these + * functions will return %NULL. You may find some embedded media art + * upon loading the file, and you can use media_art_process_buffer() + * to convert it to the correct format and save it in the cache for + * next time. The media_art_process_file() function also supports + * searching for external media art images using a basic heuristic. **/ static gboolean @@ -271,9 +274,7 @@ media_art_get_file (const gchar *artist, *local_file = NULL; } - if (!artist && !title) { - return; - } + g_return_if_fail (artist != NULL || title != NULL); if (artist) { artist_stripped = media_art_strip_invalid_entities (artist); @@ -359,8 +360,8 @@ media_art_get_file (const gchar *artist, * @local_uri: (out) (transfer full) (allow-none): the location to store the * local uri or %NULL * - * Get the path to media art for a given resource. Newly allocated data in - * @path and @local_uri must be freed with g_free(). + * Get the path to media art for a given resource. Newly allocated + * data returned in @path and @local_uri must be freed with g_free(). * * Since: 0.2.0 */ @@ -417,7 +418,7 @@ media_art_remove_foreach (gpointer data, * @artist: artist the media art belongs to * @album: (allow-none): album the media art belongs or %NULL * - * Removes media art for given album/artist/etc provided. + * Removes media art for given album/artist provided. * * Returns: #TRUE on success, otherwise #FALSE. * @@ -470,9 +471,11 @@ media_art_remove (const gchar *artist, } /* Add the album path also (to which the symlinks are made) */ - media_art_get_path (NULL, album, "album", NULL, &target, NULL); - if (target) { - g_hash_table_replace (table, target, target); + if (album) { + media_art_get_path (NULL, album, "album", NULL, &target, NULL); + if (target) { + g_hash_table_replace (table, target, target); + } } /* Perhaps we should have an internal list of media art files that we made, diff --git a/libmediaart/extract.c b/libmediaart/extract.c index e9ff970..7091aac 100644 --- a/libmediaart/extract.c +++ b/libmediaart/extract.c @@ -46,7 +46,7 @@ * from a media file and saving it into the media art cache, so that future * applications can display the media art without having to extract the image * again. This is done using the media_art_process_file() or - * media_art_process() functions. + * media_art_process_buffer() functions. * * Extracting new media art from a file needs to be done by your application. * Usually, when an application loads a media file any embedded images will be @@ -56,21 +56,26 @@ * * The media art cache requires that all images are saved as 'application/jpeg' * files. Embedded images can be in several formats, and - * media_art_process_file() and media_art_process() functions will + * media_art_process_file() and media_art_process_buffer() functions will * convert the supplied image data into the correct format if * necessary. There are multiple backends that can be used for this, * and you can choose which is used at build time using the library's * 'configure' script. * * If there is no embedded media art in a file, - * media_art_process_file() and media_art_process() functions will + * media_art_process_file() and media_art_process_buffer() functions will * look in the directory that contains the media file for likely media * art using a simple heuristic. - * - * You must call media_art_init() before using the functions in libmediaart, - * and call media_art_shutdown() to free the resources it uses. **/ +typedef struct { + gboolean disable_requests; + + GHashTable *media_art_cache; + GDBusConnection *connection; + Storage *storage; +} MediaArtProcessPrivate; + static const gchar *media_art_type_name[MEDIA_ART_TYPE_COUNT] = { "invalid", "album", @@ -78,6 +83,7 @@ static const gchar *media_art_type_name[MEDIA_ART_TYPE_COUNT] = { }; typedef struct { + MediaArtProcess *process; gchar *art_path; gchar *local_uri; } FileInfo; @@ -96,16 +102,129 @@ typedef enum { IMAGE_MATCH_TYPE_COUNT } ImageMatchType; -static gboolean initialized = FALSE; -static gboolean disable_requests; +static void media_art_queue_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data); +static void media_art_process_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MediaArtProcess, media_art_process, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + media_art_process_initable_iface_init) + G_ADD_PRIVATE (MediaArtProcess)) + +static void +media_art_process_finalize (GObject *object) +{ + MediaArtProcessPrivate *private; + MediaArtProcess *process; + + process = MEDIA_ART_PROCESS (object); + private = media_art_process_get_instance_private (process); + + if (private->storage) { + g_object_unref (private->storage); + } + + if (private->connection) { + g_object_unref (private->connection); + } + + if (private->media_art_cache) { + g_hash_table_unref (private->media_art_cache); + } + + media_art_plugin_shutdown (); + + G_OBJECT_CLASS (media_art_process_parent_class)->finalize (object); +} + +static gboolean +media_art_process_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + MediaArtProcessPrivate *private; + MediaArtProcess *process; + GError *local_error = NULL; + + process = MEDIA_ART_PROCESS (initable); + private = media_art_process_get_instance_private (process); + + g_debug ("Initializing media art processing requirements..."); -static GHashTable *media_art_cache; -static GDBusConnection *connection; -static Storage *storage; + media_art_plugin_init (0); -static void media_art_queue_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data); + /* Cache to know if we have already handled uris */ + private->media_art_cache = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); + + /* Signal handler for new album art from the extractor */ + private->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error); + + if (!private->connection) { + g_critical ("Could not connect to the D-Bus session bus, %s", + local_error ? local_error->message : "no error given."); + g_propagate_error (error, local_error); + + return FALSE; + } + + private->storage = storage_new (); + if (!private->storage) { + g_critical ("Could not start storage module for removable media detection"); + + if (error) { + *error = g_error_new (media_art_error_quark (), + MEDIA_ART_ERROR_NO_STORAGE, + "Could not initialize storage module"); + } + + return FALSE; + } + + return TRUE; +} + +static void +media_art_process_initable_iface_init (GInitableIface *iface) +{ + iface->init = media_art_process_initable_init; +} + +static void +media_art_process_class_init (MediaArtProcessClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = media_art_process_finalize; +} + +static void +media_art_process_init (MediaArtProcess *thumbnailer) +{ +} + +/** + * media_art_process_new: + * @error: Pointer to potential GLib / MediaArt error, or %NULL + * + * Initialize a GObject for processing and extracting media art. + * + * This function initializes cache hash tables, backend plugins, + * storage modules used for removable devices and a connection to D-Bus. + * + * Returns: A new #MediaArtProcess object on success or %NULL if + * @error is set. This object must be freed using g_object_unref(). + * + * Since: 0.5.0 + */ +MediaArtProcess * +media_art_process_new (GError **error) +{ + return g_initable_new (MEDIA_ART_TYPE_PROCESS, NULL, error, NULL); +} static GDir * get_parent_g_dir (const gchar *uri, @@ -142,7 +261,6 @@ get_parent_g_dir (const gchar *uri, return dir; } - static gchar * checksum_for_data (GChecksumType checksum_type, const guchar *data, @@ -255,10 +373,11 @@ end: } static gboolean -convert_from_other_format (const gchar *found, - const gchar *target, - const gchar *album_path, - const gchar *artist) +convert_from_other_format (const gchar *found, + const gchar *target, + const gchar *album_path, + const gchar *artist, + GError **error) { gboolean retval; gchar *sum1 = NULL; @@ -266,18 +385,28 @@ convert_from_other_format (const gchar *found, target_temp = g_strdup_printf ("%s-tmp", target); - if (!media_art_file_to_jpeg (found, target_temp)) { + if (!media_art_file_to_jpeg (found, target_temp, error)) { g_free (target_temp); return FALSE; } if (artist == NULL || g_strcmp0 (artist, " ") == 0) { - if (g_rename (target_temp, album_path) == -1) { - g_debug ("rename(%s, %s) error: %s", - target_temp, - album_path, - g_strerror (errno)); + 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)); } + + g_debug ("rename(%s, %s) error: %s", + target_temp, + album_path, + g_strerror (errno)); } else if (file_get_checksum_if_exists (G_CHECKSUM_MD5, target_temp, &sum1, @@ -294,45 +423,77 @@ convert_from_other_format (const gchar *found, /* If album-space-md5.jpg is the same as found, * make a symlink */ - - if (symlink (album_path, target) != 0) { - g_debug ("symlink(%s, %s) error: %s", - album_path, - target, - g_strerror (errno)); - retval = FALSE; - } else { - retval = TRUE; + 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_debug ("symlink(%s, %s) error: %s", + album_path, + target, + g_strerror (errno)); + g_unlink (target_temp); } else { /* If album-space-md5.jpg isn't the same as found, * make a new album-md5-md5.jpg (found -> target) */ - - if (g_rename (target_temp, album_path) == -1) { - g_debug ("rename(%s, %s) error: %s", - target_temp, - album_path, - g_strerror (errno)); + 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)); } + + g_debug ("rename(%s, %s) error: %s", + target_temp, + album_path, + g_strerror (errno)); } g_free (sum2); } else { /* If there's not yet a album-space-md5.jpg, make one, * and symlink album-md5-md5.jpg to it */ - g_rename (target_temp, album_path); + 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)); + } 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)); + } - if (symlink (album_path, target) != 0) { g_debug ("symlink(%s,%s) error: %s", - album_path, - target, - g_strerror (errno)); - retval = FALSE; - } else { - retval = TRUE; + album_path, + target, + g_strerror (errno)); } } @@ -530,11 +691,12 @@ media_art_find_by_artist_and_title (const gchar *uri, } static gboolean -media_art_heuristic (const gchar *artist, - const gchar *title, - MediaArtType type, - const gchar *filename_uri, - const gchar *local_uri) +get_heuristic (MediaArtType type, + const gchar *filename_uri, + const gchar *local_uri, + const gchar *artist, + const gchar *title, + GError **error) { gchar *art_file_path = NULL; gchar *album_art_file_path = NULL; @@ -544,7 +706,10 @@ media_art_heuristic (const gchar *artist, gboolean retval = FALSE; if (title == NULL || title[0] == '\0') { - g_debug ("Unable to fetch media art, no title specified"); + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_NO_TITLE, + "Title is required, but was not provided, or was empty"); return FALSE; } @@ -600,171 +765,186 @@ media_art_heuristic (const gchar *artist, artist, title); - if (art_file_path != NULL) { - if (g_str_has_suffix (art_file_path, "jpeg") || - g_str_has_suffix (art_file_path, "jpg")) { + if (!art_file_path) { + // FIXME: Do we GError here? - gboolean is_jpeg = FALSE; - gchar *sum1 = NULL; - - if (type != MEDIA_ART_ALBUM || - (artist == NULL || g_strcmp0 (artist, " ") == 0)) { - GFile *art_file; - GFile *target_file; - GError *err = NULL; - - g_debug ("Album art (JPEG) found in same directory being used:'%s'", - art_file_path); - - target_file = g_file_new_for_path (target); - art_file = g_file_new_for_path (art_file_path); + g_free (art_file_path); + g_free (album_art_file_path); - g_file_copy (art_file, - target_file, - 0, - NULL, - NULL, - NULL, - &err); + g_free (target); + g_free (artist_stripped); + g_free (title_stripped); - if (err) { - g_debug ("%s", err->message); - g_clear_error (&err); - } + return FALSE; + } - g_object_unref (art_file); - g_object_unref (target_file); - } else if (file_get_checksum_if_exists (G_CHECKSUM_MD5, - art_file_path, - &sum1, - TRUE, - &is_jpeg)) { - /* Avoid duplicate artwork for each track in an album */ - media_art_get_path (NULL, - title_stripped, - media_art_type_name [type], - NULL, - &album_art_file_path, - NULL); + if (g_str_has_suffix (art_file_path, "jpeg") || + g_str_has_suffix (art_file_path, "jpg")) { + gboolean is_jpeg = FALSE; + gchar *sum1 = NULL; + + if (type != MEDIA_ART_ALBUM || + (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); + + target_file = g_file_new_for_path (target); + art_file = g_file_new_for_path (art_file_path); + + g_file_copy (art_file, + target_file, + 0, + NULL, + NULL, + NULL, + &local_error); + + if (local_error) { + g_debug ("%s", local_error->message); + g_propagate_error (error, local_error); + } - if (is_jpeg) { - gchar *sum2 = NULL; - - g_debug ("Album art (JPEG) found in same directory being used:'%s'", art_file_path); - - if (file_get_checksum_if_exists (G_CHECKSUM_MD5, - album_art_file_path, - &sum2, - FALSE, - NULL)) { - if (g_strcmp0 (sum1, sum2) == 0) { - /* If album-space-md5.jpg is the same as found, - * make a symlink */ - - if (symlink (album_art_file_path, target) != 0) { - g_debug ("symlink(%s, %s) error: %s", - album_art_file_path, - target, - g_strerror (errno)); - retval = FALSE; - } else { - retval = TRUE; - } - } else { - GFile *art_file; - GFile *target_file; - GError *err = NULL; - - /* If album-space-md5.jpg isn't the same as found, - * make a new album-md5-md5.jpg (found -> target) */ - - target_file = g_file_new_for_path (target); - art_file = g_file_new_for_path (art_file_path); - retval = g_file_copy (art_file, - target_file, - 0, - NULL, - NULL, - NULL, - &err); - if (err) { - g_debug ("%s", err->message); - g_clear_error (&err); - } - g_object_unref (art_file); - g_object_unref (target_file); + g_object_unref (art_file); + g_object_unref (target_file); + } else if (file_get_checksum_if_exists (G_CHECKSUM_MD5, + art_file_path, + &sum1, + TRUE, + &is_jpeg)) { + /* Avoid duplicate artwork for each track in an album */ + media_art_get_path (NULL, + title_stripped, + media_art_type_name [type], + NULL, + &album_art_file_path, + NULL); + + if (is_jpeg) { + gchar *sum2 = NULL; + + g_debug ("Album art (JPEG) found in same directory being used:'%s'", art_file_path); + + if (file_get_checksum_if_exists (G_CHECKSUM_MD5, + album_art_file_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_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", + album_art_file_path, + target, + g_strerror (errno)); } - g_free (sum2); + + g_debug ("symlink(%s, %s) error: %s", + album_art_file_path, + target, + g_strerror (errno)); } else { GFile *art_file; - GFile *album_art_file; - GError *err = NULL; - - /* If there's not yet a album-space-md5.jpg, make one, - * and symlink album-md5-md5.jpg to it */ + GFile *target_file; - album_art_file = g_file_new_for_path (album_art_file_path); + /* If album-space-md5.jpg isn't the same as found, + * make a new album-md5-md5.jpg (found -> target) */ + target_file = g_file_new_for_path (target); art_file = g_file_new_for_path (art_file_path); retval = g_file_copy (art_file, - album_art_file, + target_file, 0, NULL, NULL, NULL, - &err); - - if (err == NULL) { - if (symlink (album_art_file_path, target) != 0) { - g_debug ("symlink(%s, %s) error: %s", - album_art_file_path, target, - g_strerror (errno)); - retval = FALSE; - } else { - retval = TRUE; - } - } else { - g_debug ("%s", err->message); - g_clear_error (&err); - retval = FALSE; - } + error); - g_object_unref (album_art_file); g_object_unref (art_file); + g_object_unref (target_file); } + + g_free (sum2); } else { - g_debug ("Album art found in same directory but not a real JPEG file (trying to convert): '%s'", art_file_path); - retval = convert_from_other_format (art_file_path, - target, - album_art_file_path, - artist); - } + GFile *art_file; + GFile *album_art_file; + + /* 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); + art_file = g_file_new_for_path (art_file_path); + retval = g_file_copy (art_file, + album_art_file, + 0, + NULL, + NULL, + NULL, + error); + + if (retval) { + 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", + album_art_file_path, + target, + g_strerror (errno)); + } - g_free (sum1); + g_debug ("symlink(%s, %s) error: %s", + album_art_file_path, target, + g_strerror (errno)); + } + + g_object_unref (album_art_file); + g_object_unref (art_file); + } } else { - /* Can't read contents of the cover.jpg file ... */ - retval = FALSE; - } - } else if (g_str_has_suffix (art_file_path, "png")) { - if (!album_art_file_path) { - media_art_get_path (NULL, - title_stripped, - media_art_type_name[type], - NULL, - &album_art_file_path, - NULL); + g_debug ("Album art found in same directory but not a real JPEG file (trying to convert): '%s'", art_file_path); + retval = convert_from_other_format (art_file_path, + target, + album_art_file_path, + artist, + error); } - g_debug ("Album art (PNG) found in same directory being used:'%s'", art_file_path); - retval = convert_from_other_format (art_file_path, - target, - album_art_file_path, - artist); + g_free (sum1); + } else { + /* Can't read contents of the cover.jpg file ... */ + retval = FALSE; + } + } else if (g_str_has_suffix (art_file_path, "png")) { + if (!album_art_file_path) { + media_art_get_path (NULL, + title_stripped, + media_art_type_name[type], + NULL, + &album_art_file_path, + NULL); } - g_free (art_file_path); - g_free (album_art_file_path); + g_debug ("Album art (PNG) found in same directory being used:'%s'", art_file_path); + retval = convert_from_other_format (art_file_path, + target, + album_art_file_path, + artist, + error); } + g_free (art_file_path); + g_free (album_art_file_path); + g_free (target); g_free (artist_stripped); g_free (title_stripped); @@ -777,8 +957,6 @@ is_buffer_jpeg (const gchar *mime, const unsigned char *buffer, size_t buffer_len) { - gboolean is_jpeg; - if (buffer == NULL || buffer_len < 3) { return FALSE; } @@ -798,21 +976,19 @@ is_buffer_jpeg (const gchar *mime, } static gboolean -media_art_set (const unsigned char *buffer, - size_t len, - const gchar *mime, - MediaArtType type, - const gchar *artist, - const gchar *title) +media_art_set (const unsigned char *buffer, + size_t len, + const gchar *mime, + MediaArtType type, + const gchar *artist, + const gchar *title, + GError **error) { gchar *local_path; gchar *album_path; gchar *md5_album = NULL; gchar *md5_tmp = NULL; gchar *temp; - const gchar *save_path = NULL; - gboolean save_buffer = FALSE; - gboolean need_symlink = FALSE; gboolean retval = FALSE; g_return_val_if_fail (type > MEDIA_ART_NONE && type < MEDIA_ART_TYPE_COUNT, FALSE); @@ -854,7 +1030,7 @@ 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); + retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, error); g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, local_path); g_free (local_path); @@ -875,21 +1051,29 @@ media_art_set (const unsigned char *buffer, if (!g_file_test (album_path, G_FILE_TEST_EXISTS)) { retval = TRUE; - if (media_art_buffer_to_jpeg (buffer, len, mime, album_path)) { + if (media_art_buffer_to_jpeg (buffer, len, mime, album_path, error)) { g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, album_path); /* If album-space-md5.jpg doesn't * exist, make one and make a symlink * to album-md5-md5.jpg */ - if (symlink (album_path, local_path) != 0) { - g_debug ("Creating symlink '%s' --> '%s', %s", - album_path, - local_path, - retval ? g_strerror (errno) : "no error given"); + retval = symlink (album_path, local_path) == 0; - retval = FALSE; + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_SYMLINK_FAILED, + "Could not link '%s' to '%s': %s", + album_path, + local_path, + g_strerror (errno)); } + + g_debug ("Creating symlink '%s' --> '%s', %s", + album_path, + local_path, + retval ? g_strerror (errno) : "no error given"); } g_free (album_path); @@ -926,6 +1110,17 @@ media_art_set (const unsigned char *buffer, */ if (g_strcmp0 (md5_data, md5_album) == 0) { retval = symlink (album_path, local_path) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_SYMLINK_FAILED, + "Could not link '%s' to '%s': %s", + album_path, + local_path, + g_strerror (errno)); + } + g_debug ("Creating symlink '%s' --> '%s', %s", album_path, local_path, @@ -934,7 +1129,7 @@ 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); + retval = media_art_buffer_to_jpeg (buffer, len, mime, local_path, error); g_debug ("Saving buffer to jpeg (%ld bytes) --> '%s'", len, local_path); } @@ -955,7 +1150,7 @@ media_art_set (const unsigned char *buffer, temp = g_strdup_printf ("%s-tmp", album_path); /* If buffer isn't a JPEG */ - if (!media_art_buffer_to_jpeg (buffer, len, mime, temp)) { + if (!media_art_buffer_to_jpeg (buffer, len, mime, temp, error)) { /* Can't read temp file ... */ g_unlink (temp); @@ -977,6 +1172,17 @@ media_art_set (const unsigned char *buffer, * buffer, make a symlink to album-md5-md5.jpg */ retval = symlink (album_path, local_path) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_SYMLINK_FAILED, + "Could not link '%s' to '%s': %s", + album_path, + local_path, + g_strerror (errno)); + } + g_debug ("Creating symlink '%s' --> '%s', %s", album_path, local_path, @@ -986,6 +1192,17 @@ media_art_set (const unsigned char *buffer, * buffer, make a new album-md5-md5.jpg */ retval = g_rename (temp, local_path) == 0; + + if (!retval) { + g_set_error (error, + media_art_error_quark (), + MEDIA_ART_ERROR_RENAME_FAILED, + "Could not rename '%s' to '%s': %s", + temp, + local_path, + g_strerror (errno)); + } + g_debug ("Renaming temp file '%s' --> '%s', %s", temp, local_path, @@ -1007,13 +1224,15 @@ media_art_set (const unsigned char *buffer, } static FileInfo * -file_info_new (const gchar *local_uri, - const gchar *art_path) +file_info_new (MediaArtProcess *process, + const gchar *local_uri, + const gchar *art_path) { FileInfo *fi; fi = g_slice_new (FileInfo); + fi->process = g_object_ref (process); fi->local_uri = g_strdup (local_uri); fi->art_path = g_strdup (art_path); @@ -1023,23 +1242,33 @@ file_info_new (const gchar *local_uri, static void file_info_free (FileInfo *fi) { + if (!fi) { + return; + } + g_free (fi->local_uri); g_free (fi->art_path); + g_object_unref (fi->process); g_slice_free (FileInfo, fi); } static void -media_art_request_download (MediaArtType type, - const gchar *album, - const gchar *artist, - const gchar *local_uri, - const gchar *art_path) +media_art_request_download (MediaArtProcess *process, + MediaArtType type, + const gchar *album, + const gchar *artist, + const gchar *local_uri, + const gchar *art_path) { - if (connection) { + MediaArtProcessPrivate *private; + + private = media_art_process_get_instance_private (process); + + if (private->connection) { FileInfo *info; - if (disable_requests) { + if (private->disable_requests) { return; } @@ -1047,9 +1276,9 @@ media_art_request_download (MediaArtType type, return; } - info = file_info_new (local_uri, art_path); + info = file_info_new (process, local_uri, art_path); - g_dbus_connection_call (connection, + g_dbus_connection_call (private->connection, ALBUMARTER_SERVICE, ALBUMARTER_PATH, ALBUMARTER_INTERFACE, @@ -1069,14 +1298,18 @@ media_art_request_download (MediaArtType type, } static void -media_art_copy_to_local (const gchar *filename, - const gchar *local_uri) +media_art_copy_to_local (MediaArtProcess *process, + const gchar *filename, + const gchar *local_uri) { + MediaArtProcessPrivate *private; GSList *roots, *l; gboolean on_removable_device = FALSE; guint flen; - roots = storage_get_device_roots (storage, STORAGE_REMOVABLE, FALSE); + private = media_art_process_get_instance_private (process); + + roots = storage_get_device_roots (private->storage, STORAGE_REMOVABLE, FALSE); flen = strlen (filename); for (l = roots; l; l = l->next) { @@ -1133,17 +1366,20 @@ media_art_queue_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { + MediaArtProcessPrivate *private; GError *error = NULL; FileInfo *fi; GVariant *v; fi = user_data; + private = media_art_process_get_instance_private (fi->process); + v = g_dbus_connection_call_finish ((GDBusConnection *) source_object, res, &error); if (error) { if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN) { - disable_requests = TRUE; + private->disable_requests = TRUE; } else { g_warning ("%s", error->message); } @@ -1154,10 +1390,11 @@ media_art_queue_cb (GObject *source_object, g_variant_unref (v); } - if (storage && + if (private->storage && fi->art_path && g_file_test (fi->art_path, G_FILE_TEST_EXISTS)) { - media_art_copy_to_local (fi->art_path, + media_art_copy_to_local (fi->process, + fi->art_path, fi->local_uri); } @@ -1165,80 +1402,23 @@ media_art_queue_cb (GObject *source_object, } /** - * media_art_init: - * - * Initialize libmediaart. + * media_art_error_quark: * - * This function initializes cache hash tables, backend plugins, - * storage modules used for removable devices and connections to D-Bus. - * - * Returns: %TRUE if initialisation was successful, %FALSE otherwise. + * Returns: the #GQuark used to identify media art errors in + * GError structures. * * Since: 0.2.0 - */ -gboolean -media_art_init (void) -{ - GError *error = NULL; - - g_return_val_if_fail (initialized == FALSE, FALSE); - - media_art_plugin_init (0); - - /* Cache to know if we have already handled uris */ - media_art_cache = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - NULL); - - /* Signal handler for new album art from the extractor */ - connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - - if (!connection) { - g_critical ("Could not connect to the D-Bus session bus, %s", - error ? error->message : "no error given."); - g_clear_error (&error); - return FALSE; - } - - storage = storage_new (); - if (!storage) { - g_critical ("Could not start storage module for removable media detection"); - return FALSE; - } - - initialized = TRUE; - - return TRUE; -} - -/** - * media_art_shutdown: - * - * Clean up and free the resources created and mentioned in media_art_init(). - * - * Since: 0.2.0 - */ -void -media_art_shutdown (void) + **/ +GQuark +media_art_error_quark (void) { - g_return_if_fail (initialized == TRUE); - - if (storage) { - g_object_unref (storage); - } + static GQuark error_quark = 0; - if (connection) { - g_object_unref (connection); + if (G_UNLIKELY (error_quark == 0)) { + error_quark = g_quark_from_static_string ("media-art-error-quark"); } - if (media_art_cache) { - g_hash_table_unref (media_art_cache); - } - - media_art_plugin_shutdown (); - - initialized = FALSE; + return error_quark; } static void @@ -1253,27 +1433,21 @@ set_mtime (const gchar *filename, static guint64 -get_mtime (GFile *file) +get_mtime (GFile *file, + GError **error) { GFileInfo *info; - GError *error = NULL; - guint64 mtime; + GError *local_error = NULL; + guint64 mtime; info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, - &error); + &local_error); - if (G_UNLIKELY (error)) { - gchar *uri; - - uri = g_file_get_uri (file); - g_message ("Could not get mtime for '%s': %s", - uri, - error->message); - g_free (uri); - g_error_free (error); + if (G_UNLIKELY (local_error != NULL)) { + g_propagate_error (error, local_error); mtime = 0; } else { mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); @@ -1283,191 +1457,327 @@ get_mtime (GFile *file) return mtime; } -guint64 -get_mtime_by_path (const gchar *path) -{ - GFile *file; - guint64 mtime; - - g_return_val_if_fail (path != NULL, 0); - - file = g_file_new_for_path (path); - - mtime = get_mtime (file); - - g_object_unref (file); - - return mtime; -} - - -guint64 -get_mtime_by_uri (const gchar *uri) +static gchar * +get_heuristic_for_parent_path (GFile *file, + MediaArtType type, + const gchar *artist, + const gchar *title) { - GFile *file; - guint64 mtime; + gchar *key; + gchar *parent_path = NULL; + GFile *parent; - g_return_val_if_fail (uri != NULL, 0); + if (!file) { + return NULL; + } - file = g_file_new_for_uri (uri); + parent = g_file_get_parent (file); + if (parent) { + parent_path = g_file_get_path (parent); + g_object_unref (parent); + } - mtime = get_mtime (file); + /* Just used for caching in our hash table */ + key = g_strdup_printf ("%s:%s:%s:%s", + parent_path ? parent_path : "", + media_art_type_name[type], + artist ? artist : "", + title ? title : ""); - g_object_unref (file); + g_free (parent_path); - return mtime; + return key; } - /** - * media_art_process_file: + * media_art_process_buffer: + * @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 - * @type: The type of media - * @artist: The media file artist name, or %NULL - * @title: The media file title, or %NULL - * @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 * - * Processes a media file. If you have extracted any embedded media art and - * passed this in as @buffer, the image data will be converted to the correct - * format and saved in the media art cache. - * - * If @buffer is %NULL, libmediaart will search the parent directory of @file - * for image files that are likely to be media art for @file, and if one is - * found it will be saved in the media art cache. + * Processes a memory buffer represented by @buffer and @len. If you + * have extracted any embedded media art and passed this in as + * @buffer, the image data will be converted to the correct format and + * saved in the media art cache. * * If @file is on a removable filesystem, the media art file will be saved in a * cache on the removable file system rather than on the host machine. * - * Returns: #TRUE if the file could be processed. + * Returns: %TRUE if @file could be processed or %FALSE if @error is set. * - * Since: 0.2.0 + * Since: 0.5.0 */ gboolean -media_art_process_file (const guchar *buffer, - gsize len, - const gchar *mime, - MediaArtType type, - const gchar *artist, - const gchar *title, - GFile *file) +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) { GFile *cache_art_file, *local_art_file; - gchar *art_path, *uri; - gchar *local_art_uri = NULL; - gboolean processed = TRUE, a_exists, created = FALSE; - guint64 mtime, a_mtime = 0; + GError *local_error = NULL; + gchar *cache_art_path, *uri; + gboolean processed, created; + guint64 mtime, cache_mtime = 0; + g_return_val_if_fail (MEDIA_ART_IS_PROCESS (process), FALSE); g_return_val_if_fail (type > MEDIA_ART_NONE && type < MEDIA_ART_TYPE_COUNT, FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (G_IS_FILE (related_file), FALSE); + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (len < 0, FALSE); - uri = g_file_get_uri (file); - g_debug ("Processing media art: artist:'%s', title:'%s', type:'%s', uri:'%s'. Buffer is %ld bytes, mime:'%s'", + processed = created = FALSE; + + uri = g_file_get_uri (related_file); + g_debug ("Processing media art: artist:'%s', title:'%s', type:'%s', uri:'%s', flags:0x%.8x. Buffer is %ld bytes, mime:'%s'", artist ? artist : "", title ? title : "", media_art_type_name[type], uri, + flags, (long int) len, mime); - mtime = get_mtime (file); + mtime = get_mtime (related_file, &local_error); + if (local_error != NULL) { + g_debug ("Could not get mtime for related file '%s': %s", + uri, + local_error->message); + g_propagate_error (error, local_error); + g_free (uri); + + return FALSE; + } media_art_get_file (artist, title, media_art_type_name[type], - file, + related_file, &cache_art_file, &local_art_file); - if (!cache_art_file) { - g_debug ("Album art path could not be obtained, not processing any further"); + cache_mtime = get_mtime (cache_art_file, &local_error); + + if (local_error && + local_error->domain == g_io_error_quark () && + local_error->code == G_IO_ERROR_NOT_FOUND) { + /* cache_art_file not existing is the only error we + * accept here, anything else and we return. + */ + gchar *path; + + path = g_file_get_uri (cache_art_file); + g_debug ("Cache for media art did not exist (%s)", + path); + g_free (path); + g_clear_error (&local_error); + } else if (local_error) { + g_free (uri); + + uri = g_file_get_uri (cache_art_file); + g_debug ("Could not get mtime for cache '%s': %s", + uri, + local_error->message); + g_free (uri); if (local_art_file) { g_object_unref (local_art_file); } - g_free (uri); + g_propagate_error (error, local_error); return FALSE; } - a_exists = g_file_query_exists (cache_art_file, NULL); - if (a_exists) { - a_mtime = get_mtime (cache_art_file); + cache_art_path = g_file_get_path (cache_art_file); + + if (flags & MEDIA_ART_PROCESS_FLAGS_FORCE || + cache_mtime == 0 || mtime > cache_mtime) { + processed = media_art_set (buffer, len, mime, type, artist, title, error); + set_mtime (cache_art_path, mtime); + } else { + g_debug ("Album art already exists for uri:'%s' as '%s'", + uri, + cache_art_path); + processed = TRUE; } - art_path = g_file_get_path (cache_art_file); - local_art_uri = g_file_get_uri (local_art_file); + 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); + } + } + + if (cache_art_file) { + g_object_unref (cache_art_file); + } + + if (local_art_file) { + g_object_unref (local_art_file); + } + + g_free (cache_art_path); + g_free (uri); + + return processed; +} + +/** + * media_art_process_file: + * @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 + * @error: Pointer to potential GLib / MediaArt error, or %NULL + * + * 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 + * %NULL, but they can not both be %NULL. + * + * NOTE: This function MAY retrieve media art for + * @artist and @title combinations. It is not guaranteed and depends + * on download services available over DBus at the time. + * + * In cases where download is unavailable, media_art_process_file() + * will only try to procure a cache for possible media art found in + * directories surrounding the location of @file. If a buffer or + * memory chunk needs to be saved to disk which has been retrieved + * from an MP3 (for example), you should use + * media_art_process_buffer(). + * + * The modification time (mtime) of @file is checked against the + * cached stored for @artist and @title. If the cache is old or + * doesn't exist, it will be updated. What this actually does is + * update the mtime of the cache (a symlink) on the disk. + * + * If there is no actual media art stored locally (for example, it's + * stored in a directory on a removable device), it is copied locally + * (usually to an XDG cache directory). + * + * If @file is on a removable filesystem, the media art file will be + * saved in a cache on the removable file system rather than on the + * host machine. + * + * Returns: %TRUE if @file could be processed or %FALSE if @error is set. + * + * Since: 0.3.0 + */ +gboolean +media_art_process_file (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + GFile *file, + const gchar *artist, + const gchar *title, + GError **error) +{ + MediaArtProcessPrivate *private; + GFile *cache_art_file, *local_art_file; + GError *local_error = NULL; + gchar *cache_art_path, *uri; + gboolean no_cache_or_old; + guint64 mtime, cache_mtime; + + g_return_val_if_fail (MEDIA_ART_IS_PROCESS (process), FALSE); + g_return_val_if_fail (type > MEDIA_ART_NONE && type < MEDIA_ART_TYPE_COUNT, FALSE); + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (artist != NULL || title != NULL, FALSE); + + private = media_art_process_get_instance_private (process); + + uri = g_file_get_uri (file); + g_debug ("Processing media art: artist:'%s', title:'%s', type:'%s', uri:'%s', flags:0x%.8x", + artist ? artist : "", + title ? title : "", + media_art_type_name[type], + uri, + flags); + + mtime = get_mtime (file, &local_error); + if (local_error != NULL) { + g_debug ("Could not get mtime for file '%s': %s", + uri, + local_error->message); + g_propagate_error (error, local_error); + g_free (uri); - if ((buffer && len > 0) && ((!a_exists) || (a_exists && mtime > a_mtime))) { - processed = media_art_set (buffer, len, mime, type, artist, title); - set_mtime (art_path, mtime); - created = TRUE; + return FALSE; } - if ((!created) && ((!a_exists) || (a_exists && mtime > a_mtime))) { + media_art_get_file (artist, + title, + media_art_type_name[type], + file, + &cache_art_file, + &local_art_file); + + cache_art_path = g_file_get_path (cache_art_file); + + cache_mtime = get_mtime (cache_art_file, &local_error); + no_cache_or_old = cache_mtime == -1 || cache_mtime < mtime; + + if (no_cache_or_old) { /* If not, we perform a heuristic on the dir */ gchar *key; - gchar *dirname = NULL; - GFile *dirf; - dirf = g_file_get_parent (file); - if (dirf) { - dirname = g_file_get_path (dirf); - g_object_unref (dirf); - } + key = get_heuristic_for_parent_path (file, type, artist, title); - key = g_strdup_printf ("%i-%s-%s-%s", - type, - artist ? artist : "", - title ? title : "", - dirname ? dirname : ""); + if (!g_hash_table_lookup (private->media_art_cache, key)) { + gchar *local_art_uri; - g_free (dirname); + local_art_uri = g_file_get_uri (local_art_file); - if (!g_hash_table_lookup (media_art_cache, key)) { - if (!media_art_heuristic (artist, - title, - type, - uri, - local_art_uri)) { + 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 (type, + media_art_request_download (process, + type, artist, title, local_art_uri, - art_path); + cache_art_path); + + /* FIXME: Should return TRUE or FALSE? */ } - set_mtime (art_path, mtime); + set_mtime (cache_art_path, mtime); - g_hash_table_insert (media_art_cache, + g_hash_table_insert (private->media_art_cache, key, GINT_TO_POINTER(TRUE)); + g_free (local_art_uri); } else { g_free (key); } } else { - if (!created) { - g_debug ("Album art already exists for uri:'%s' as '%s'", - uri, - art_path); - } - } - - 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)) { - media_art_copy_to_local (art_path, local_art_uri); - } + g_debug ("Album art already exists for uri:'%s' as '%s'", + uri, + cache_art_path); } if (cache_art_file) { @@ -1478,54 +1788,56 @@ media_art_process_file (const guchar *buffer, g_object_unref (local_art_file); } - g_free (art_path); - g_free (local_art_uri); + g_free (cache_art_path); g_free (uri); - return processed; + return TRUE; } - /** - * media_art_process: - * @buffer: (array length=len): A buffer of binary image data - * @len: The length of @buffer, in bytes - * @mime: The MIME type of the data stored in @buffer + * media_art_process_uri: + * @process: Media art process object * @type: The type of media that contained the image data - * @artist: (allow-none): Artist name of the media - * @title: (allow-none): Title of the media - * @uri: URI of the media file that contained the image data + * @flags: How the media art is processed + * @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 + * @error: Pointer to potential GLib / MediaArt error, or %NULL * - * This function is the same as media_art_process_file(), but takes the URI as - * a string rather than a #GFile object. + * This function calls media_art_process_file(), but takes the @uri as + * a string rather than a #GFile object. Either @artist OR @title can be + * %NULL, but they can not both be %NULL. * - * Returns: %TRUE in case of success, %FALSE otherwise. + * Returns: %TRUE if @uri could be processed or %FALSE if @error is set. * - * Since: 0.2.0 + * Since: 0.5.0 */ gboolean -media_art_process (const unsigned char *buffer, - size_t len, - const gchar *mime, - MediaArtType type, - const gchar *artist, - const gchar *title, - const gchar *uri) +media_art_process_uri (MediaArtProcess *process, + MediaArtType type, + MediaArtProcessFlags flags, + const gchar *uri, + const gchar *artist, + const gchar *title, + GError **error) { GFile *file; gboolean result; + g_return_val_if_fail (MEDIA_ART_IS_PROCESS (process), FALSE); + g_return_val_if_fail (type > MEDIA_ART_NONE && type < MEDIA_ART_TYPE_COUNT, FALSE); g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (artist != NULL || title != NULL, FALSE); file = g_file_new_for_uri (uri); - result = media_art_process_file (buffer, - len, - mime, + result = media_art_process_file (process, type, + flags, + file, artist, title, - file); + error); g_object_unref (file); diff --git a/libmediaart/extract.h b/libmediaart/extract.h index 3744923..e5ab8fa 100644 --- a/libmediaart/extract.h +++ b/libmediaart/extract.h @@ -46,25 +46,111 @@ typedef enum { MEDIA_ART_TYPE_COUNT } MediaArtType; -gboolean media_art_init (void); -void media_art_shutdown (void); - -gboolean media_art_process (const unsigned char *buffer, - size_t len, - const gchar *mime, - MediaArtType type, - const gchar *artist, - const gchar *title, - const gchar *uri); - -gboolean media_art_process_file (const guchar *buffer, - gsize len, - const gchar *mime, - MediaArtType type, - const gchar *artist, - const gchar *title, - GFile *file); +/** + * MediaArtProcessFlags: + * @MEDIA_ART_PROCESS_FLAGS_NONE: Normal operation. + * @MEDIA_ART_PROCESS_FLAGS_FORCE: Force media art to be re-saved to disk even if it already exists and the related file or URI has the same modified time (mtime). + * + * This type categorized the flags used when processing media art. + * + * Since: 0.3.0 + */ +typedef enum { + MEDIA_ART_PROCESS_FLAGS_NONE = 0, + MEDIA_ART_PROCESS_FLAGS_FORCE = 1 << 0, +} MediaArtProcessFlags; + +/** + * MediaArtError: + * @MEDIA_ART_ERROR_NO_STORAGE: Storage information is unknown, we + * have no knowledge about removable media. + * @MEDIA_ART_ERROR_NO_TITLE: Title is required, but was not provided, + * or was empty. + * @MEDIA_ART_ERROR_SYMLINK_FAILED: A call to symlink() failed + * resulting in the incorrect storage of media art. + * @MEDIA_ART_ERROR_RENAME_FAILED: File could not be renamed. + * + * Enumeration values used in errors returned by the + * #MediaArtError API. + * + * Since: 0.2.0 + **/ +typedef enum { + MEDIA_ART_ERROR_NO_STORAGE, + MEDIA_ART_ERROR_NO_TITLE, + MEDIA_ART_ERROR_SYMLINK_FAILED, + MEDIA_ART_ERROR_RENAME_FAILED +} MediaArtError; + + +/** + * media_art_error_quark: + * + * A #GQuark representing the type of #GError for #MediaArtProcess failures. + * + * Since: 0.2.0 + **/ +GQuark media_art_error_quark (void) G_GNUC_CONST; + + +#define MEDIA_ART_TYPE_PROCESS (media_art_process_get_type()) +#define MEDIA_ART_PROCESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MEDIA_ART_TYPE_PROCESS, MediaArtProcess)) +#define MEDIA_ART_PROCESS_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MEDIA_ART_TYPE_PROCESS, MediaArtProcessClass)) +#define MEDIA_ART_IS_PROCESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MEDIA_ART_TYPE_PROCESS)) +#define MEDIA_ART_IS_PROCESS_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), MEDIA_ART_TYPE_PROCESS)) +#define MEDIA_ART_PROCESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MEDIA_ART_TYPE_PROCESS, MediaArtProcessClass)) + +typedef struct _MediaArtProcess MediaArtProcess; +typedef struct _MediaArtProcessClass MediaArtProcessClass; + +/** + * MediaArtProcess: + * @parent: parent object + * + * A class implementation for processing and extracting media art. + **/ +struct _MediaArtProcess { + GObject parent; +}; + +/** + * MediaArtProcessClass: + * @parent: parent object class + * + * Prototype for the class. + **/ +struct _MediaArtProcessClass { + GObjectClass parent; +}; + + +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); G_END_DECLS -#endif /* __LIBMEDIAART_UTILS_H__ */ +#endif /* __LIBMEDIAART_EXTRACT_H__ */ diff --git a/libmediaart/extractdummy.c b/libmediaart/extractdummy.c index 195de31..f80ccd2 100644 --- a/libmediaart/extractdummy.c +++ b/libmediaart/extractdummy.c @@ -22,30 +22,98 @@ #include "extractgeneric.h" +/** + * SECTION:plugins + * @title: Plugins + * @short_description: Plugins for cache conversion. + * @include: libmediaart/mediaart.h + * + * Plugins are provided to allow different systems to make use of + * existing file format conversion APIs. By default, a GdkPixbuf and + * Qt implementation are provided. This API allows new implementations + * to be provided. + * + **/ + +/** + * media_art_plugin_init: + * @max_width: The maximum width that an image is allowed to be + * + * This function facilitates a plugin's need to create any + * internal caches before anything else is done. This function must + * exist in each plugin and is called immediately after the plugin is + * loaded. Conversely, media_art_plugin_shutdown() is called before + * tear down of the plugin system or plugin itself. + * + * Since: 0.1.0 + */ void media_art_plugin_init (gint max_width) { /* Initialize something */ } +/** + * media_art_plugin_shutdown: + * + * This function facilitates a plugin's need to clean up any + * internal caches. This function must exist in each plugin and is + * called immediately after the plugin is loaded. Conversely, + * media_art_plugin_init() is called after the plugin is loaded. + * + * Since: 0.1.0 + */ void media_art_plugin_shutdown (void) { /* Shutdown something */ } +/** + * media_art_file_to_jpeg: + * @filename: Original file name (not URI) to convert + * @target: Output file name (not URI) to save converted content to + * @error: A #GError to use upon failure, or %NULL + * + * Save @filename to @target as JPEG format. The @filename may not be + * a JPEG in the first place. + * + * Returns: %TRUE if conversion was successful, otherwise %FALSE is + * returned if @error is set. + * + * Since: 0.1.0 + */ gboolean -media_art_file_to_jpeg (const gchar *filename, - const gchar *target) +media_art_file_to_jpeg (const gchar *filename, + const gchar *target, + GError **error) { return FALSE; } +/** + * media_art_buffer_to_jpeg: + * @buffer: Raw buffer representing content to save + * @len: Length of @buffer to use + * @buffer_mime: MIME type for @buffer + * @target: Output file name (not URI) to save converted content to + * @error: A #GError to use upon failure, or %NULL + * + * This function performs the same operation as + * media_art_file_to_jpeg() with the exception that a raw @buffer can + * be used instead providing @len and the @buffer_mime too. + * + * Returns: %TRUE if conversion was successful, otherwise %FALSE is + * returned if @error is set. + * + * Since: 0.1.0 + */ gboolean -media_art_buffer_to_jpeg (const unsigned char *buffer, - size_t len, - const gchar *buffer_mime, - const gchar *target) +media_art_buffer_to_jpeg (const unsigned char *buffer, + size_t len, + const gchar *buffer_mime, + const gchar *target, + GError **error) { return FALSE; } diff --git a/libmediaart/extractgeneric.h b/libmediaart/extractgeneric.h index b48d2be..8fa114b 100644 --- a/libmediaart/extractgeneric.h +++ b/libmediaart/extractgeneric.h @@ -20,7 +20,6 @@ * Philip Van Hoof <philip@codeminded.be> */ - #ifndef __LIBMEDIAART_EXTRACTGENERIC_H__ #define __LIBMEDIAART_EXTRACTGENERIC_H__ @@ -32,15 +31,17 @@ G_BEGIN_DECLS -void media_art_plugin_init (gint max_width); +void media_art_plugin_init (gint max_width); void media_art_plugin_shutdown (void); -gboolean media_art_file_to_jpeg (const gchar *filename, - const gchar *target); -gboolean media_art_buffer_to_jpeg (const unsigned char *buffer, - size_t len, - const gchar *buffer_mime, - const gchar *target); +gboolean media_art_file_to_jpeg (const gchar *filename, + const gchar *target, + GError **error); +gboolean media_art_buffer_to_jpeg (const unsigned char *buffer, + size_t len, + const gchar *buffer_mime, + const gchar *target, + GError **error); G_END_DECLS diff --git a/libmediaart/extractpixbuf.c b/libmediaart/extractpixbuf.c index 2f823fc..3b2854b 100644 --- a/libmediaart/extractpixbuf.c +++ b/libmediaart/extractpixbuf.c @@ -40,28 +40,28 @@ media_art_plugin_shutdown (void) } gboolean -media_art_file_to_jpeg (const gchar *filename, - const gchar *target) +media_art_file_to_jpeg (const gchar *filename, + const gchar *target, + GError **error) { GdkPixbuf *pixbuf; - GError *error = NULL; + GError *local_error = NULL; /* TODO: Add resizing support */ - pixbuf = gdk_pixbuf_new_from_file (filename, &error); - - if (error) { - g_clear_error (&error); + pixbuf = gdk_pixbuf_new_from_file (filename, &local_error); + if (local_error) { + g_propagate_error (error, local_error); return FALSE; - } else { - gdk_pixbuf_save (pixbuf, target, "jpeg", &error, NULL); - g_object_unref (pixbuf); + } - if (error) { - g_clear_error (&error); - return FALSE; - } + gdk_pixbuf_save (pixbuf, target, "jpeg", &local_error, NULL); + g_object_unref (pixbuf); + + if (local_error) { + g_propagate_error (error, local_error); + return FALSE; } return TRUE; @@ -87,11 +87,14 @@ size_prepared_cb (GdkPixbufLoader *loader, } gboolean -media_art_buffer_to_jpeg (const unsigned char *buffer, - size_t len, - const gchar *buffer_mime, - const gchar *target) +media_art_buffer_to_jpeg (const unsigned char *buffer, + size_t len, + const gchar *buffer_mime, + const gchar *target, + GError **error) { + GError *local_error = NULL; + if (max_width_in_bytes < 0) { g_debug ("Not saving album art from buffer, disabled in config"); return TRUE; @@ -103,11 +106,12 @@ media_art_buffer_to_jpeg (const unsigned char *buffer, g_strcmp0 (buffer_mime, "JPG") == 0) && (buffer && len > 2 && buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff)) { g_debug ("Saving album art using raw data as uri:'%s'", target); - g_file_set_contents (target, (const gchar *) buffer, (gssize) len, NULL); + if (!g_file_set_contents (target, (const gchar *) buffer, (gssize) len, error)) { + return FALSE; + } } else { GdkPixbuf *pixbuf; GdkPixbufLoader *loader; - GError *error = NULL; g_debug ("Saving album art using GdkPixbufLoader for uri:'%s' (max width:%d)", target, @@ -121,11 +125,11 @@ media_art_buffer_to_jpeg (const unsigned char *buffer, NULL); } - if (!gdk_pixbuf_loader_write (loader, buffer, len, &error)) { - g_warning ("Could not write with GdkPixbufLoader when setting album art, %s", - error ? error->message : "no error given"); + if (!gdk_pixbuf_loader_write (loader, buffer, len, &local_error)) { + g_warning ("Could not write with GdkPixbufLoader when setting media art, %s", + local_error ? local_error->message : "no error given"); - g_clear_error (&error); + g_propagate_error (error, local_error); gdk_pixbuf_loader_close (loader, NULL); g_object_unref (loader); @@ -135,7 +139,9 @@ media_art_buffer_to_jpeg (const unsigned char *buffer, pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); if (pixbuf == NULL) { - g_warning ("Could not get pixbuf from GdkPixbufLoader when setting album art"); + g_warning ("Could not get pixbuf from GdkPixbufLoader when setting media art"); + + /* FIXME: Set error here */ gdk_pixbuf_loader_close (loader, NULL); g_object_unref (loader); @@ -143,21 +149,24 @@ media_art_buffer_to_jpeg (const unsigned char *buffer, return FALSE; } - if (!gdk_pixbuf_save (pixbuf, target, "jpeg", &error, NULL)) { - g_warning ("Could not save GdkPixbuf when setting album art, %s", - error ? error->message : "no error given"); + if (!gdk_pixbuf_save (pixbuf, target, "jpeg", &local_error, NULL)) { + g_warning ("Could not save GdkPixbuf when setting media art, %s", + local_error ? local_error->message : "no error given"); - g_clear_error (&error); + g_propagate_error (error, local_error); gdk_pixbuf_loader_close (loader, NULL); g_object_unref (loader); return FALSE; } - if (!gdk_pixbuf_loader_close (loader, &error)) { - g_warning ("Could not close GdkPixbufLoader when setting album art, %s", - error ? error->message : "no error given"); - g_clear_error (&error); + if (!gdk_pixbuf_loader_close (loader, &local_error)) { + g_warning ("Could not close GdkPixbufLoader when setting media art, %s", + local_error ? local_error->message : "no error given"); + + g_propagate_error (error, local_error); + + return FALSE; } g_object_unref (loader); diff --git a/libmediaart/extractqt.cpp b/libmediaart/extractqt.cpp index d39ddd7..dda324f 100644 --- a/libmediaart/extractqt.cpp +++ b/libmediaart/extractqt.cpp @@ -82,8 +82,9 @@ media_art_plugin_shutdown (void) } gboolean -media_art_file_to_jpeg (const gchar *filename, - const gchar *target) +media_art_file_to_jpeg (const gchar *filename, + const gchar *target, + GError **error) { if (max_width_in_bytes < 0) { g_debug ("Not saving album art from file, disabled in config"); @@ -91,6 +92,7 @@ media_art_file_to_jpeg (const gchar *filename, } /* TODO: Add resizing support */ + /* TODO: Add error reporting */ QFile file (filename); @@ -129,10 +131,11 @@ media_art_file_to_jpeg (const gchar *filename, } gboolean -media_art_buffer_to_jpeg (const unsigned char *buffer, - size_t len, - const gchar *buffer_mime, - const gchar *target) +media_art_buffer_to_jpeg (const unsigned char *buffer, + size_t len, + const gchar *buffer_mime, + const gchar *target, + GError **error) { if (max_width_in_bytes < 0) { g_debug ("Not saving album art from buffer, disabled in config"); @@ -144,14 +147,16 @@ media_art_buffer_to_jpeg (const unsigned char *buffer, (g_strcmp0 (buffer_mime, "image/jpeg") == 0 || g_strcmp0 (buffer_mime, "JPG") == 0) && (buffer && len > 2 && buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff)) { - g_debug ("Saving album art using raw data as uri:'%s'", - target); - g_file_set_contents (target, (const gchar*) buffer, (gssize) len, NULL); + g_debug ("Saving album art using raw data as uri:'%s'", target); + if (!g_file_set_contents (target, (const gchar*) buffer, (gssize) len, error)) { + return FALSE; + } } else { QImageReader *reader = NULL; QByteArray array; /* TODO: Add resizing support */ + /* TODO: Add error reporting */ array = QByteArray ((const char *) buffer, (int) len); diff --git a/libmediaart/storage.c b/libmediaart/storage.c index feb22f6..36213d7 100644 --- a/libmediaart/storage.c +++ b/libmediaart/storage.c @@ -28,7 +28,7 @@ #include "marshal.h" /** - * SECTION:-storage + * SECTION:storage * @short_description: Removable storage and mount point convenience API * @include: libmediaart/mediaart.h * @@ -140,8 +140,6 @@ storage_init (Storage *storage) { StoragePrivate *priv; - g_message ("Initializing Storage..."); - priv = STORAGE_GET_PRIVATE (storage); priv->mounts = g_node_new (NULL); @@ -163,8 +161,6 @@ storage_init (Storage *storage) g_signal_connect_object (priv->volume_monitor, "mount-added", G_CALLBACK (mount_added_cb), storage, 0); - g_message ("Mount monitors set up for to watch for added, removed and pre-unmounts..."); - /* Get all mounts and set them up */ if (!mounts_setup (storage)) { return; @@ -702,7 +698,7 @@ mounts_setup (Storage *storage) mounts = g_volume_monitor_get_mounts (priv->volume_monitor); if (!mounts) { - g_message ("No mounts found to iterate"); + g_debug ("No mounts found to iterate"); return TRUE; } @@ -752,19 +748,19 @@ mount_remove (Storage *storage, if (node) { info = node->data; - g_message ("Mount:'%s' with UUID:'%s' now unmounted from:'%s'", - name, - info->uuid, - mount_point); + g_debug ("Mount:'%s' with UUID:'%s' now unmounted from:'%s'", + name, + info->uuid, + mount_point); g_signal_emit (storage, signals[MOUNT_POINT_REMOVED], 0, info->uuid, mount_point, NULL); g_hash_table_remove (priv->mounts_by_uuid, info->uuid); mount_node_free (node); } else { - g_message ("Mount:'%s' now unmounted from:'%s' (was not tracked)", - name, - mount_point); + g_debug ("Mount:'%s' now unmounted from:'%s' (was not tracked)", + name, + mount_point); } g_free (name); diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..0f4126c --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1 @@ +*.m4 diff --git a/m4/attributes.m4 b/m4/attributes.m4 new file mode 100644 index 0000000..aa53ef2 --- /dev/null +++ b/m4/attributes.m4 @@ -0,0 +1,288 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2008 Diego Pettenò <flameeyes@gmail.com> +dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com> +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if FLAG in ENV-VAR is supported by compiler and append it +dnl to WHERE-TO-APPEND variable +dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG]) + +AC_DEFUN([CC_CHECK_FLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], + AS_TR_SH([cc_cv_$2_$3]), + [eval "AS_TR_SH([cc_save_$2])='${$2}'" + eval "AS_TR_SH([$2])='-Werror $3'" + AC_LINK_IFELSE([AC_LANG_SOURCE([int a = 0; int main(void) { return a; } ])], + [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], + [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) + eval "AS_TR_SH([$2])='$cc_save_$2'"]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], + [eval "$1='${$1} $3'"]) +]) + +dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2]) +AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ + for flag in $3; do + CC_CHECK_FLAG_APPEND($1, $2, $flag) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable commandline, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff --git a/m4/local.m4 b/m4/local.m4 new file mode 100644 index 0000000..bca646d --- /dev/null +++ b/m4/local.m4 @@ -0,0 +1,258 @@ +dnl ######################################################################### +AC_DEFUN([AX_DOTS_TO_UNDERSCORES], [ + $1[]_UNDERSCORES=`echo "$$1" | sed -e 's/\./_/g'` + AC_SUBST($1[]_UNDERSCORES) +]) dnl AX_DOTS_TO_UNDERSCORES + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [illegal OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([illegal OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION + +dnl ######################################################################### +dnl Turn on the additional warnings last, so -Werror doesn't affect other tests. +AC_DEFUN([IDT_COMPILE_WARNINGS],[ + if test -f $srcdir/autogen.sh; then + default_compile_warnings="maximum" + else + default_compile_warnings="no" + fi + + AC_ARG_WITH(compile-warnings, + AS_HELP_STRING([--with-compile-warnings=@<:@no/yes/maximum/error@:>@], + [Compiler warnings]), + [enable_compile_warnings="$withval"], + [enable_compile_warnings="$default_compile_warnings"]) + + warnCFLAGS= + if test "x$GCC" != xyes; then + enable_compile_warnings=no + fi + + warning_cflags= + warning_valaflags= + realsave_CFLAGS="$CFLAGS" + + # Everything from -Wall except: + # 1. the -Wunused-* stuff + # 2. the non C warnings: -Wreorder -Wc++11-compat + # 3. unfixable issues: -Wmissing-braces + # + # We don't want to see warnings about generated code. + CC_CHECK_FLAGS_APPEND([common_cflags], [CFLAGS], [\ + -Waddress \ + -Warray-bounds \ + -Wchar-subscripts \ + -Wenum-compare \ + -Wimplicit-int \ + -Wimplicit-function-declaration \ + -Wcomment \ + -Wformat \ + -Wmain \ + -Wmaybe-uninitialized \ + -Wnonnull \ + -Wparentheses \ + -Wpointer-sign \ + -Wreturn-type \ + -Wsequence-point \ + -Wsign-compare \ + -Wstrict-aliasing \ + -Wstrict-overflow=1 \ + -Wswitch \ + -Wtrigraphs \ + -Wuninitialized \ + -Wunknown-pragmas \ + -Wvolatile-register-var \ + ]) + + case "$enable_compile_warnings" in + no) + warning_cflags= + warning_valaflags= + ;; + yes) + CC_CHECK_FLAGS_APPEND([additional_cflags], [CFLAGS], [\ + -Wall \ + -Wunused \ + -Wmissing-prototypes \ + -Wmissing-declarations \ + ]) + + CC_CHECK_FLAGS_APPEND([additional_valaflags], [CFLAGS], [\ + -Wmissing-prototypes \ + -Wmissing-declarations \ + ]) + + dnl -Wall includes the $common_cflags already. + warning_cflags="$additional_cflags" + warning_valaflags="$common_cflags $additional_valaflags" + ;; + maximum|error) + CC_CHECK_FLAGS_APPEND([additional_cflags], [CFLAGS], [\ + -Wall \ + -Wunused \ + -Wchar-subscripts \ + -Wmissing-prototypes \ + -Wmissing-declarations \ + -Wnested-externs \ + -Wpointer-arit \ + -Wno-sign-compare \ + -Wno-pointer-sign \ + ]) + + CC_CHECK_FLAGS_APPEND([additional_valaflags], [CFLAGS], [\ + -Wmissing-prototypes \ + -Wmissing-declarations \ + -Wnested-externs \ + -Wpointer-arith \ + -Wno-sign-compare \ + -Wno-pointer-sign \ + ]) + + dnl -Wall includes the $common_cflags already. + warning_cflags="$additional_cflags" + warning_valaflags="$common_cflags $additional_valaflags" + + if test "$enable_compile_warnings" = "error" ; then + warning_cflags="$warning_cflags -Werror" + warning_valaflags="$warning_valaflags -Werror" + fi + ;; + *) + AC_MSG_ERROR(Unknown argument '$enable_compile_warnings' to --with-compile-warnings) + ;; + esac + CFLAGS="$realsave_CFLAGS" + AC_MSG_CHECKING(what warning flags to pass to the C compiler) + AC_MSG_RESULT($warning_cflags) + + AC_MSG_CHECKING(what warning flags to pass to the C compiler for Vala built sources) + AC_MSG_RESULT($warning_valaflags) + + WARN_CFLAGS="$warning_cflags" + AC_SUBST(WARN_CFLAGS) + + WARN_VALACFLAGS="$warning_valaflags" + AC_SUBST(WARN_VALACFLAGS) +]) dnl IDT_COMPILE_WARNINGS + + + +dnl Stolen from https://git.gnome.org/browse/glib/tree/m4macros/glibtests.m4 + +dnl GLIB_TESTS +dnl + +AC_DEFUN([GLIB_TESTS], +[ + AC_ARG_ENABLE(installed-tests, + AS_HELP_STRING([--enable-installed-tests], + [Enable installation of some test cases]), + [case ${enableval} in + yes) ENABLE_INSTALLED_TESTS="1" ;; + no) ENABLE_INSTALLED_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-installed-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], test "$ENABLE_INSTALLED_TESTS" = "1") + AC_ARG_ENABLE(always-build-tests, + AS_HELP_STRING([--enable-always-build-tests], + [Enable always building tests during 'make all']), + [case ${enableval} in + yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;; + no) ENABLE_ALWAYS_BUILD_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-always-build-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_ALWAYS_BUILD_TESTS], test "$ENABLE_ALWAYS_BUILD_TESTS" = "1") + if test "$ENABLE_INSTALLED_TESTS" = "1"; then + AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME) + AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME) + fi +]) diff --git a/tests/LanedoIconHKS43-64².png b/tests/LanedoIconHKS43-64².png Binary files differdeleted file mode 100644 index b5261a7..0000000 --- a/tests/LanedoIconHKS43-64².png +++ /dev/null diff --git a/tests/mediaarttest.c b/tests/mediaarttest.c index 3690335..09cc1ae 100644 --- a/tests/mediaarttest.c +++ b/tests/mediaarttest.c @@ -76,9 +76,17 @@ struct { }; static void -test_mediaart_init (void) +test_mediaart_new (void) { - g_assert_true (media_art_init ()); + 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 @@ -97,11 +105,6 @@ test_mediaart_stripping (void) } static void -test_mediaart_stripping_null (void) -{ -} - -static void test_mediaart_stripping_failures_subprocess (void) { g_assert (!media_art_strip_invalid_entities (NULL)); @@ -150,8 +153,6 @@ test_mediaart_location (void) g_free (local_uri); } g_print ("(%d test cases) ", i); - - } static void @@ -160,8 +161,13 @@ test_mediaart_location_null (void) gchar *path = NULL, *local_uri = NULL; /* NULL parameters */ - media_art_get_path (NULL, NULL, "album", "file:///a/b/c.mp3", &path, &local_uri); - g_assert (!path && !local_uri); + 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); } static void @@ -192,35 +198,41 @@ test_mediaart_location_path (void) static void test_mediaart_embedded_mp3 (void) { + MediaArtProcess *process; GError *error = NULL; GFile *file = NULL; gchar *dir, *path; gboolean retval; - /* FIXME: Handle 'buffer' AND 'file/path', is broken currently */ - dir = g_get_current_dir (); path = g_build_filename (G_DIR_SEPARATOR_S, dir, "543249_King-Kilo---Radium.mp3", NULL); file = g_file_new_for_path (path); g_free (path); - retval = media_art_process_file (NULL, - 0, - "audio/mp3", /* mime */ + 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 */ - "Lanedo", /* title */ - file); + "Radium", /* title */ + &error); + g_assert_no_error (error); g_assert_true (retval); g_object_unref (file); g_free (dir); + + g_object_unref (process); } static void -test_mediaart_png (void) +test_mediaart_process_buffer (void) { + MediaArtProcess *process; GError *error = NULL; GFile *file = NULL; gchar *dir, *path; @@ -230,14 +242,17 @@ test_mediaart_png (void) gboolean retval; dir = g_get_current_dir (); - path = g_build_filename (G_DIR_SEPARATOR_S, dir, "LanedoIconHKS43-64².png", NULL); + path = g_build_filename (G_DIR_SEPARATOR_S, dir, "cover.png", NULL); file = g_file_new_for_path (path); g_free (dir); + process = media_art_process_new (&error); + g_assert_no_error (error); + /* Check data is not cached currently */ media_art_get_path ("Lanedo", /* artist / title */ - NULL, /* album */ - NULL, /* prefix */ + NULL, /* album */ + NULL, /* prefix */ path, &out_path, &out_uri); @@ -246,20 +261,20 @@ test_mediaart_png (void) g_free (out_uri); /* Process data */ - retval = media_art_process_file (NULL, - 0, - "image/png", /* mime */ + retval = media_art_process_file (process, MEDIA_ART_ALBUM, - NULL, /* album */ - "Lanedo", /* title */ - file); - + MEDIA_ART_PROCESS_FLAGS_NONE, + file, + NULL, /* album */ + "Lanedo", /* title */ + &error); + g_assert_no_error (error); g_assert_true (retval); /* Check cache exists */ media_art_get_path ("Lanedo", /* artist / title */ - NULL, /* album */ - NULL, /* prefix */ + NULL, /* album */ + NULL, /* prefix */ path, &out_path, &out_uri); @@ -274,7 +289,7 @@ test_mediaart_png (void) /* 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_assert (g_file_test (out_path, G_FILE_TEST_EXISTS) == TRUE); g_free (out_path); g_free (out_uri); @@ -288,6 +303,70 @@ test_mediaart_png (void) g_object_unref (file); g_free (path); + + g_object_unref (process); +} + +static void +test_mediaart_process_failures (void) +{ + MediaArtProcess *process; + GError *error = NULL; + + 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*"); + + process = media_art_process_new (&error); + 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); + + /* Test: Invalid mime type */ + /* g_assert (!media_art_process_uri (process, */ + /* "file:///invalid/path.png", */ + /* NULL, */ + /* 0, */ + /* "image/png", /\* mime *\/ */ + /* MEDIA_ART_ALBUM, */ + /* "Foo", /\* album *\/ */ + /* "Bar", /\* title *\/ */ + /* &error)); */ + + /* g_message ("code:%d, domain:%d, error:'%s'\n", error->code, error->domain, error->message); */ + + g_object_unref (process); +} + +static void +test_mediaart_process_failures_subprocess (void) +{ + MediaArtProcess *process; + GError *error = NULL; + + process = media_art_process_new (&error); + g_assert_no_error (error); + + g_assert (!media_art_process_uri (process, + MEDIA_ART_ALBUM, + MEDIA_ART_PROCESS_FLAGS_NONE, + NULL, + "Foo", /* album */ + "Bar", /* title */ + &error)); + g_assert_no_error (error); + + g_object_unref (process); } int @@ -297,8 +376,8 @@ main (int argc, char **argv) g_test_init (&argc, &argv, NULL); - g_test_add_func ("/mediaart/init", - test_mediaart_init); + g_test_add_func ("/mediaart/new", + test_mediaart_new); g_test_add_func ("/mediaart/stripping", test_mediaart_stripping); g_test_add_func ("/mediaart/stripping_failures", @@ -313,12 +392,14 @@ main (int argc, char **argv) test_mediaart_location_path); g_test_add_func ("/mediaart/embedded_mp3", test_mediaart_embedded_mp3); - g_test_add_func ("/mediaart/png", - test_mediaart_png); + 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 (); - media_art_shutdown (); - return success; } |