[gnome-music/wip/mschraal/3-30-flatpak-lua: 4/4] Restart remote cover lookup on source availability



commit 884f7c2e86bceb3d88b247471b586aa0634a0586
Author: Marinus Schraal <mschraal gnome org>
Date:   Thu Sep 27 22:39:59 2018 +0200

    Restart remote cover lookup on source availability
    
    Grilo might not have a network available on startup, so the cover art
    lookup does not check the remote sources. Music only checks for new art on
    first start, so the remote lookup may never happen.
    
    Add logic so Grilo triggers a remote art lookup if new Grilo cover art
    sources become available.
    
    Side effects from this change:
     * No loading state for remote-art, as there is no check for network
    connectivity by Music.
     * All remote update checks are triggered in close proximity, this might
    turn out to be problematic on large collections.

 gnomemusic/albumartcache.py      | 24 ++++++++++++++++++++----
 gnomemusic/grilo.py              | 20 ++++++++++++++++++++
 gnomemusic/widgets/coverstack.py | 36 ++++++++++++++++++++++++++++++------
 3 files changed, 70 insertions(+), 10 deletions(-)
---
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index 88022220..3ca45e63 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -246,6 +246,7 @@ class Art(GObject.GObject):
         remote_art = RemoteArt()
         remote_art.connect('retrieved', self._remote_art_retrieved)
         remote_art.connect('unavailable', self._remote_art_unavailable)
+        remote_art.connect('no-remote-sources', self._remote_art_no_sources)
         remote_art.query(self._media)
 
     @log
@@ -260,6 +261,10 @@ class Art(GObject.GObject):
         self._add_to_blacklist()
         self._no_art_available()
 
+    @log
+    def _remote_art_no_sources(self, klass):
+        self._no_art_available()
+
     @log
     def _no_art_available(self):
         self._surface = DefaultIcon().get(
@@ -610,7 +615,8 @@ class RemoteArt(GObject.GObject):
 
     __gsignals__ = {
         'retrieved': (GObject.SignalFlags.RUN_FIRST, None, ()),
-        'unavailable': (GObject.SignalFlags.RUN_FIRST, None, ())
+        'unavailable': (GObject.SignalFlags.RUN_FIRST, None, ()),
+        'no-remote-sources': (GObject.SignalFlags.RUN_FIRST, None, ())
     }
 
     def __repr__(self):
@@ -631,10 +637,20 @@ class RemoteArt(GObject.GObject):
         """
         self._album = utils.get_album_title(media)
         self._artist = utils.get_artist_name(media)
+        self._media = media
 
-        # FIXME: It seems this Grilo query does not always return,
-        # especially on queries with little info.
-        grilo.get_album_art_for_item(media, self._remote_album_art)
+        if not grilo.props.cover_sources:
+            self.emit('no-remote-sources')
+            grilo.connect(
+                'notify::cover-sources', self._on_grilo_cover_sources_changed)
+        else:
+            # FIXME: It seems this Grilo query does not always return,
+            # especially on queries with little info.
+            grilo.get_album_art_for_item(media, self._remote_album_art)
+
+    def _on_grilo_cover_sources_changed(self, klass, data):
+        if grilo.props.cover_sources:
+            grilo.get_album_art_for_item(self._media, self._remote_album_art)
 
     @log
     def _delete_callback(self, src, result, data):
diff --git a/gnomemusic/grilo.py b/gnomemusic/grilo.py
index 890918be..65d0373f 100644
--- a/gnomemusic/grilo.py
+++ b/gnomemusic/grilo.py
@@ -80,6 +80,7 @@ class Grilo(GObject.GObject):
     _theaudiodb_api_key = "195003"
 
     sources = GObject.Property()
+    cover_sources = GObject.Property(type=bool, default=False)
 
     def __repr__(self):
         return '<Grilo>'
@@ -117,6 +118,9 @@ class Grilo(GObject.GObject):
         self.changes_pending = {'Albums': False, 'Artists': False, 'Songs': False}
         self.pending_changed_medias = []
 
+        self._thumbnail_sources = []
+        self._thumbnail_sources_timeout = None
+
         self.registry = Grl.Registry.get_default()
 
         self.sparqltracker = TrackerWrapper().tracker
@@ -201,6 +205,14 @@ class Grilo(GObject.GObject):
         self.emit('changes-pending')
         return False
 
+    @log
+    def _trigger_art_update(self):
+        self._thumbnail_sources_timeout = None
+        if len(self._thumbnail_sources) > 0:
+            self.props.cover_sources = True
+
+        return GLib.SOURCE_REMOVE
+
     @log
     def _on_source_added(self, pluginRegistry, mediaSource):
         if ("net:plaintext" in mediaSource.get_tags()
@@ -212,6 +224,14 @@ class Grilo(GObject.GObject):
                     "Failed to unregister {}".format(mediaSource.get_id()))
             return
 
+        if Grl.METADATA_KEY_THUMBNAIL in mediaSource.supported_keys():
+            self._thumbnail_sources.append(mediaSource)
+            if not self._thumbnail_sources_timeout:
+                # Aggregate sources being added, for example when the
+                # network comes online.
+                self._thumbnail_sources_timeout = GLib.timeout_add_seconds(
+                    5, self._trigger_art_update)
+
         id = mediaSource.get_id()
         logger.debug("new grilo source %s was added", id)
         try:
diff --git a/gnomemusic/widgets/coverstack.py b/gnomemusic/widgets/coverstack.py
index 6950908c..d7456ec6 100644
--- a/gnomemusic/widgets/coverstack.py
+++ b/gnomemusic/widgets/coverstack.py
@@ -22,7 +22,7 @@
 # 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 gi.repository import GObject, Gtk
+from gi.repository import GLib, GObject, Gtk
 
 from gnomemusic import log
 from gnomemusic.albumartcache import Art, DefaultIcon
@@ -55,8 +55,10 @@ class CoverStack(Gtk.Stack):
         """
         super().__init__()
 
-        self._size = None
+        self._art = None
         self._handler_id = None
+        self._size = None
+        self._timeout = None
 
         self._loading_cover = Gtk.Image()
         self._cover_a = Gtk.Image()
@@ -100,15 +102,34 @@ class CoverStack(Gtk.Stack):
         Update the stack with the art retrieved from the given media.
         :param Grl.Media media: The media object
         """
+        if self._handler_id and self._art:
+            # Remove a possible dangling 'finished' callback if update
+            # is called again, but it is still looking for the previous
+            # art.
+            self._art.disconnect(self._handler_id)
+            # Set the loading state only after a delay to make between
+            # song transitions smooth if loading time is negligible.
+            self._timeout = GLib.timeout_add(100, self._set_loading_child)
+
         self._active_child = self.props.visible_child_name
 
-        art = Art(self.props.size, media, self.props.scale_factor)
-        self._handler_id = art.connect('finished', self._art_retrieved)
-        art.lookup()
+        self._art = Art(self.props.size, media, self.props.scale_factor)
+        self._handler_id = self._art.connect('finished', self._art_retrieved)
+        self._art.lookup()
+
+    @log
+    def _set_loading_child(self):
+        self.props.visible_child_name = "loading"
+        self._active_child = self.props.visible_child_name
+
+        return GLib.SOURCE_REMOVE
 
     @log
     def _art_retrieved(self, klass):
-        klass.disconnect(self._handler_id)
+        if self._timeout:
+            GLib.source_remove(self._timeout)
+            self._timeout = None
+
         if self._active_child == "B":
             self._cover_a.props.surface = klass.surface
             self.props.visible_child_name = "A"
@@ -116,4 +137,7 @@ class CoverStack(Gtk.Stack):
             self._cover_b.props.surface = klass.surface
             self.props.visible_child_name = "B"
 
+        self._active_child = self.props.visible_child_name
+        self._art = None
+
         self.emit('updated')


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