diff options
author | Martyn Russell <martyn@lanedo.com> | 2013-08-15 17:37:14 +0100 |
---|---|---|
committer | Martyn Russell <martyn@lanedo.com> | 2013-08-15 17:37:14 +0100 |
commit | d574933587c2051f2ce8052d107ddee171bd4c8f (patch) | |
tree | b902dae12271085089e703618c84208de4ae3423 /libmediaart/cache.c | |
parent | 034d8ed7cda2d17794ee4a9c8e751ac978898032 (diff) | |
download | libmediaart-d574933587c2051f2ce8052d107ddee171bd4c8f.tar.gz |
libmediaart: Merged utils.[ch] into cache.[ch]
Diffstat (limited to 'libmediaart/cache.c')
-rw-r--r-- | libmediaart/cache.c | 296 |
1 files changed, 293 insertions, 3 deletions
diff --git a/libmediaart/cache.c b/libmediaart/cache.c index da518de..93acd48 100644 --- a/libmediaart/cache.c +++ b/libmediaart/cache.c @@ -19,12 +19,13 @@ #include "config.h" +#include <string.h> + #include <glib.h> #include <glib/gstdio.h> +#include <gio/gio.h> -#include <libtracker-sparql/tracker-sparql.h> - -#include "utils.h" +#include "cache.h" /** * SECTION:cache @@ -33,6 +34,295 @@ * @include: libmediaart/mediaart.h **/ +static gboolean +media_art_strip_find_next_block (const gchar *original, + const gunichar open_char, + const gunichar close_char, + gint *open_pos, + gint *close_pos) +{ + const gchar *p1, *p2; + + if (open_pos) { + *open_pos = -1; + } + + if (close_pos) { + *close_pos = -1; + } + + p1 = g_utf8_strchr (original, -1, open_char); + if (p1) { + if (open_pos) { + *open_pos = p1 - original; + } + + p2 = g_utf8_strchr (g_utf8_next_char (p1), -1, close_char); + if (p2) { + if (close_pos) { + *close_pos = p2 - original; + } + + return TRUE; + } + } + + return FALSE; +} + +/** + * media_art_strip_invalid_entities: + * @original: original string + * + * Strip a albumname or artistname string to prepare it for calculating the + * media art path with it. Certain characters and charactersets will be stripped + * and a newly allocated string returned which you must free with g_free(). + * + * Returns: copy of original but then stripped + * + * Since: 0.2.0 + */ +gchar * +media_art_strip_invalid_entities (const gchar *original) +{ + GString *str_no_blocks; + gchar **strv; + gchar *str; + gboolean blocks_done = FALSE; + const gchar *p; + const gchar *invalid_chars = "()[]<>{}_!@#$^&*+=|\\/\"'?~"; + const gchar *invalid_chars_delimiter = "*"; + const gchar *convert_chars = "\t"; + const gchar *convert_chars_delimiter = " "; + const gunichar blocks[5][2] = { + { '(', ')' }, + { '{', '}' }, + { '[', ']' }, + { '<', '>' }, + { 0, 0 } + }; + + str_no_blocks = g_string_new (""); + + p = original; + + while (!blocks_done) { + gint pos1, pos2, i; + + pos1 = -1; + pos2 = -1; + + for (i = 0; blocks[i][0] != 0; i++) { + gint start, end; + + /* Go through blocks, find the earliest block we can */ + if (media_art_strip_find_next_block (p, blocks[i][0], blocks[i][1], &start, &end)) { + if (pos1 == -1 || start < pos1) { + pos1 = start; + pos2 = end; + } + } + } + + /* If either are -1 we didn't find any */ + if (pos1 == -1) { + /* This means no blocks were found */ + g_string_append (str_no_blocks, p); + blocks_done = TRUE; + } else { + /* Append the test BEFORE the block */ + if (pos1 > 0) { + g_string_append_len (str_no_blocks, p, pos1); + } + + p = g_utf8_next_char (p + pos2); + + /* Do same again for position AFTER block */ + if (*p == '\0') { + blocks_done = TRUE; + } + } + } + + /* Now convert chars to lower case */ + str = g_utf8_strdown (str_no_blocks->str, -1); + g_string_free (str_no_blocks, TRUE); + + /* Now strip invalid chars */ + g_strdelimit (str, invalid_chars, *invalid_chars_delimiter); + strv = g_strsplit (str, invalid_chars_delimiter, -1); + g_free (str); + str = g_strjoinv (NULL, strv); + g_strfreev (strv); + + /* Now convert chars */ + g_strdelimit (str, convert_chars, *convert_chars_delimiter); + strv = g_strsplit (str, convert_chars_delimiter, -1); + g_free (str); + str = g_strjoinv (convert_chars_delimiter, strv); + g_strfreev (strv); + + while (g_strrstr (str, " ") != NULL) { + /* Now remove double spaces */ + strv = g_strsplit (str, " ", -1); + g_free (str); + str = g_strjoinv (" ", strv); + g_strfreev (strv); + } + + /* Now strip leading/trailing white space */ + g_strstrip (str); + + return str; +} + +static gchar * +media_art_checksum_for_data (GChecksumType checksum_type, + const guchar *data, + gsize length) +{ + GChecksum *checksum; + gchar *retval; + + checksum = g_checksum_new (checksum_type); + if (!checksum) { + return NULL; + } + + g_checksum_update (checksum, data, length); + retval = g_strdup (g_checksum_get_string (checksum)); + g_checksum_free (checksum); + + return retval; +} + +/** + * media_art_get_path: + * @artist: the artist + * @title: the title + * @prefix: For example "album" + * @uri: NULL or the uri of the file + * @path: the location to store the local path + * @local_uri: 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(). + * + * Since: 0.2.0 + */ +void +media_art_get_path (const gchar *artist, + const gchar *title, + const gchar *prefix, + const gchar *uri, + gchar **path, + gchar **local_uri) +{ + const gchar *space_checksum = "7215ee9c7d9dc229d2921a40e899ec5f"; + const gchar *a, *b; + + gchar *art_filename; + gchar *dir; + gchar *artist_down, *title_down; + gchar *artist_stripped, *title_stripped; + gchar *artist_norm, *title_norm; + gchar *artist_checksum = NULL, *title_checksum = NULL; + + /* http://live.gnome.org/MediaArtStorageSpec */ + + if (path) { + *path = NULL; + } + + if (local_uri) { + *local_uri = NULL; + } + + if (!artist && !title) { + return; + } + + if (artist) { + artist_stripped = media_art_strip_invalid_entities (artist); + artist_norm = g_utf8_normalize (artist_stripped, -1, G_NORMALIZE_NFKD); + artist_down = g_utf8_strdown (artist_norm, -1); + artist_checksum = media_art_checksum_for_data (G_CHECKSUM_MD5, + (const guchar *) artist_down, + strlen (artist_down)); + } + + if (title) { + title_stripped = media_art_strip_invalid_entities (title); + title_norm = g_utf8_normalize (title_stripped, -1, G_NORMALIZE_NFKD); + title_down = g_utf8_strdown (title_norm, -1); + title_checksum = media_art_checksum_for_data (G_CHECKSUM_MD5, + (const guchar *) title_down, + strlen (title_down)); + } + + dir = g_build_filename (g_get_user_cache_dir (), + "media-art", + NULL); + + if (!g_file_test (dir, G_FILE_TEST_EXISTS)) { + g_mkdir_with_parents (dir, 0770); + } + + if (artist) { + a = artist_checksum; + b = title ? title_checksum : space_checksum; + } else { + a = title_checksum; + b = space_checksum; + } + + art_filename = g_strdup_printf ("%s-%s-%s.jpeg", prefix ? prefix : "album", a, b); + + if (artist) { + g_free (artist_checksum); + g_free (artist_stripped); + g_free (artist_down); + g_free (artist_norm); + } + + if (title) { + g_free (title_checksum); + g_free (title_stripped); + g_free (title_down); + g_free (title_norm); + } + + if (path) { + *path = g_build_filename (dir, art_filename, NULL); + } + + if (local_uri) { + gchar *local_dir; + GFile *file, *parent; + + if (strstr (uri, "://")) { + file = g_file_new_for_uri (uri); + } else { + file = g_file_new_for_path (uri); + } + + parent = g_file_get_parent (file); + if (parent) { + local_dir = g_file_get_uri (parent); + + /* This is a URI, don't use g_build_filename here */ + *local_uri = g_strdup_printf ("%s/.mediaartlocal/%s", local_dir, art_filename); + + g_free (local_dir); + g_object_unref (parent); + } + g_object_unref (file); + } + + g_free (dir); + g_free (art_filename); +} + /** * media_art_remove: * @artist: Artist the media art belongs to |