diff -u rhythmbox-0.11.5/debian/changelog rhythmbox-0.11.5/debian/changelog --- rhythmbox-0.11.5/debian/changelog +++ rhythmbox-0.11.5/debian/changelog @@ -1,3 +1,11 @@ +rhythmbox (0.11.5-5ubuntu3) intrepid; urgency=low + + * debian/patches/07_embedded_cover_art.patch + - Extract embedded album art into ~/.rhythmbox/covers so the cover art + plugin can display it. (lp: #109889) + + -- John Millikin Fri, 13 Jun 2008 19:02:11 -0700 + rhythmbox (0.11.5-5ubuntu2) intrepid; urgency=low * debian/patches/70_from_svn_fix_incorrect_shuffle_detection.patch: only in patch2: unchanged: --- rhythmbox-0.11.5.orig/debian/patches/07_embedded_cover_art.patch +++ rhythmbox-0.11.5/debian/patches/07_embedded_cover_art.patch @@ -0,0 +1,337 @@ +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/bindings/python/rhythmdb.defs rhythmbox-0.11.5.new/bindings/python/rhythmdb.defs +--- rhythmbox-0.11.5/bindings/python/rhythmdb.defs 2008-03-16 03:09:27.000000000 -0700 ++++ rhythmbox-0.11.5.new/bindings/python/rhythmdb.defs 2008-06-13 18:46:20.000000000 -0700 +@@ -153,6 +153,7 @@ + '("prop-copyright" "RHYTHMDB_PROP_COPYRIGHT") + '("prop-image" "RHYTHMDB_PROP_IMAGE") + '("prop-post-time" "RHYTHMDB_PROP_POST_TIME") ++ '("prop-cover-art-uri" "RHYTHMDB_PROP_COVER_ART_URI") + '("num-properties" "RHYTHMDB_NUM_PROPERTIES") + ) + ) +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/metadata/rb-metadata-common.c rhythmbox-0.11.5.new/metadata/rb-metadata-common.c +--- rhythmbox-0.11.5/metadata/rb-metadata-common.c 2008-02-04 01:03:33.000000000 -0800 ++++ rhythmbox-0.11.5.new/metadata/rb-metadata-common.c 2008-06-13 18:46:20.000000000 -0700 +@@ -66,6 +66,7 @@ + /* RB_METADATA_FIELD_MUSICBRAINZ_ALBUMID */ { G_TYPE_STRING, "musicbrainz-albumid" }, + /* RB_METADATA_FIELD_MUSICBRAINZ_ALBUMARTISTID */ { G_TYPE_STRING, "musicbrainz-albumartistid" }, + /* RB_METADATA_FIELD_ARTIST_SORTNAME */ { G_TYPE_STRING, "musicbrainz-sortname" }, ++ /* RB_METADATA_FIELD_COVER_ART_URI */ { G_TYPE_STRING, "cover-art-uri" }, + + }; + +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/metadata/rb-metadata-gst.c rhythmbox-0.11.5.new/metadata/rb-metadata-gst.c +--- rhythmbox-0.11.5/metadata/rb-metadata-gst.c 2008-02-04 01:03:33.000000000 -0800 ++++ rhythmbox-0.11.5.new/metadata/rb-metadata-gst.c 2008-06-13 18:46:20.000000000 -0700 +@@ -590,6 +590,144 @@ + } + } + ++static gchar * ++rb_get_cover_cache_dir (void) ++{ ++ gchar *cache_dir = g_build_filename (rb_dot_dir (), "covers", NULL); ++ if (g_mkdir_with_parents (cache_dir, 0750) == -1) ++ rb_debug ("Unable to create cover art cache directory"); ++ ++ return cache_dir; ++} ++ ++static gchar * ++rb_get_extension_for_mime_type (const gchar *mime_type) ++{ ++ GSList *formats, *f; ++ gchar *extension = NULL; ++ GdkPixbufFormat *format = NULL; ++ ++ formats = gdk_pixbuf_get_formats (); ++ ++ for (f = formats; f != NULL; f = f->next) ++ { ++ GdkPixbufFormat *this_format; ++ gchar *this_type, **mime_types; ++ guint ii; ++ ++ this_format = (GdkPixbufFormat *) (f->data); ++ mime_types = gdk_pixbuf_format_get_mime_types (this_format); ++ ++ for (ii = 0; mime_types[ii] != NULL; ii++) ++ { ++ this_type = mime_types[ii]; ++ if (strcmp (mime_type, this_type) == 0) ++ { ++ format = this_format; ++ break; ++ } ++ } ++ ++ g_strfreev (mime_types); ++ if (format) break; ++ } ++ ++ g_slist_free (formats); ++ ++ if (format) ++ { ++ gchar **extensions; ++ extensions = gdk_pixbuf_format_get_extensions (format); ++ if (extensions[0]) extension = g_strdup (extensions[0]); ++ g_strfreev (extensions); ++ } ++ ++ return extension; ++} ++ ++static gchar * ++rb_cover_art_build_cache_file_name (const gchar *hexdigest, ++ const gchar *mime_type) ++{ ++ gchar *cache_dir, *extension, *without_extension, *file_name; ++ ++ extension = rb_get_extension_for_mime_type (mime_type); ++ g_return_val_if_fail (extension != NULL, NULL); ++ ++ cache_dir = rb_get_cover_cache_dir (); ++ without_extension = g_build_filename (cache_dir, hexdigest, NULL); ++ file_name = g_strdup_printf ("%s.%s", without_extension, extension); ++ g_free (cache_dir); ++ g_free (without_extension); ++ return file_name; ++} ++ ++static void ++rb_metadata_load_gst_image_tag (const GValue *image_value, RBMetaData *md) ++{ ++ gchar *hexdigest, *file_name; ++ const gchar *mime_type; ++ GstStructure *mime_struct; ++ GstBuffer *buffer; ++ ++ /* Retrieve image MIME-type, data, and data length */ ++ g_return_if_fail (image_value != NULL); ++ buffer = gst_value_get_buffer (image_value); ++ g_return_if_fail (buffer != NULL); ++ g_return_if_fail (gst_caps_is_fixed (buffer->caps)); ++ ++ mime_struct = gst_caps_get_structure (buffer->caps, 0); ++ mime_type = gst_structure_get_name (mime_struct); ++ ++ if (strcmp (mime_type, "text/uri-list") == 0) ++ { ++ g_hash_table_insert (md->priv->metadata, ++ GINT_TO_POINTER (RB_METADATA_FIELD_COVER_ART_URI), ++ g_strndup ((gchar *)buffer->data, ++ buffer->size)); ++ return; ++ } ++ ++ /* Calculate the checksum of the cover art's contents. This way, ++ * multiple copies of the same art are not cached. ++ **/ ++ hexdigest = g_compute_checksum_for_data (G_CHECKSUM_SHA1, buffer->data, ++ buffer->size); ++ file_name = rb_cover_art_build_cache_file_name (hexdigest, mime_type); ++ g_free (hexdigest); ++ ++ g_return_if_fail (file_name != NULL); ++ ++ if (!g_file_test (file_name, G_FILE_TEST_EXISTS)) ++ { ++ GError *error = NULL; ++ if (!g_file_set_contents (file_name, (gchar *) (buffer->data), ++ buffer->size, &error)) ++ { ++ rb_debug ("Error saving cover art to \"%s\": %s", ++ file_name, error->message); ++ g_error_free (error); ++ g_free (file_name); ++ file_name = NULL; ++ } ++ } ++ ++ if (file_name) ++ { ++ gchar *uri; ++ GValue *newval; ++ ++ uri = gnome_vfs_get_uri_from_local_path (file_name); ++ g_free (file_name); ++ newval = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING); ++ g_value_take_string (newval, uri); ++ g_hash_table_insert (md->priv->metadata, ++ GINT_TO_POINTER (RB_METADATA_FIELD_COVER_ART_URI), ++ newval); ++ rb_debug ("Got cover art URI: %s", g_value_get_string (newval)); ++ } ++} ++ + static void + rb_metadata_gst_load_tag (const GstTagList *list, const gchar *tag, RBMetaData *md) + { +@@ -604,6 +742,17 @@ + if (count < 1) + return; + ++ /* Special case for embedded art. Rather than saving the entire image ++ * in the database, extract it to a file and save the file's URI. ++ **/ ++ if (strcmp (tag, "image") == 0) ++ { ++ const GValue *image_value; ++ image_value = gst_tag_list_get_value_index (list, tag, 0); ++ rb_metadata_load_gst_image_tag (image_value, md); ++ return; ++ } ++ + tem = rb_metadata_gst_tag_to_field (tag); + if (tem < 0) + return; +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/metadata/rb-metadata.h rhythmbox-0.11.5.new/metadata/rb-metadata.h +--- rhythmbox-0.11.5/metadata/rb-metadata.h 2008-02-04 01:03:33.000000000 -0800 ++++ rhythmbox-0.11.5.new/metadata/rb-metadata.h 2008-06-13 18:46:20.000000000 -0700 +@@ -26,7 +26,7 @@ + + G_BEGIN_DECLS + +-#define RB_METADATA_NUM_FIELDS 23 ++#define RB_METADATA_NUM_FIELDS 24 + + typedef enum + { +@@ -61,6 +61,7 @@ + RB_METADATA_FIELD_MUSICBRAINZ_ALBUMID, /* string */ + RB_METADATA_FIELD_MUSICBRAINZ_ALBUMARTISTID, /* string */ + RB_METADATA_FIELD_ARTIST_SORTNAME, /* string */ ++ RB_METADATA_FIELD_COVER_ART_URI, /* string */ + + RB_METADATA_FIELD_LAST /* nothing */ + } RBMetaDataField; +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/plugins/artdisplay/artdisplay/CoverArtDatabase.py rhythmbox-0.11.5.new/plugins/artdisplay/artdisplay/CoverArtDatabase.py +--- rhythmbox-0.11.5/plugins/artdisplay/artdisplay/CoverArtDatabase.py 2008-02-04 01:03:33.000000000 -0800 ++++ rhythmbox-0.11.5.new/plugins/artdisplay/artdisplay/CoverArtDatabase.py 2008-06-13 18:46:20.000000000 -0700 +@@ -130,7 +130,22 @@ + if entry is None: + callback (entry, None, None) + return +- ++ ++ cover_art_uri = db.entry_get (entry, rhythmdb.PROP_COVER_ART_URI) ++ if cover_art_uri: ++ if cover_art_uri.startswith ('file://'): ++ try: ++ local_path = cover_art_uri[len ('file://'):] ++ pixbuf = gtk.gdk.pixbuf_new_from_file (local_path) ++ self.ticket.purge (entry) ++ callback (entry, pixbuf, local_path) ++ return ++ except Exception: ++ print 'Could not load pixbuf from specified URI: %s' % cover_art_uri ++ else: ++ self.set_pixbuf_from_uri (db, entry, st_cover_art, callback) ++ return ++ + st_artist = db.entry_get (entry, rhythmdb.PROP_ARTIST) or _("Unknown") + st_album = db.entry_get (entry, rhythmdb.PROP_ALBUM) or _("Unknown") + +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/rhythmdb/rhythmdb.c rhythmbox-0.11.5.new/rhythmdb/rhythmdb.c +--- rhythmbox-0.11.5/rhythmdb/rhythmdb.c 2008-03-14 19:18:22.000000000 -0700 ++++ rhythmbox-0.11.5.new/rhythmdb/rhythmdb.c 2008-06-13 18:46:20.000000000 -0700 +@@ -1224,6 +1224,7 @@ + ret->musicbrainz_albumartistid = rb_refstring_ref (db->priv->empty_string); + ret->artist_sortname = rb_refstring_ref (db->priv->empty_string); + ret->mimetype = rb_refstring_ref (db->priv->octet_stream_str); ++ ret->cover_art_uri = rb_refstring_ref (db->priv->empty_string); + + ret->flags |= RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY | + RHYTHMDB_ENTRY_FIRST_SEEN_DIRTY | +@@ -1403,6 +1404,7 @@ + rb_refstring_unref (entry->musicbrainz_albumartistid); + rb_refstring_unref (entry->artist_sortname); + rb_refstring_unref (entry->mimetype); ++ rb_refstring_unref (entry->cover_art_uri); + + g_free (entry); + } +@@ -1664,6 +1666,16 @@ + RHYTHMDB_PROP_ALBUM_PEAK, &val); + g_value_unset (&val); + } ++ ++ /* Cover art URI */ ++ if (rb_metadata_get (metadata, ++ RB_METADATA_FIELD_COVER_ART_URI, ++ &val)) ++ { ++ rhythmdb_entry_set_internal (db, entry, TRUE, ++ RHYTHMDB_PROP_COVER_ART_URI, &val); ++ g_value_unset (&val); ++ } + } + + static gboolean +@@ -3117,6 +3129,12 @@ + g_assert (podcast); + podcast->post_time = g_value_get_ulong (value); + break; ++ case RHYTHMDB_PROP_COVER_ART_URI: ++ if (entry->cover_art_uri != NULL) { ++ rb_refstring_unref (entry->cover_art_uri); ++ } ++ entry->cover_art_uri = rb_refstring_new (g_value_get_string (value)); ++ break; + case RHYTHMDB_NUM_PROPERTIES: + g_assert_not_reached (); + break; +@@ -3900,6 +3918,7 @@ + ENUM_ENTRY (RHYTHMDB_PROP_POST_TIME, "Podcast time of post (gulong) [post-time]"), + + ENUM_ENTRY (RHYTHMDB_PROP_KEYWORD, "Keywords applied to track (gchararray) [keyword]"), ++ ENUM_ENTRY (RHYTHMDB_PROP_COVER_ART_URI, "URI to this track's album cover art (gchararray) [cover-art-uri]"), + { 0, 0, 0 } + }; + g_assert ((sizeof (values) / sizeof (values[0]) - 1) == RHYTHMDB_NUM_PROPERTIES); +@@ -4641,6 +4660,8 @@ + return rb_refstring_get (entry->first_seen_str); + case RHYTHMDB_PROP_LAST_SEEN_STR: + return rb_refstring_get (entry->last_seen_str); ++ case RHYTHMDB_PROP_COVER_ART_URI: ++ return rb_refstring_get (entry->cover_art_uri); + + /* synthetic properties */ + case RHYTHMDB_PROP_SEARCH_MATCH: +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/rhythmdb/rhythmdb.h rhythmbox-0.11.5.new/rhythmdb/rhythmdb.h +--- rhythmbox-0.11.5/rhythmdb/rhythmdb.h 2008-02-04 01:03:31.000000000 -0800 ++++ rhythmbox-0.11.5.new/rhythmdb/rhythmdb.h 2008-06-13 18:46:20.000000000 -0700 +@@ -204,6 +204,8 @@ + RHYTHMDB_PROP_MUSICBRAINZ_ALBUMARTISTID, + RHYTHMDB_PROP_ARTIST_SORTNAME, + ++ RHYTHMDB_PROP_COVER_ART_URI, ++ + RHYTHMDB_NUM_PROPERTIES + } RhythmDBPropType; + +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/rhythmdb/rhythmdb-private.h rhythmbox-0.11.5.new/rhythmdb/rhythmdb-private.h +--- rhythmbox-0.11.5/rhythmdb/rhythmdb-private.h 2008-02-04 01:03:31.000000000 -0800 ++++ rhythmbox-0.11.5.new/rhythmdb/rhythmdb-private.h 2008-06-13 18:46:20.000000000 -0700 +@@ -87,6 +87,7 @@ + RBRefString *musicbrainz_albumid; + RBRefString *musicbrainz_albumartistid; + RBRefString *artist_sortname; ++ RBRefString *cover_art_uri; + gulong tracknum; + gulong discnum; + gulong duration; +diff -Nur -x '*.orig' -x '*~' rhythmbox-0.11.5/rhythmdb/rhythmdb-tree.c rhythmbox-0.11.5.new/rhythmdb/rhythmdb-tree.c +--- rhythmbox-0.11.5/rhythmdb/rhythmdb-tree.c 2008-02-04 01:03:31.000000000 -0800 ++++ rhythmbox-0.11.5.new/rhythmdb/rhythmdb-tree.c 2008-06-13 18:46:20.000000000 -0700 +@@ -1047,6 +1047,9 @@ + + g_list_free (keywords); + break; ++ case RHYTHMDB_PROP_COVER_ART_URI: ++ save_entry_string(ctx, elt_name, rb_refstring_get (entry->cover_art_uri)); ++ break; + case RHYTHMDB_PROP_TITLE_SORT_KEY: + case RHYTHMDB_PROP_GENRE_SORT_KEY: + case RHYTHMDB_PROP_ARTIST_SORT_KEY: