[gnome-music/wip/mschraal/searchview-rework: 12/15] split artist art out & fix round art
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/searchview-rework: 12/15] split artist art out & fix round art
- Date: Sat, 3 Aug 2019 10:29:29 +0000 (UTC)
commit 6122048f5a8ddfaf83093b1a13b5c5d343e97f8d
Author: Marinus Schraal <mschraal gnome org>
Date: Fri Aug 2 22:18:44 2019 +0200
split artist art out & fix round art
gnomemusic/albumartcache.py | 204 --------------------------
gnomemusic/artistart.py | 268 +++++++++++++++++++++++++++++++++++
gnomemusic/coreartist.py | 2 +-
gnomemusic/widgets/artistartstack.py | 3 +-
4 files changed, 271 insertions(+), 206 deletions(-)
---
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index b1c6a069..ec7ca541 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -166,210 +166,6 @@ class DefaultIcon(GObject.GObject):
return self._cache[(icon_type, art_size, scale)]
-class ArtistArt(GObject.GObject):
-
- def __init__(self, coreartist):
- super().__init__()
-
- self._coreartist = coreartist
- self._artist = self._coreartist.props.artist
-
- if self._in_cache():
- print("In cache!")
- return
-
- # FIXME: Ugly.
- grilo = self._coreartist._coremodel._grilo
-
- self._coreartist.connect(
- "notify::thumbnail", self._on_thumbnail_changed)
-
- grilo.get_artist_art(self._coreartist)
-
- def _in_cache(self):
- success, thumb_file = MediaArt.get_file(
- self._artist, None, "artist")
- if (not success
- or not thumb_file.query_exists()):
- return False
-
- print("setting cached uri")
- self._coreartist.props.cached_thumbnail_uri = thumb_file.get_path()
-
- return True
-
- def _on_thumbnail_changed(self, coreartist, thumbnail):
- uri = coreartist.props.thumbnail
- print("ArtistArt", uri)
-
- if (uri is None
- or uri == ""):
- return
-
- src = Gio.File.new_for_uri(uri)
- src.read_async(
- GLib.PRIORITY_LOW, None, self._read_callback, None)
-
- def _read_callback(self, src, result, data):
- try:
- istream = src.read_finish(result)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- return
-
- try:
- [tmp_file, iostream] = Gio.File.new_tmp()
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- return
-
- ostream = iostream.get_output_stream()
- # FIXME: Passing the iostream here, otherwise it gets
- # closed. PyGI specific issue?
- ostream.splice_async(
- istream, Gio.OutputStreamSpliceFlags.CLOSE_SOURCE
- | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, GLib.PRIORITY_LOW,
- None, self._splice_callback, [tmp_file, iostream])
-
- def _delete_callback(self, src, result, data):
- try:
- src.delete_finish(result)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
-
- def _splice_callback(self, src, result, data):
- tmp_file, iostream = data
-
- iostream.close_async(
- GLib.PRIORITY_LOW, None, self._close_iostream_callback, None)
-
- try:
- src.splice_finish(result)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- return
-
- success, cache_path = MediaArt.get_path(self._artist, None, "artist")
-
- if not success:
- return
-
- try:
- # FIXME: I/O blocking
- MediaArt.file_to_jpeg(tmp_file.get_path(), cache_path)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- return
-
- self._in_cache()
-
- tmp_file.delete_async(
- GLib.PRIORITY_LOW, None, self._delete_callback, None)
-
- def _close_iostream_callback(self, src, result, data):
- try:
- src.close_finish(result)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
-
-
-class ArtistCache(GObject.GObject):
- """Handles retrieval of MediaArt cache art
-
- Uses signals to indicate success or failure.
- """
-
- __gtype_name__ = "ArtistCache"
-
- __gsignals__ = {
- 'miss': (GObject.SignalFlags.RUN_FIRST, None, ()),
- 'hit': (GObject.SignalFlags.RUN_FIRST, None, (object, ))
- }
-
- def __repr__(self):
- return "<ArtistCache>"
-
- @log
- def __init__(self):
- super().__init__()
-
- # FIXME
- self._size = Art.Size.MEDIUM
- self._scale = 1
-
- # FIXME: async
- self.cache_dir = os.path.join(GLib.get_user_cache_dir(), 'media-art')
- if not os.path.exists(self.cache_dir):
- try:
- Gio.file_new_for_path(self.cache_dir).make_directory(None)
- except GLib.Error as error:
- logger.warning(
- "Error: {}, {}".format(error.domain, error.message))
- return
-
- @log
- def query(self, coreartist):
- """Start the cache query
-
- :param CoreSong coresong: The CoreSong object to search art for
- """
- print("query")
- thumb_file = Gio.File.new_for_path(
- coreartist.props.cached_thumbnail_uri)
- if thumb_file:
- thumb_file.read_async(
- GLib.PRIORITY_LOW, None, self._open_stream, None)
- return
-
- self.emit('miss')
-
- @log
- def _open_stream(self, thumb_file, result, arguments):
- try:
- stream = thumb_file.read_finish(result)
- except GLib.Error as error:
- print("hier")
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- self.emit('miss')
- return
-
- GdkPixbuf.Pixbuf.new_from_stream_async(
- stream, None, self._pixbuf_loaded, None)
-
- @log
- def _pixbuf_loaded(self, stream, result, data):
- try:
- pixbuf = GdkPixbuf.Pixbuf.new_from_stream_finish(result)
- except GLib.Error as error:
- print("hm")
- logger.warning("Error: {}, {}".format(error.domain, error.message))
- self.emit('miss')
- return
-
- stream.close_async(GLib.PRIORITY_LOW, None, self._close_stream, None)
-
- surface = Gdk.cairo_surface_create_from_pixbuf(
- pixbuf, self._scale, None)
- surface = _make_icon_frame(surface, self._size, self._scale)
-
- self.emit("hit", surface)
-
- @log
- def _close_stream(self, stream, result, data):
- try:
- stream.close_finish(result)
- except GLib.Error as error:
- logger.warning("Error: {}, {}".format(error.domain, error.message))
-
- def _cache_hit(self, klass, pixbuf):
- surface = Gdk.cairo_surface_create_from_pixbuf(
- pixbuf, self._scale, None)
- surface = _make_icon_frame(surface, self._size, self._scale)
- self._surface = surface
-
- self.emit('finished')
-
-
class Art(GObject.GObject):
"""Retrieves art for an album or song
diff --git a/gnomemusic/artistart.py b/gnomemusic/artistart.py
new file mode 100644
index 00000000..ff9049fa
--- /dev/null
+++ b/gnomemusic/artistart.py
@@ -0,0 +1,268 @@
+# Copyright 2019 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.
+
+from enum import Enum
+import logging
+from math import pi
+import os
+
+import cairo
+import gi
+gi.require_version("MediaArt", "2.0")
+from gi.repository import Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk, MediaArt
+
+from gnomemusic.albumartcache import Art
+
+
+def _make_icon_frame(icon_surface, art_size=None, scale=1, default_icon=False):
+ icon_w = icon_surface.get_width()
+ icon_h = icon_surface.get_height()
+ ratio = icon_h / icon_w
+
+ # scale = 2
+ # Scale down the image according to the biggest axis
+ if ratio > 1:
+ w = int(art_size.width / ratio)
+ h = art_size.height
+ else:
+ w = art_size.width
+ h = int(art_size.height * ratio)
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w * scale, h * scale)
+ surface.set_device_scale(scale, scale)
+ ctx = cairo.Context(surface)
+
+ ctx.arc(w / 2, h / 2, w / 2, 0, 2 * pi)
+ ctx.clip()
+
+ matrix = cairo.Matrix()
+
+ # if default_icon:
+ # matrix.translate(-w * (1 / 3), -h * (1 / 3))
+ # ctx.set_operator(cairo.Operator.DIFFERENCE)
+ # else:
+ matrix.scale(icon_w / w, icon_h / h)
+
+ ctx.set_source_surface(icon_surface, 0, 0)
+ pattern = ctx.get_source()
+ pattern.set_matrix(matrix)
+ ctx.rectangle(0, 0, w, h)
+ ctx.fill()
+
+ return surface
+
+
+class ArtistArt(GObject.GObject):
+
+ def __init__(self, coreartist):
+ super().__init__()
+
+ self._coreartist = coreartist
+ self._artist = self._coreartist.props.artist
+
+ if self._in_cache():
+ print("In cache!")
+ return
+
+ # FIXME: Ugly.
+ grilo = self._coreartist._coremodel._grilo
+
+ self._coreartist.connect(
+ "notify::thumbnail", self._on_thumbnail_changed)
+
+ grilo.get_artist_art(self._coreartist)
+
+ def _in_cache(self):
+ success, thumb_file = MediaArt.get_file(
+ self._artist, None, "artist")
+ if (not success
+ or not thumb_file.query_exists()):
+ return False
+
+ print("setting cached uri")
+ self._coreartist.props.cached_thumbnail_uri = thumb_file.get_path()
+
+ return True
+
+ def _on_thumbnail_changed(self, coreartist, thumbnail):
+ uri = coreartist.props.thumbnail
+ print("ArtistArt", uri)
+
+ if (uri is None
+ or uri == ""):
+ return
+
+ src = Gio.File.new_for_uri(uri)
+ src.read_async(
+ GLib.PRIORITY_LOW, None, self._read_callback, None)
+
+ def _read_callback(self, src, result, data):
+ try:
+ istream = src.read_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ return
+
+ try:
+ [tmp_file, iostream] = Gio.File.new_tmp()
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ return
+
+ ostream = iostream.get_output_stream()
+ # FIXME: Passing the iostream here, otherwise it gets
+ # closed. PyGI specific issue?
+ ostream.splice_async(
+ istream, Gio.OutputStreamSpliceFlags.CLOSE_SOURCE
+ | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, GLib.PRIORITY_LOW,
+ None, self._splice_callback, [tmp_file, iostream])
+
+ def _delete_callback(self, src, result, data):
+ try:
+ src.delete_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+
+ def _splice_callback(self, src, result, data):
+ tmp_file, iostream = data
+
+ iostream.close_async(
+ GLib.PRIORITY_LOW, None, self._close_iostream_callback, None)
+
+ try:
+ src.splice_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ return
+
+ success, cache_path = MediaArt.get_path(self._artist, None, "artist")
+
+ if not success:
+ return
+
+ try:
+ # FIXME: I/O blocking
+ MediaArt.file_to_jpeg(tmp_file.get_path(), cache_path)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ return
+
+ self._in_cache()
+
+ tmp_file.delete_async(
+ GLib.PRIORITY_LOW, None, self._delete_callback, None)
+
+ def _close_iostream_callback(self, src, result, data):
+ try:
+ src.close_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+
+
+class ArtistCache(GObject.GObject):
+ """Handles retrieval of MediaArt cache art
+
+ Uses signals to indicate success or failure.
+ """
+
+ __gtype_name__ = "ArtistCache"
+
+ __gsignals__ = {
+ 'miss': (GObject.SignalFlags.RUN_FIRST, None, ()),
+ 'hit': (GObject.SignalFlags.RUN_FIRST, None, (object, ))
+ }
+
+ def __repr__(self):
+ return "<ArtistCache>"
+
+ def __init__(self):
+ super().__init__()
+
+ # FIXME
+ self._size = Art.Size.MEDIUM
+ self._scale = 1
+
+ # FIXME: async
+ self.cache_dir = os.path.join(GLib.get_user_cache_dir(), 'media-art')
+ if not os.path.exists(self.cache_dir):
+ try:
+ Gio.file_new_for_path(self.cache_dir).make_directory(None)
+ except GLib.Error as error:
+ logger.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+ return
+
+ def query(self, coreartist):
+ """Start the cache query
+
+ :param CoreSong coresong: The CoreSong object to search art for
+ """
+ print("query")
+ thumb_file = Gio.File.new_for_path(
+ coreartist.props.cached_thumbnail_uri)
+ if thumb_file:
+ thumb_file.read_async(
+ GLib.PRIORITY_LOW, None, self._open_stream, None)
+ return
+
+ self.emit('miss')
+
+ def _open_stream(self, thumb_file, result, arguments):
+ try:
+ stream = thumb_file.read_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ self.emit('miss')
+ return
+
+ GdkPixbuf.Pixbuf.new_from_stream_async(
+ stream, None, self._pixbuf_loaded, None)
+
+ def _pixbuf_loaded(self, stream, result, data):
+ try:
+ pixbuf = GdkPixbuf.Pixbuf.new_from_stream_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+ self.emit('miss')
+ return
+
+ stream.close_async(GLib.PRIORITY_LOW, None, self._close_stream, None)
+
+ surface = Gdk.cairo_surface_create_from_pixbuf(
+ pixbuf, self._scale, None)
+ surface = _make_icon_frame(surface, self._size, self._scale)
+
+ self.emit("hit", surface)
+
+ def _close_stream(self, stream, result, data):
+ try:
+ stream.close_finish(result)
+ except GLib.Error as error:
+ logger.warning("Error: {}, {}".format(error.domain, error.message))
+
+ def _cache_hit(self, klass, pixbuf):
+ surface = Gdk.cairo_surface_create_from_pixbuf(
+ pixbuf, self._scale, None)
+ surface = _make_icon_frame(surface, self._size, self._scale)
+ self._surface = surface
diff --git a/gnomemusic/coreartist.py b/gnomemusic/coreartist.py
index 7e24f8db..5910e8bb 100644
--- a/gnomemusic/coreartist.py
+++ b/gnomemusic/coreartist.py
@@ -27,7 +27,7 @@ gi.require_version('Grl', '0.3')
from gi.repository import Gio, Grl, GObject
from gnomemusic import log
-from gnomemusic.albumartcache import ArtistArt
+from gnomemusic.artistart import ArtistArt
import gnomemusic.utils as utils
diff --git a/gnomemusic/widgets/artistartstack.py b/gnomemusic/widgets/artistartstack.py
index 35599c13..ded31359 100644
--- a/gnomemusic/widgets/artistartstack.py
+++ b/gnomemusic/widgets/artistartstack.py
@@ -25,7 +25,8 @@
from gi.repository import GLib, GObject, Gtk
from gnomemusic import log
-from gnomemusic.albumartcache import Art, ArtistCache, DefaultIcon
+from gnomemusic.albumartcache import Art, DefaultIcon
+from gnomemusic.artistart import ArtistCache
from gnomemusic.coreartist import CoreArtist
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]