[gnome-music/wip/mschraal/core-thumb-property: 12/19] Restore embedded art support



commit ddf5b6b43e751fa5702162c38cc33aa94e0ca67a
Author: Marinus Schraal <mschraal gnome org>
Date:   Sun Jun 14 23:09:36 2020 +0200

    Restore embedded art support

 gnomemusic/albumart.py    |  13 +++-
 gnomemusic/embeddedart.py | 181 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 193 insertions(+), 1 deletion(-)
---
diff --git a/gnomemusic/albumart.py b/gnomemusic/albumart.py
index 84008a35..2d3f14eb 100644
--- a/gnomemusic/albumart.py
+++ b/gnomemusic/albumart.py
@@ -26,6 +26,8 @@ import gi
 gi.require_version("MediaArt", "2.0")
 from gi.repository import GObject, MediaArt
 
+from gnomemusic.embeddedart import EmbeddedArt
+
 
 class AlbumArt(GObject.GObject):
     """AlbumArt retrieval object
@@ -39,6 +41,7 @@ class AlbumArt(GObject.GObject):
         """
         super().__init__()
 
+        self._application = application
         self._corealbum = corealbum
         self._album = self._corealbum.props.title
         self._artist = self._corealbum.props.artist
@@ -46,7 +49,15 @@ class AlbumArt(GObject.GObject):
         if self._in_cache():
             return
 
-        application.props.coregrilo.get_album_art(self._corealbum)
+        embedded = EmbeddedArt()
+        embedded.connect("art-found", self._on_embedded_art_found)
+        embedded.query(corealbum, self._album)
+
+    def _on_embedded_art_found(self, embeddedart, found):
+        if found:
+            self._in_cache()
+        else:
+            self._application.props.coregrilo.get_album_art(self._corealbum)
 
     def _in_cache(self):
         success, thumb_file = MediaArt.get_file(
diff --git a/gnomemusic/embeddedart.py b/gnomemusic/embeddedart.py
new file mode 100644
index 00000000..7ef4f93d
--- /dev/null
+++ b/gnomemusic/embeddedart.py
@@ -0,0 +1,181 @@
+# Copyright 2020 The GNOME Music developers
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music.  This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered.  If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so.  If you do not wish to do so,
+# delete this exception statement from your version.
+
+import gi
+gi.require_versions({"GstPbutils": "1.0", "GstTag": "1.0", "MediaArt": "2.0"})
+from gi.repository import GLib, GObject, MediaArt, Gst, GstTag, GstPbutils
+
+from gnomemusic.musiclogger import MusicLogger
+
+
+class EmbeddedArt(GObject.GObject):
+    """Lookup local art
+
+    1. Embedded art using GStreamer
+    2. Available in the directory using MediaArt
+    """
+
+    _log = MusicLogger()
+
+    __gsignals__ = {
+        "art-found": (GObject.SignalFlags.RUN_FIRST, None, (bool, ))
+    }
+
+    def __init__(self):
+        """Initialize EmbeddedArt
+        """
+        super().__init__()
+
+        try:
+            Gst.init(None)
+            GstPbutils.pb_utils_init()
+        except GLib.Error as error:
+            self._log.warning(
+                "Error: {}, {}".format(error.domain, error.message))
+            return
+
+        self._media_art = MediaArt.Process.new()
+
+        self._album = None
+        self._artist = None
+        self._coreobject = None
+        self._path = None
+
+    def query(self, coreobject, title):
+        """Start the local query
+
+        :param coreobject: The CoreAlbum or CoreSong to search art for
+        :param str title: The album title for the CoreAlbum or CoreSong
+        """
+        self._album = title
+        self._artist = coreobject.props.artist
+        self._coreobject = coreobject
+
+        try:
+            if coreobject.props.url is None:
+                self.emit("art-found", False)
+                return
+        except AttributeError:
+            self.emit("art-found", False)
+            return
+
+        try:
+            discoverer = GstPbutils.Discoverer.new(Gst.SECOND)
+        except GLib.Error as error:
+            self._log.warning(
+                "Error: {}, {}".format(error.domain, error.message))
+            self._lookup_cover_in_directory()
+            return
+
+        discoverer.connect("discovered", self._discovered)
+        discoverer.start()
+
+        success, path = MediaArt.get_path(self._artist, self._album, "album")
+
+        if not success:
+            self.emit("art-found", False)
+            discoverer.stop()
+            return
+
+        self._path = path
+
+        success = discoverer.discover_uri_async(self._coreobject.props.url)
+
+        if not success:
+            self._log.warning("Could not add url to discoverer.")
+            self.emit("art-found", False)
+            discoverer.stop()
+            return
+
+    def _discovered(self, discoverer, info, error):
+        tags = info.get_tags()
+        index = 0
+
+        if (error is not None
+                or tags is None):
+            if error:
+                self._log.warning("Discoverer error: {}, {}".format(
+                    Gst.CoreError(error.code), error.message))
+            discoverer.stop()
+            self.emit("art-found", False)
+            return
+
+        while True:
+            success, sample = tags.get_sample_index(Gst.TAG_IMAGE, index)
+            if not success:
+                break
+            index += 1
+            struct = sample.get_info()
+            if struct is None:
+                break
+            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, self._path)
+                discoverer.stop()
+                self.emit("art-found", True)
+                return
+            except GLib.Error as error:
+                self._log.warning("Error: {}, {}".format(
+                    MediaArt.Error(error.code), error.message))
+
+        discoverer.stop()
+
+        self._lookup_cover_in_directory()
+
+    def _lookup_cover_in_directory(self):
+        # Find local art in cover.jpeg files.
+        self._media_art.uri_async(
+            MediaArt.Type.ALBUM, MediaArt.ProcessFlags.NONE,
+            self._coreobject.props.url, self._artist, self._album,
+            GLib.PRIORITY_LOW, None, self._uri_async_cb, None)
+
+    def _uri_async_cb(self, src, result, data):
+        try:
+            success = self._media_art.uri_finish(result)
+            if success:
+                self.emit("art-found", True)
+                return
+        except GLib.Error as error:
+            if MediaArt.Error(error.code) == MediaArt.Error.SYMLINK_FAILED:
+                # This error indicates that the coverart has already
+                # been linked by another concurrent lookup.
+                self.emit("art-found", True)
+                return
+            else:
+                self._log.warning("Error: {}, {}".format(
+                    MediaArt.Error(error.code), error.message))
+
+        self.emit("art-found", False)


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