[gnome-music] AlbumArtCache: cleanup the public interface and correct the filenames



commit 2c931967a4b58ce0c85bcf0056c53d5dee6111b3
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sun Jun 16 02:43:32 2013 +0200

    AlbumArtCache: cleanup the public interface and correct the filenames
    
    Almost always, the user of AlbumArtCache wants to lookup the image
    in cache or trigger a resolve operation and fetch from the network.
    Also, sometimes the API user is interested in the cached path too
    (for example to send to another app).
    Naturally, for that to work we need to ensure that PNG thumbnails
    end up with .png, not .jpeg. For us it works because we use
    gdk_pixbuf_new_from_stream(), which uses sniffing exclusively.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=702377

 src/albumArtCache.js |  102 +++++++++++++++++++++++++++++++++++++------------
 src/view.js          |   46 ++++------------------
 2 files changed, 86 insertions(+), 62 deletions(-)
---
diff --git a/src/albumArtCache.js b/src/albumArtCache.js
index 91e906f..87c7652 100644
--- a/src/albumArtCache.js
+++ b/src/albumArtCache.js
@@ -29,6 +29,9 @@ const Regex = GLib.Regex;
 const Path = GLib.Path;
 const Grl = imports.gi.Grl;
 
+const Grilo = imports.grilo;
+const grilo = Grilo.grilo;
+
 const InvalidChars = /[()<>\[\]{}_! #$^&*+=|\\\/\"'?~]/g;
 const ReduceSpaces = /\t|\s+/g;
 
@@ -52,16 +55,19 @@ const AlbumArtCache = new Lang.Class({
         }
     },
 
-    _tryLoad: function(size, artist, album, i, callback) {
+    _tryLoad: function(size, artist, album, i, format, callback) {
         var key, path, file;
 
         if (i >= this._keybuilder_funcs.length) {
-            callback(null);
+            if (format == 'jpeg')
+                this._tryLoad(size, artist, album, 0, 'png', callback);
+            else
+                callback(null);
             return;
         }
 
         key = this._keybuilder_funcs[i].call(this, artist, album);
-        path = GLib.build_filenamev([this.cacheDir, key + ".jpeg"]);
+        path = GLib.build_filenamev([this.cacheDir, key + '.' + format]);
         file = Gio.File.new_for_path(path);
 
         file.read_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this,
@@ -76,7 +82,7 @@ const AlbumArtCache = new Lang.Class({
                                     height = pixbuf.get_height();
                                 if (width >= size || height >= size) {
                                     let scale = Math.max(width, height)/size;
-                                    callback(pixbuf.scale_simple(width/scale, height/scale, 2));
+                                    callback(pixbuf.scale_simple(width/scale, height/scale, 2), path);
 
                                     return;
                                 }
@@ -86,7 +92,7 @@ const AlbumArtCache = new Lang.Class({
                                     print ("ERROR:", error);
                             }
 
-                            this._tryLoad(size, artist, album, ++i, callback);
+                            this._tryLoad(size, artist, album, ++i, format, callback);
                         }));
 
                     return;
@@ -96,7 +102,7 @@ const AlbumArtCache = new Lang.Class({
                         print ("ERROR:", error);
                 }
 
-                this._tryLoad(size, artist, album, ++i, callback);
+                this._tryLoad(size, artist, album, ++i, format, callback);
             }));
     },
 
@@ -109,7 +115,40 @@ const AlbumArtCache = new Lang.Class({
             album = " ";
         }
 
-        this._tryLoad(size, artist, album, 0, callback);
+        this._tryLoad(size, artist, album, 0, 'jpeg', callback);
+    },
+
+    lookupOrResolve: function(item, width, height, callback) {
+        let artist = null;
+        if (item.get_author() != null)
+            artist = item.get_author();
+        if (item.get_string(Grl.METADATA_KEY_ARTIST) != null)
+            artist = item.get_string(Grl.METADATA_KEY_ARTIST);
+        let album = item.get_string(Grl.METADATA_KEY_ALBUM);
+
+        this.lookup(height, artist, album, Lang.bind(this, function(icon, path) {
+            if (icon != null) {
+                // Cache the path on the original item for faster retrieval
+                item._thumbnail = path;
+                callback(icon, path);
+                return;
+            }
+
+            let options = Grl.OperationOptions.new(null);
+            options.set_flags(Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY);
+            grilo.tracker.resolve(item, [Grl.METADATA_KEY_THUMBNAIL], options,
+                                  Lang.bind(this, function(source, param, item) {
+                                      let uri = item.get_thumbnail();
+                                      if (!uri)
+                                          return;
+
+                                      this.getFromUri(uri, artist, album, width, height,
+                                                      function(image, path) {
+                                                          item._thumbnail = path;
+                                                          callback(image, path);
+                                                      });
+                                  }));
+        }));
     },
 
     normalizeAndHash: function(input, utf8Only, utf8) {
@@ -153,35 +192,48 @@ const AlbumArtCache = new Lang.Class({
             return;
         }
 
-        let key = this._keybuilder_funcs[0].call(this, artist, album),
-            path = GLib.build_filenamev([
-                this.cacheDir, key + ".jpeg"
-            ]),
-            file = Gio.File.new_for_uri(uri);
+        let key = this._keybuilder_funcs[0].call(this, artist, album);
+        let file = Gio.File.new_for_uri(uri);
 
-        print("missing", album, artist);
-
-        file.read_async(300, null, Lang.bind(this, function(source, res, user_data) {
+        file.read_async(300, null, Lang.bind(this, function(source, res) {
             try {
                 let stream = file.read_finish(res);
-                let new_file = Gio.File.new_for_path(path);
+                let path = GLib.build_filenamev([this.cacheDir, key]);
 
-                if (new_file.query_exists(null)) {
-                    new_file.delete(null);
-                    new_file = Gio.File.new_for_path(path);
+                try {
+                    let streamInfo = stream.query_info('standard::content-type', null);
+                    let contentType = streamInfo.get_content_type();
+
+                    if (contentType == 'image/png') {
+                        path += '.png';
+                    } else if (contentType == 'image/jpeg') {
+                        path += '.jpeg';
+                    } else {
+                        log('Thumbnail is not in a supported format, not caching');
+                        stream.close(null);
+                        return;
+                    }
+                } catch(e) {
+                    log('Failed to query thumbnail content type (%s), assuming JPG'.format(e.message));
+                    path += '.jpeg';
+                    return;
                 }
 
-                new_file.append_to_async(Gio.FileCreateFlags.REPLACE_DESTINATION,
+                let newFile = Gio.File.new_for_path(path);
+
+                newFile.replace_async(null, false, Gio.FileCreateFlags.REPLACE_DESTINATION,
                     300, null, Lang.bind(this, function (new_file, res, error) {
-                    let outstream = new_file.append_to_finish(res);
+                    let outstream = new_file.replace_finish(res);
                     outstream.splice_async(stream, Gio.IOStreamSpliceFlags.NONE, 300, null,
                         Lang.bind(this, function(outstream, res, error) {
                             if (outstream.splice_finish(res) > 0) {
                                for (let i=0; i<this.requested_uris[uri].length; i++) {
-                                  let cb = this.requested_uris[uri][i][0],
-                                      w = this.requested_uris[uri][i][1],
-                                      h = this.requested_uris[uri][i][2];
-                                  cb(GdkPixbuf.Pixbuf.new_from_file_at_scale(path, h, w, true));
+                                   let callback = this.requested_uris[uri][i][0];
+                                   let width = this.requested_uris[uri][i][1];
+                                   let height = this.requested_uris[uri][i][2];
+
+                                   let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, height, width, 
true);
+                                   callback(pixbuf, path);
                                }
                                delete this.requested_uris[uri];
                             }
diff --git a/src/view.js b/src/view.js
index ee4a21d..c6bcb36 100644
--- a/src/view.js
+++ b/src/view.js
@@ -40,7 +40,6 @@ const Toolbar = imports.toolbar;
 const tracker = Tracker.SparqlConnection.get (null);
 const AlbumArtCache = imports.albumArtCache;
 const Grilo = imports.grilo;
-const albumArtCache = AlbumArtCache.AlbumArtCache.getDefault();
 
 const nowPlayingIconName = 'media-playback-start-symbolic';
 const errorIconName = 'dialog-error-symbolic';
@@ -51,6 +50,7 @@ function extractFileName(uri) {
     return unescape(uri.replace(exp, ''));
 }
 
+const albumArtCache = AlbumArtCache.AlbumArtCache.getDefault();
 const grilo = Grilo.grilo;
 
 const ViewContainer = new Lang.Class({
@@ -235,42 +235,14 @@ const ViewContainer = new Lang.Class({
     },
 
     _updateAlbumArt: function(item, iter) {
-        var artist = null;
-        if (item.get_author() != null)
-            artist = item.get_author();
-        if (item.get_string(Grl.METADATA_KEY_ARTIST) != null)
-            artist = item.get_string(Grl.METADATA_KEY_ARTIST)
-        albumArtCache.lookup(this._iconHeight, artist, item.get_string(Grl.METADATA_KEY_ALBUM), 
Lang.bind(this,
-            function(icon) {
-                if (icon != null) {
-                    icon = albumArtCache.makeIconFrame(icon)
-                    this._model.set_value(iter, 4, icon);
-                    this.emit("album-art-updated");
-                }
-                else {
-                    var options = Grl.OperationOptions.new(null);
-                    options.set_flags(Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY);
-                    grilo.tracker.resolve(
-                        item,
-                        [Grl.METADATA_KEY_THUMBNAIL],
-                        options,
-                        Lang.bind(this,
-                        function(source, param, item) {
-                            var uri = item.get_thumbnail();
-                            albumArtCache.getFromUri(uri,
-                                artist,
-                                item.get_string(Grl.METADATA_KEY_ALBUM),
-                                this._iconWidth,
-                                this._iconHeight,
-                                Lang.bind(this,
-                                    function(icon) {
-                                        icon = albumArtCache.makeIconFrame(icon);
-                                        this._model.set_value(iter, 4, icon);
-                                        this.emit("album-art-updated");
-                                    }))
-                        }));
-                }
-            }));
+        albumArtCache.lookupOrResolve(item, this._iconWidth, this._iconHeight, Lang.bind(this, 
function(icon) {
+            if (icon)
+                this._model.set_value(iter, 4, albumArtCache.makeIconFrame(icon));
+            else
+                this._model.set_value(iter, 4, null);
+            this.emit("album-art-updated");
+        }));
+
         return false;
     },
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]