[sushi] cover-art: implement cache for cover art
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [sushi] cover-art: implement cache for cover art
- Date: Thu, 1 Sep 2011 21:37:52 +0000 (UTC)
commit afc5491be24f956c032e85972438c29d570391a5
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Thu Sep 1 17:07:24 2011 -0400
cover-art: implement cache for cover art
https://bugzilla.gnome.org/show_bug.cgi?id=655093
src/libsushi/sushi-cover-art.c | 199 +++++++++++++++++++++++++++++++++++++---
1 files changed, 184 insertions(+), 15 deletions(-)
---
diff --git a/src/libsushi/sushi-cover-art.c b/src/libsushi/sushi-cover-art.c
index 1d8f7c9..c8adc49 100644
--- a/src/libsushi/sushi-cover-art.c
+++ b/src/libsushi/sushi-cover-art.c
@@ -43,6 +43,10 @@ enum {
struct _SushiCoverArtFetcherPrivate {
GdkPixbuf *cover;
GstTagList *taglist;
+
+ gchar *asin;
+ gboolean tried_cache;
+ GInputStream *input_stream;
};
#define AMAZON_IMAGE_FORMAT "http://images.amazon.com/images/P/%s.01.LZZZZZZZ.jpg"
@@ -54,6 +58,8 @@ static void sushi_cover_art_fetcher_get_uri_for_track_async (SushiCoverArtFetche
const gchar *album,
GAsyncReadyCallback callback,
gpointer user_data);
+static void try_read_from_file (SushiCoverArtFetcher *self,
+ GFile *file);
static void
sushi_cover_art_fetcher_dispose (GObject *object)
@@ -61,12 +67,16 @@ sushi_cover_art_fetcher_dispose (GObject *object)
SushiCoverArtFetcherPrivate *priv = SUSHI_COVER_ART_FETCHER_GET_PRIVATE (object);
g_clear_object (&priv->cover);
+ g_clear_object (&priv->input_stream);
if (priv->taglist != NULL) {
gst_tag_list_free (priv->taglist);
priv->taglist = NULL;
}
+ g_free (priv->asin);
+ priv->asin = NULL;
+
G_OBJECT_CLASS (sushi_cover_art_fetcher_parent_class)->dispose (object);
}
@@ -227,7 +237,7 @@ fetch_uri_job (GIOSchedulerJob *sched_job,
if (asin != NULL &&
asin[0] != '\0') {
- retval = g_strdup_printf (AMAZON_IMAGE_FORMAT, asin);
+ retval = g_strdup (asin);
break;
}
}
@@ -283,6 +293,92 @@ sushi_cover_art_fetcher_get_uri_for_track_async (SushiCoverArtFetcher *self,
G_PRIORITY_DEFAULT, NULL);
}
+static GFile *
+get_gfile_for_amazon (SushiCoverArtFetcher *self)
+{
+ GFile *retval;
+ gchar *uri;
+
+ uri = g_strdup_printf (AMAZON_IMAGE_FORMAT, self->priv->asin);
+ retval = g_file_new_for_uri (uri);
+ g_free (uri);
+
+ return retval;
+}
+
+static GFile *
+get_gfile_for_cache (SushiCoverArtFetcher *self)
+{
+ GFile *retval;
+ gchar *cache_path;
+ gchar *filename, *path;
+
+ cache_path = g_build_filename (g_get_user_cache_dir (),
+ "sushi", NULL);
+ g_mkdir_with_parents (cache_path, 0700);
+
+ filename = g_strdup_printf ("%s.jpg", self->priv->asin);
+ path = g_build_filename (cache_path, filename, NULL);
+ retval = g_file_new_for_path (path);
+
+ g_free (filename);
+ g_free (path);
+ g_free (cache_path);
+
+ return retval;
+}
+
+static void
+cache_splice_ready_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
+ res, &error);
+
+ if (error != NULL) {
+ g_warning ("Can't save the cover art image in the cache: %s\n", error->message);
+ g_error_free (error);
+
+ return;
+ }
+}
+
+static void
+cache_replace_ready_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileOutputStream *cache_stream;
+ GError *error = NULL;
+ SushiCoverArtFetcher *self = user_data;
+
+ cache_stream = g_file_replace_finish (G_FILE (source),
+ res, &error);
+
+ if (error != NULL) {
+ g_warning ("Can't save the cover art image in the cache: %s\n", error->message);
+ g_error_free (error);
+
+ return;
+ }
+
+ g_seekable_seek (G_SEEKABLE (self->priv->input_stream), 0, G_SEEK_SET,
+ NULL, NULL);
+
+ g_output_stream_splice_async (G_OUTPUT_STREAM (cache_stream),
+ self->priv->input_stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ cache_splice_ready_cb, self);
+
+ g_object_unref (cache_stream);
+}
+
static void
pixbuf_from_stream_async_cb (GObject *source,
GAsyncResult *res,
@@ -292,42 +388,115 @@ pixbuf_from_stream_async_cb (GObject *source,
SushiCoverArtFetcherPrivate *priv = SUSHI_COVER_ART_FETCHER_GET_PRIVATE (self);
GError *error = NULL;
GdkPixbuf *pix;
+ GFile *file, *cache_file;
pix = gdk_pixbuf_new_from_stream_finish (res, &error);
if (error != NULL) {
- g_print ("Unable to fetch Amazon cover art: %s\n", error->message);
+ if (!self->priv->tried_cache) {
+ self->priv->tried_cache = TRUE;
+
+ file = get_gfile_for_amazon (self);
+ try_read_from_file (self, file);
+
+ g_object_unref (file);
+ } else {
+ g_print ("Unable to fetch Amazon cover art: %s\n", error->message);
+ }
+
g_error_free (error);
return;
}
priv->cover = pix;
g_object_notify (G_OBJECT (self), "cover");
+
+ if (self->priv->tried_cache) {
+ /* the pixbuf has been loaded. if we didn't hit the cache,
+ * save it now.
+ */
+ cache_file = get_gfile_for_cache (self);
+ g_file_replace_async (cache_file,
+ NULL, FALSE,
+ G_FILE_CREATE_PRIVATE,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ cache_replace_ready_cb,
+ self);
+
+ g_object_unref (cache_file);
+ }
}
static void
-asin_uri_read_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+read_async_ready_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
SushiCoverArtFetcher *self = user_data;
SushiCoverArtFetcherPrivate *priv = SUSHI_COVER_ART_FETCHER_GET_PRIVATE (self);
GFileInputStream *stream;
GError *error = NULL;
+ GFile *file;
stream = g_file_read_finish (G_FILE (source),
res, &error);
if (error != NULL) {
- g_print ("Unable to fetch Amazon cover art: %s\n", error->message);
+ if (!self->priv->tried_cache) {
+ self->priv->tried_cache = TRUE;
+
+ file = get_gfile_for_amazon (self);
+ try_read_from_file (self, file);
+
+ g_object_unref (file);
+ } else {
+ g_print ("Unable to fetch Amazon cover art: %s\n", error->message);
+ }
+
g_error_free (error);
return;
}
- gdk_pixbuf_new_from_stream_async (G_INPUT_STREAM (stream), NULL,
+ priv->input_stream = G_INPUT_STREAM (stream);
+ gdk_pixbuf_new_from_stream_async (priv->input_stream, NULL,
pixbuf_from_stream_async_cb, self);
+}
- g_object_unref (stream);
+static void
+try_read_from_file (SushiCoverArtFetcher *self,
+ GFile *file)
+{
+ g_file_read_async (file,
+ G_PRIORITY_DEFAULT, NULL,
+ read_async_ready_cb, self);
+}
+
+static void
+cache_file_query_info_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GFileInfo *cache_info = NULL;
+ SushiCoverArtFetcher *self = user_data;
+ GError *error = NULL;
+ GFile *file;
+
+ cache_info = g_file_query_info_finish (G_FILE (source),
+ res, &error);
+
+ if (error != NULL) {
+ self->priv->tried_cache = TRUE;
+ file = get_gfile_for_amazon (self);
+ g_error_free (error);
+ } else {
+ file = g_object_ref (source);
+ }
+
+ try_read_from_file (self, file);
+
+ g_clear_object (&cache_info);
+ g_object_unref (file);
}
static void
@@ -337,10 +506,9 @@ amazon_cover_uri_async_ready_cb (GObject *source,
{
SushiCoverArtFetcher *self = SUSHI_COVER_ART_FETCHER (source);
GError *error = NULL;
- gchar *asin;
GFile *file;
- asin = sushi_cover_art_fetcher_get_uri_for_track_finish
+ self->priv->asin = sushi_cover_art_fetcher_get_uri_for_track_finish
(self, res, &error);
if (error != NULL) {
@@ -351,13 +519,14 @@ amazon_cover_uri_async_ready_cb (GObject *source,
return;
}
- file = g_file_new_for_uri (asin);
- g_file_read_async (file, G_PRIORITY_DEFAULT,
- NULL, asin_uri_read_cb,
- self);
+ file = get_gfile_for_cache (self);
+ g_file_query_info_async (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT, NULL,
+ cache_file_query_info_cb,
+ self);
g_object_unref (file);
- g_free (asin);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]