[gnome-music] albumartcache: Lookup embedded/local cover art



commit 38320cd8176a508c7f3ccf57b18c45fbba7b66b8
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sat Mar 4 17:54:39 2017 +0100

    albumartcache: Lookup embedded/local cover art
    
    This behavior is similar in result to what gnome-music used to obtained
    from Tracker albumart management, if the albumart cache file does not
    exist, it will first lookup embedded, then local images.
    
    If none of those exist, the Grilo lookup paths will kick in as it used
    to do.
    
    As we now need an URI to pull embedded albumart from, the "all albums"
    query will now return one of the songs from the album.
    
    Bump libmediaart version to contain a gir fix.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=779584

 configure.ac                |    2 +-
 gnomemusic/albumartcache.py |  107 +++++++++++++++++++++++++++++++++++++++++--
 gnomemusic/query.py         |    1 +
 3 files changed, 105 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index b52ccff..03b166e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,7 +33,7 @@ GLIB_GSETTINGS
 AX_REQUIRE_DEFINED([GOBJECT_INTROSPECTION_CHECK])
 GOBJECT_INTROSPECTION_CHECK([1.35.9])
 PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.19.3])
-PKG_CHECK_MODULES(MEDIAART, [libmediaart-2.0])
+PKG_CHECK_MODULES([MEDIAART], [libmediaart-2.0 >= 1.9.1])
 
 PYGOBJECT_MIN_VERSION=3.21.1
 PKG_CHECK_MODULES(PYGOBJECT, [pygobject-3.0 >= $PYGOBJECT_MIN_VERSION])
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index eae2927..f891336 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -36,7 +36,8 @@ import cairo
 from gettext import gettext as _
 import gi
 gi.require_version('MediaArt', '2.0')
-from gi.repository import Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk, MediaArt
+from gi.repository import (Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk, MediaArt,
+                           Gst, GstTag, GstPbutils)
 
 from gnomemusic import log
 from gnomemusic.grilo import grilo
@@ -186,8 +187,11 @@ class DefaultIcon(GObject.GObject):
 class AlbumArtCache(GObject.GObject):
     """Album art retrieval class
 
-    On basis of a given media item looks up album art locally and if
-    not found remotely.
+    On basis of a given media item looks up album art in the following order:
+    1) already existing in cache
+    2) from embedded images
+    3) from local images
+    3) remotely
     """
     _instance = None
     blacklist = {}
@@ -209,6 +213,19 @@ class AlbumArtCache(GObject.GObject):
                 logger.warn("Error: %s, %s", err.__class__, err)
                 return
 
+        Gst.init(None)
+        self._discoverer = GstPbutils.Discoverer.new(Gst.SECOND)
+        self._discoverer.connect('discovered', self._discovered_cb)
+        self._discoverer.start()
+
+        self._discoverer_items = {}
+
+        self._media_art = None
+        try:
+            self._media_art = MediaArt.Process.new()
+        except Exception as err:
+            logger.warn("Error: %s, %s", err.__class__, err)
+
     @log
     def lookup(self, item, art_size, callback, itr):
         """Find art for the given item
@@ -223,7 +240,7 @@ class AlbumArtCache(GObject.GObject):
     @log
     def _lookup_local(self, item, callback, itr, art_size):
         """Checks if there is already a local art file, if not calls
-        the remote lookup function"""
+        the embedded lookup function"""
         album = utils.get_album_title(item)
         artist = utils.get_artist_name(item)
 
@@ -281,9 +298,91 @@ class AlbumArtCache(GObject.GObject):
             do_callback(None)
             return
 
+        self._lookup_embedded(item, callback, itr, art_size)
+
+    @log
+    def _discovered_cb(self, discoverer, info, error):
+        item, callback, itr, art_size, cache_path = \
+            self._discoverer_items[info.get_uri()]
+
+        album = utils.get_album_title(item)
+        artist = utils.get_artist_name(item)
+        tags = info.get_tags()
+        index = 0
+
+        def art_retrieved(result):
+            if not result:
+                if artist not in self.blacklist:
+                    self.blacklist[artist] = []
+
+                album_stripped = MediaArt.strip_invalid_entities(album)
+                self.blacklist[artist].append(album_stripped)
+
+            self.lookup(item, art_size, callback, itr)
+
+        if error is not None:
+            art_retrieved(False)
+            return
+
+        while True:
+            success, sample = tags.get_sample_index(Gst.TAG_IMAGE, index)
+            if not success:
+                break
+            index += 1
+            struct = sample.get_info()
+            success, image_type = struct.get_enum('image-type',
+                                                  GstTag.TagImageType)
+            if not success:
+                continue
+            if image_type != GstTag.TagImageType.FRONT_COVER:
+                continue
+
+            buf = sample.get_buffer()
+            success, map_info = buf.map(Gst.MapFlags.READ)
+            if not success:
+                continue
+
+            try:
+                mime = sample.get_caps().get_structure(0).get_name()
+                MediaArt.buffer_to_jpeg(map_info.data, mime, cache_path)
+                art_retrieved(True)
+                return
+            except Exception as err:
+                logger.warn("Error: %s, %s", err.__class__, err)
+
+        try:
+            self._media_art.uri(MediaArt.Type.ALBUM,
+                                MediaArt.ProcessFlags.NONE, item.get_url(),
+                                artist, album, None)
+            if os.path.exists(cache_path):
+                art_retrieved(True)
+                return
+        except Exception as err:
+            logger.warn("Trying to process misc albumart: %s, %s",
+                        err.__class__, err)
+
         self._lookup_remote(item, callback, itr, art_size)
 
     @log
+    def _lookup_embedded(self, item, callback, itr, art_size):
+        """Lookup embedded cover
+
+        Lookup embedded art through Gst.Discoverer. If found
+        copy locally and call _lookup_local to finish retrieving
+        suitable art, otherwise follow up with _lookup_remote.
+        """
+        album = utils.get_album_title(item)
+        artist = utils.get_artist_name(item)
+
+        success, cache_path = MediaArt.get_path(artist, album, "album")
+        if not success:
+            self._lookup_remote(item, callback, itr, art_size)
+
+        self._discoverer_items[item.get_url()] = [item, callback, itr,
+                                                  art_size, cache_path]
+        self._discoverer.discover_uri_async(item.get_url())
+
+    @log
     def _lookup_remote(self, item, callback, itr, art_size):
         """Lookup remote art
 
diff --git a/gnomemusic/query.py b/gnomemusic/query.py
index b471d04..e285bae 100644
--- a/gnomemusic/query.py
+++ b/gnomemusic/query.py
@@ -157,6 +157,7 @@ class Query():
         ?title
         COUNT(?song) AS ?childcount
         YEAR(MAX(nie:contentCreated(?song))) AS ?creation_date
+        nie:url(?song) AS ?url
     {
         %(where_clause)s
         ?song a nmm:MusicPiece ;


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