[gnome-music/wip/jfelder/3-34-playlist-update] grltrackerplaylists: Restore smart playlists update



commit 750ab91e0591a89fb0a9fea6ac17848848f2232a
Author: Jean Felder <jfelder src gnome org>
Date:   Sat Mar 28 21:24:24 2020 +0100

    grltrackerplaylists: Restore smart playlists update
    
    This feature was lost during the core rewrite.
    
    Everytime a change is triggered, two smart playlists might need to be
    updated:
     * the PlayerPlaylist (active_playlist)
     * the currently actively viewed playlist
    Besides, a smart playlist needs to be updated every time it becomes
    visible.
    
    An update method is introduced to update a smart playlist content. The
    model of the SmartPlaylist is queried and compared with the previous
    one to perform the correct insert and remove operations.

 gnomemusic/coremodel.py                         |  1 +
 gnomemusic/grilowrappers/grltrackerplaylists.py | 59 +++++++++++++++++++++++++
 gnomemusic/grilowrappers/grltrackerwrapper.py   |  1 +
 gnomemusic/views/playlistsview.py               | 12 +++++
 4 files changed, 73 insertions(+)
---
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index 09d5ac78..6188e03a 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -67,6 +67,7 @@ class CoreModel(GObject.GObject):
     __gsignals__ = {
         "artists-loaded": (GObject.SignalFlags.RUN_FIRST, None, ()),
         "playlist-loaded": (GObject.SignalFlags.RUN_FIRST, None, (int,)),
+        "smart-playlist-change": (GObject.SignalFlags.RUN_FIRST, None, ())
     }
 
     active_playlist = GObject.Property(type=Playlist, default=None)
diff --git a/gnomemusic/grilowrappers/grltrackerplaylists.py b/gnomemusic/grilowrappers/grltrackerplaylists.py
index ec5072bd..51911acc 100644
--- a/gnomemusic/grilowrappers/grltrackerplaylists.py
+++ b/gnomemusic/grilowrappers/grltrackerplaylists.py
@@ -255,6 +255,20 @@ class GrlTrackerPlaylists(GObject.GObject):
         self._tracker.update_blank_async(
             query, GLib.PRIORITY_LOW, None, _create_cb, None)
 
+    def check_smart_playlist_change(self):
+        """Check if smart playlists need to be updated.
+
+        A smart playlist needs to be updated in two cases:
+        * it is being played (active_playlist)
+        * it is visible in PlaylistsView
+        """
+        active_playlist = self._coremodel.props.active_playlist
+        if (active_playlist is not None
+                and active_playlist.props.is_smart is True):
+            active_playlist.update()
+        else:
+            self._coremodel.emit("smart-playlist-change")
+
 
 class Playlist(GObject.GObject):
     """ Base class of all playlists """
@@ -711,6 +725,51 @@ class SmartPlaylist(Playlist):
 
         return self._model
 
+    def update(self):
+        """Updates playlist model."""
+        if self._model is None:
+            return
+
+        new_model_medias = []
+
+        def _fill_new_model(source, op_id, media, remaining, error):
+            if error:
+                return
+
+            if not media:
+                self._finish_update(new_model_medias)
+                return
+
+            new_model_medias.append(media)
+
+        options = self._fast_options.copy()
+        self._source.query(
+            self.props.query, self.METADATA_KEYS, options, _fill_new_model)
+
+    def _finish_update(self, new_model_medias):
+        if not new_model_medias:
+            self._model.remove_all()
+            return
+
+        current_models_ids = [coresong.props.media.get_id()
+                              for coresong in self._model]
+        new_model_ids = [media.get_id() for media in new_model_medias]
+
+        idx_to_delete = []
+        for idx, media_id in enumerate(current_models_ids):
+            if media_id not in new_model_ids:
+                idx_to_delete.insert(0, idx)
+
+        for idx in idx_to_delete:
+            self._model.remove(idx)
+            self.props.count -= 1
+
+        for idx, media in enumerate(new_model_medias):
+            if media.get_id() not in current_models_ids:
+                coresong = CoreSong(media, self._coreselection, self._grilo)
+                self._model.append(coresong)
+                self.props.count += 1
+
 
 class MostPlayed(SmartPlaylist):
     """Most Played smart playlist"""
diff --git a/gnomemusic/grilowrappers/grltrackerwrapper.py b/gnomemusic/grilowrappers/grltrackerwrapper.py
index 1bfabe00..385804ae 100644
--- a/gnomemusic/grilowrappers/grltrackerwrapper.py
+++ b/gnomemusic/grilowrappers/grltrackerwrapper.py
@@ -164,6 +164,7 @@ class GrlTrackerWrapper(GObject.GObject):
 
         self._check_album_change()
         self._check_artist_change()
+        self._tracker_playlists.check_smart_playlist_change()
 
         self._batch_changed_media_ids = {}
         self._content_changed_timeout = None
diff --git a/gnomemusic/views/playlistsview.py b/gnomemusic/views/playlistsview.py
index 6c6be6f5..0b831f09 100644
--- a/gnomemusic/views/playlistsview.py
+++ b/gnomemusic/views/playlistsview.py
@@ -115,6 +115,9 @@ class PlaylistsView(BaseView):
         self._active_playlist_id = self._coremodel.connect(
             "notify::active-playlist", self._on_active_playlist_changed)
 
+        self._coremodel.connect(
+            "smart-playlist-change", self._on_smart_playlist_change)
+
         self._model.connect("items-changed", self._on_playlists_model_changed)
         self._on_playlists_model_changed(self._model, 0, 0, 0)
 
@@ -171,6 +174,13 @@ class PlaylistsView(BaseView):
             self._sidebar.select_row(row_next)
             self._on_playlist_activated(self._sidebar, row_next, True)
 
+    def _on_smart_playlist_change(self, coremodel):
+        selection = self._sidebar.get_selected_row()
+        current_playlist = selection.props.playlist
+        if (current_playlist is not None
+                and current_playlist.props.is_smart):
+            current_playlist.update()
+
     @log
     def _on_view_right_clicked(self, gesture, n_press, x, y):
         requested_row = self._view.get_row_at_y(y)
@@ -234,6 +244,8 @@ class PlaylistsView(BaseView):
 
         self._view.bind_model(
             playlist.props.model, self._create_song_widget, playlist)
+        if playlist.props.is_smart:
+            playlist.update()
 
         self._pl_ctrls.props.playlist = playlist
 


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