[gnome-music/wip/mschraal/core-thumb-property: 10/20] corealbum: Add thumbnail property
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/core-thumb-property: 10/20] corealbum: Add thumbnail property
- Date: Fri, 19 Jun 2020 13:42:53 +0000 (UTC)
commit ffa2b36417fe87a3c95e7ceaf8a149453d9b1d0f
Author: Marinus Schraal <mschraal gnome org>
Date: Sun Apr 5 23:30:59 2020 +0200
corealbum: Add thumbnail property
Use the ArtistArt machinery to retrieve and store art.
data/ui/AlbumCover.ui | 2 +-
data/ui/AlbumWidget.ui | 2 +-
data/ui/ArtistAlbumWidget.ui | 2 +-
gnomemusic/albumart.py | 62 +++++++++++++++++++++++++++
gnomemusic/artcache.py | 41 +++++++++++++-----
gnomemusic/corealbum.py | 27 ++++++++++++
gnomemusic/coregrilo.py | 8 ++++
gnomemusic/grilowrappers/grltrackerwrapper.py | 36 ++++++++++++++++
gnomemusic/storeartistart.py | 38 ++++++++++------
gnomemusic/widgets/albumcover.py | 6 +--
gnomemusic/widgets/albumwidget.py | 6 +--
gnomemusic/widgets/artistalbumwidget.py | 8 ++--
gnomemusic/widgets/artstack.py | 8 ++--
13 files changed, 204 insertions(+), 42 deletions(-)
---
diff --git a/data/ui/AlbumCover.ui b/data/ui/AlbumCover.ui
index d825c1cc..7ac403c2 100644
--- a/data/ui/AlbumCover.ui
+++ b/data/ui/AlbumCover.ui
@@ -16,7 +16,7 @@
<property name="can_focus">False</property>
<property name="margin_bottom">4</property>
<child>
- <object class="CoverStack" id="_cover_stack">
+ <object class="ArtStack" id="_art_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vexpand">True</property>
diff --git a/data/ui/AlbumWidget.ui b/data/ui/AlbumWidget.ui
index 9fdb87cf..e5848709 100644
--- a/data/ui/AlbumWidget.ui
+++ b/data/ui/AlbumWidget.ui
@@ -32,7 +32,7 @@
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
- <object class="CoverStack" id="_cover_stack">
+ <object class="ArtStack" id="_art_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
diff --git a/data/ui/ArtistAlbumWidget.ui b/data/ui/ArtistAlbumWidget.ui
index 7462799b..e25083ce 100644
--- a/data/ui/ArtistAlbumWidget.ui
+++ b/data/ui/ArtistAlbumWidget.ui
@@ -7,7 +7,7 @@
<property name="margin_right">120</property>
<property name="visible">True</property>
<child>
- <object class="CoverStack" id="_cover_stack">
+ <object class="ArtStack" id="_art_stack">
<property name="visible">True</property>
<property name="margin_top">20</property>
<property name="margin_right">30</property>
diff --git a/gnomemusic/albumart.py b/gnomemusic/albumart.py
new file mode 100644
index 00000000..f0137c71
--- /dev/null
+++ b/gnomemusic/albumart.py
@@ -0,0 +1,62 @@
+# 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_version("MediaArt", "2.0")
+from gi.repository import GObject, MediaArt
+
+from gnomemusic.musiclogger import MusicLogger
+
+
+class AlbumArt(GObject.GObject):
+
+ _log = MusicLogger()
+
+ def __init__(self, application, corealbum):
+ """Initialize AlbumArt
+
+ :param Application application: The application object
+ :param CoreAlbum corealbum: The corealbum to use
+ """
+ super().__init__()
+
+ self._corealbum = corealbum
+ self._album = self._corealbum.props.title
+ self._artist = self._corealbum.props.artist
+
+ if self._in_cache():
+ return
+
+ application.props.coregrilo.get_album_art(self._corealbum)
+
+ def _in_cache(self):
+ success, thumb_file = MediaArt.get_file(
+ self._artist, self._album, "album")
+ if (not success
+ or not thumb_file.query_exists()):
+ self._corealbum.props.thumbnail = "loading"
+ return False
+
+ self._corealbum.props.thumbnail = thumb_file.get_path()
+
+ return True
diff --git a/gnomemusic/artcache.py b/gnomemusic/artcache.py
index 7b6a849e..8627b938 100644
--- a/gnomemusic/artcache.py
+++ b/gnomemusic/artcache.py
@@ -27,6 +27,8 @@ from math import pi
import cairo
from gi.repository import Gdk, GdkPixbuf, Gio, Gtk, GLib, GObject
+from gnomemusic.corealbum import CoreAlbum
+from gnomemusic.coreartist import CoreArtist
from gnomemusic.musiclogger import MusicLogger
@@ -120,6 +122,7 @@ class DefaultIcon(GObject.GObject):
class Type(Enum):
ARTIST = "avatar-default-symbolic"
+ ARTIST_LOADING = "content-loading-symbolic"
LOADING = "content-loading-symbolic"
MUSIC = "folder-music-symbolic"
@@ -182,19 +185,32 @@ class ArtCache(GObject.GObject):
self._size = size
self._scale = scale
- self._loading_icon = DefaultIcon().get(
- DefaultIcon.Type.LOADING, self._size, self._scale,
- round_shape=True)
- self._default_icon = DefaultIcon().get(
- DefaultIcon.Type.ARTIST, self._size, self._scale, round_shape=True)
+ self._coreobject = None
+ self._default_icon = None
+ self._loading_icon = None
- def query(self, coreartist):
+ def query(self, coreobject):
"""Start the cache query
- :param CoreArtist coreartist: The object to search art for
+ :param coreobject: The object to search art for
"""
- thumbnail_uri = coreartist.props.thumbnail
- if thumbnail_uri == "loading":
+ self._coreobject = coreobject
+
+ if isinstance(coreobject, CoreArtist):
+ self._loading_icon = DefaultIcon().get(
+ DefaultIcon.Type.ARTIST_LOADING, self._size, self._scale,
+ round_shape=True)
+ self._default_icon = DefaultIcon().get(
+ DefaultIcon.Type.ARTIST, self._size, self._scale,
+ round_shape=True)
+ elif isinstance(coreobject, CoreAlbum):
+ self._loading_icon = DefaultIcon().get(
+ DefaultIcon.Type.LOADING, self._size, self._scale)
+ self._default_icon = DefaultIcon().get(
+ DefaultIcon.Type.MUSIC, self._size, self._scale)
+
+ thumbnail_uri = coreobject.props.thumbnail
+ if thumbnail_uri in ["loading", "", None]:
self.emit("result", self._loading_icon)
return
elif thumbnail_uri == "generic":
@@ -234,8 +250,11 @@ class ArtCache(GObject.GObject):
surface = Gdk.cairo_surface_create_from_pixbuf(
pixbuf, self._scale, None)
- surface = _make_icon_frame(
- surface, self._size, self._scale, round_shape=True)
+ if isinstance(self._coreobject, CoreArtist):
+ surface = _make_icon_frame(
+ surface, self._size, self._scale, round_shape=True)
+ elif isinstance(self._coreobject, CoreAlbum):
+ surface = _make_icon_frame(surface, self._size, self._scale)
self.emit("result", surface)
diff --git a/gnomemusic/corealbum.py b/gnomemusic/corealbum.py
index 588001f7..906a9a0b 100644
--- a/gnomemusic/corealbum.py
+++ b/gnomemusic/corealbum.py
@@ -28,6 +28,8 @@ from gi.repository import Gfm, Gio, Grl, GObject
import gnomemusic.utils as utils
+from gnomemusic.albumart import AlbumArt
+
class CoreAlbum(GObject.GObject):
"""Exposes a Grl.Media with relevant data as properties
@@ -49,9 +51,12 @@ class CoreAlbum(GObject.GObject):
"""
super().__init__()
+ self._application = application
self._coregrilo = application.props.coregrilo
self._model = None
self._selected = False
+ self._thumbnail = None
+
self.update(media)
def update(self, media):
@@ -126,3 +131,25 @@ class CoreAlbum(GObject.GObject):
# is requested, it will trigger the filled model update as
# well.
self.props.model.items_changed(0, 0, 0)
+
+ @GObject.Property(type=str, default=None)
+ def thumbnail(self):
+ """Album art thumbnail retrieval
+
+ :return: The album art location or "generic" or "loading"
+ :rtype: string
+ """
+ if self._thumbnail is None:
+ self._thumbnail = "loading"
+ self.notify("thumbnail")
+ AlbumArt(self._application, self)
+
+ return self._thumbnail
+
+ @thumbnail.setter
+ def thumbnail(self, value):
+ """Album art thumbnail setter
+
+ :param string value: path, "generic" or "loading"
+ """
+ self._thumbnail = value
diff --git a/gnomemusic/coregrilo.py b/gnomemusic/coregrilo.py
index fa977ab1..cf78bd58 100644
--- a/gnomemusic/coregrilo.py
+++ b/gnomemusic/coregrilo.py
@@ -204,6 +204,14 @@ class CoreGrilo(GObject.GObject):
self._wrappers["grl-tracker-source"].get_album_art_for_item(
coresong, callback)
+ def get_album_art(self, corealbum):
+ """Retrieve album art for the given CoreAlbum
+
+ :param CoreAlbum corealbum: CoreAlbum to retrieve art for
+ """
+ if "grl-tracker-source" in self._wrappers:
+ self._wrappers["grl-tracker-source"].get_album_art(corealbum)
+
def get_artist_art(self, coreartist):
"""Retrieve artist art for the given CoreArtist
diff --git a/gnomemusic/grilowrappers/grltrackerwrapper.py b/gnomemusic/grilowrappers/grltrackerwrapper.py
index 652e2269..8cb0952f 100644
--- a/gnomemusic/grilowrappers/grltrackerwrapper.py
+++ b/gnomemusic/grilowrappers/grltrackerwrapper.py
@@ -982,6 +982,42 @@ class GrlTrackerWrapper(GObject.GObject):
return query
+ def get_album_art(self, corealbum):
+ """Retrieve album art for the given CoreAlbum
+
+ :param CoreAlbum corealbum: CoreAlbum to get art for
+ """
+ media = corealbum.props.media
+
+ def art_retrieved_cb(source, op_id, queried_media, remaining, error):
+ if error:
+ self._log.warning("Error: {}".format(error))
+ corealbum.props.thumbnail = "generic"
+ return
+
+ if (remaining == 0
+ and queried_media is None):
+ corealbum.props.thumbnail = "generic"
+ return
+
+ thumbnail_uri = queried_media.get_thumbnail()
+ if thumbnail_uri is None:
+ corealbum.props.thumbnail = "generic"
+ else:
+ media.set_thumbnail(thumbnail_uri)
+ StoreArtistArt(corealbum)
+
+ album_id = media.get_id()
+ query = self._get_album_for_album_id(album_id)
+
+ full_options = Grl.OperationOptions()
+ full_options.set_resolution_flags(
+ Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY)
+
+ self._source.query(
+ query, self.METADATA_THUMBNAIL_KEYS, full_options,
+ art_retrieved_cb)
+
def get_artist_art(self, coreartist):
"""Retrieve artist art for the given CoreArtist
diff --git a/gnomemusic/storeartistart.py b/gnomemusic/storeartistart.py
index 95aaecd3..3dbf6181 100644
--- a/gnomemusic/storeartistart.py
+++ b/gnomemusic/storeartistart.py
@@ -27,25 +27,28 @@ gi.require_versions({"MediaArt": "2.0", "Soup": "2.4"})
from gi.repository import Gio, GLib, GObject, MediaArt, Soup
from gnomemusic.musiclogger import MusicLogger
+from gnomemusic.coreartist import CoreArtist
+from gnomemusic.corealbum import CoreAlbum
class StoreArtistArt(GObject.Object):
"""Stores Art in the MediaArt cache.
"""
- def __init__(self, coreartist):
+ def __init__(self, coreobject):
"""Initialize StoreArtistArt
- :param CoreArtist coreartist: The core artist to store art for
+ :param coreobject: The CoreArtist or CoreSong to store art for
"""
- self._coreartist = coreartist
+ self._coreobject = coreobject
+
self._log = MusicLogger()
self._soup_session = Soup.Session.new()
- uri = coreartist.props.media.get_thumbnail()
+ uri = coreobject.props.media.get_thumbnail()
if (uri is None
or uri == ""):
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
cache_dir = GLib.build_filenamev(
@@ -65,7 +68,7 @@ class StoreArtistArt(GObject.Object):
except GLib.Error as error:
self._log.warning(
"Error: {}, {}".format(error.domain, error.message))
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
msg = Soup.Message.new("GET", uri)
@@ -83,7 +86,7 @@ class StoreArtistArt(GObject.Object):
except GLib.Error as error:
self._log.warning(
"Error: {}, {}".format(error.domain, error.message))
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
istream = Gio.MemoryInputStream.new_from_bytes(
@@ -114,14 +117,21 @@ class StoreArtistArt(GObject.Object):
except GLib.Error as error:
self._log.warning(
"Error: {}, {}".format(error.domain, error.message))
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
- success, cache_path = MediaArt.get_path(
- self._coreartist.props.artist, None, "artist")
+ if isinstance(self._coreobject, CoreArtist):
+ success, cache_path = MediaArt.get_path(
+ self._coreobject.props.artist, None, "artist")
+ elif isinstance(self._coreobject, CoreAlbum):
+ success, cache_path = MediaArt.get_path(
+ self._coreobject.props.artist, self._coreobject.props.title,
+ "album")
+ else:
+ success = False
if not success:
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
try:
@@ -130,11 +140,11 @@ class StoreArtistArt(GObject.Object):
except GLib.Error as error:
self._log.warning(
"Error: {}, {}".format(error.domain, error.message))
- self._coreartist.props.thumbnail = "generic"
+ self._coreobject.props.thumbnail = "generic"
return
- self._coreartist.props.media.set_thumbnail(cache_path)
- self._coreartist.props.thumbnail = cache_path
+ self._coreobject.props.media.set_thumbnail(cache_path)
+ self._coreobject.props.thumbnail = cache_path
tmp_file.delete_async(
GLib.PRIORITY_LOW, None, self._delete_callback, None)
diff --git a/gnomemusic/widgets/albumcover.py b/gnomemusic/widgets/albumcover.py
index 9bd31e6b..557b318b 100644
--- a/gnomemusic/widgets/albumcover.py
+++ b/gnomemusic/widgets/albumcover.py
@@ -40,7 +40,7 @@ class AlbumCover(Gtk.FlowBoxChild):
__gtype_name__ = 'AlbumCover'
- _cover_stack = Gtk.Template.Child()
+ _art_stack = Gtk.Template.Child()
_check = Gtk.Template.Child()
_title_label = Gtk.Template.Child()
_artist_label = Gtk.Template.Child()
@@ -81,7 +81,7 @@ class AlbumCover(Gtk.FlowBoxChild):
self.connect('query-tooltip', self._on_tooltip_query)
- self._cover_stack.props.size = Art.Size.MEDIUM
+ self._art_stack.props.size = Art.Size.MEDIUM
self.show()
@@ -95,7 +95,7 @@ class AlbumCover(Gtk.FlowBoxChild):
return
self._retrieved = True
- self._cover_stack.update(self._corealbum)
+ self._art_stack.props.coreobject = self._corealbum
@GObject.Property(type=CoreAlbum, flags=GObject.ParamFlags.READABLE)
def corealbum(self):
diff --git a/gnomemusic/widgets/albumwidget.py b/gnomemusic/widgets/albumwidget.py
index 635b19cd..6bc81f5b 100644
--- a/gnomemusic/widgets/albumwidget.py
+++ b/gnomemusic/widgets/albumwidget.py
@@ -45,7 +45,7 @@ class AlbumWidget(Gtk.EventBox):
_artist_label = Gtk.Template.Child()
_composer_label = Gtk.Template.Child()
_composer_info_label = Gtk.Template.Child()
- _cover_stack = Gtk.Template.Child()
+ _art_stack = Gtk.Template.Child()
_disc_list_box = Gtk.Template.Child()
_released_info_label = Gtk.Template.Child()
_running_info_label = Gtk.Template.Child()
@@ -68,7 +68,7 @@ class AlbumWidget(Gtk.EventBox):
self._duration_signal_id = None
self._model_signal_id = None
- self._cover_stack.props.size = Art.Size.LARGE
+ self._art_stack.props.size = Art.Size.LARGE
self._player = self._application.props.player
self.bind_property(
@@ -89,7 +89,7 @@ class AlbumWidget(Gtk.EventBox):
self._corealbum = corealbum
- self._cover_stack.update(self._corealbum)
+ self._art_stack.props.coreobject = self._corealbum
album_name = self._corealbum.props.title
artist = self._corealbum.props.artist
diff --git a/gnomemusic/widgets/artistalbumwidget.py b/gnomemusic/widgets/artistalbumwidget.py
index 47f35f4f..b80be261 100644
--- a/gnomemusic/widgets/artistalbumwidget.py
+++ b/gnomemusic/widgets/artistalbumwidget.py
@@ -40,7 +40,7 @@ class ArtistAlbumWidget(Gtk.Box):
__gtype_name__ = 'ArtistAlbumWidget'
_album_box = Gtk.Template.Child()
- _cover_stack = Gtk.Template.Child()
+ _art_stack = Gtk.Template.Child()
_disc_list_box = Gtk.Template.Child()
_title_year = Gtk.Template.Child()
@@ -66,8 +66,8 @@ class ArtistAlbumWidget(Gtk.Box):
self._selection_mode = False
- self._cover_stack.props.size = Art.Size.MEDIUM
- self._cover_stack.update(corealbum)
+ self._art_stack.props.size = Art.Size.MEDIUM
+ self._art_stack.props.coreobject = corealbum
self.bind_property(
'selection-mode', self._disc_list_box, 'selection-mode',
@@ -83,7 +83,7 @@ class ArtistAlbumWidget(Gtk.Box):
self._size_group.add_widget(self._album_box)
if self._cover_size_group:
- self._cover_size_group.add_widget(self._cover_stack)
+ self._cover_size_group.add_widget(self._art_stack)
corealbum.props.model.connect_after(
"items-changed", self._on_model_items_changed)
diff --git a/gnomemusic/widgets/artstack.py b/gnomemusic/widgets/artstack.py
index 5c1f405f..2fde30ba 100644
--- a/gnomemusic/widgets/artstack.py
+++ b/gnomemusic/widgets/artstack.py
@@ -1,4 +1,4 @@
-# Copyright 2019 The GNOME Music developers
+# 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
@@ -112,9 +112,9 @@ class ArtStack(Gtk.Stack):
self.props.visible_child_name = "B"
def _on_destroy(self, widget):
- # If the stacm is destroyed while the art is updated, an error
- # can occur once the art is retrieved because the CoverStack
- # does not have children anymore.
+ # If the stack is destroyed while the art is updated, an error
+ # can occur once the art is retrieved because the ArtStack does
+ # not have children anymore.
self._disconnect_cache()
def _disconnect_cache(self):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]