[gnome-music/wip/garnacho/performance-improvements: 1/5] player: Take care of media item discovery



commit 6f1cb8d448d8a1a5e04e86b7bf292ee1ddaa9798
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Feb 15 14:25:56 2015 +0100

    player: Take care of media item discovery
    
    All models have been added a column to store the DiscoveryStatus for the
    song, and this column is passed on set_playlist(), so the Player object
    does take care of updating the status after the song failed playing, or
    discovery failed on it.
    
    This makes sure we react properly to player/discovery failures for the
    current and next songs, and only when it's needed so. Discovery is a
    very expensive operation, and this allows us to stop doing it for every
    song at the time of adding these to a model/view, which means lots of
    I/O and CPU time just to know whether songs can be played, even it they
    might not eventually.

 gnomemusic/player.py  |   46 ++++++++++++++++++++++++++++++++++++++++++----
 gnomemusic/view.py    |   23 ++++++++++++++---------
 gnomemusic/widgets.py |   11 +++++++----
 3 files changed, 63 insertions(+), 17 deletions(-)
---
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 684aef6..20c05fe 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -61,6 +61,10 @@ class PlaybackStatus:
     PAUSED = 1
     STOPPED = 2
 
+class DiscoveryStatus:
+    PENDING = 0
+    FAILED = 1
+    SUCCEEDED = 2
 
 class Player(GObject.GObject):
     nextTrack = None
@@ -210,6 +214,8 @@ class Player(GObject.GObject):
     def _onBusError(self, bus, message):
         media = self.get_current_media()
         if media is not None:
+            currentTrack = self.playlist.get_iter(self.currentTrack.get_path())
+            self.playlist.set_value(currentTrack, self.discovery_status_field, DiscoveryStatus.FAILED)
             uri = media.get_url()
         else:
             uri = 'none'
@@ -225,8 +231,6 @@ class Player(GObject.GObject):
 
     @log
     def _on_bus_eos(self, bus, message):
-        self.nextTrack = self._get_next_track()
-
         if self.nextTrack:
             GLib.idle_add(self._on_glib_idle)
         elif (self.repeat == RepeatType.NONE):
@@ -468,6 +472,37 @@ class Player(GObject.GObject):
         self.emit('playlist-item-changed', self.playlist, currentTrack)
         self.emit('current-changed')
 
+        self._validate_next_track();
+
+    def _on_next_item_validated(self, info, error, _iter):
+        if error:
+            print("Info %s: error: %s" % (info, error))
+            self.playlist.set_value(_iter, self.discovery_status_field, DiscoveryStatus.FAILED);
+            nextTrack = self.playlist.iter_next(_iter)
+
+            if nextTrack:
+                self._validate_next_track(Gtk.TreeRowReference.new(self.playlist, 
self.playlist.get_path(nextTrack)))
+
+    def _validate_next_track(self, track=None):
+        if track is None:
+            track = self._get_next_track()
+
+        if track is None:
+            return
+
+        self.nextTrack = track
+
+        _iter = self.playlist.get_iter(self.nextTrack.get_path())
+        status = self.playlist.get_value(_iter, self.discovery_status_field)
+        nextSong = self.playlist.get_value(_iter, self.playlistField)
+
+        if status == DiscoveryStatus.PENDING:
+            self.discover_item(nextSong, self._on_next_item_validated, _iter)
+        elif status == DiscoveryStatus.FAILED:
+            GLib.idle_add(self._validate_next_track())
+
+        return False;
+
     @log
     def _on_cache_lookup(self, pixbuf, path, data=None):
         if pixbuf is not None:
@@ -524,7 +559,7 @@ class Player(GObject.GObject):
             return True
 
         self.stop()
-        self.currentTrack = self._get_next_track()
+        self.currentTrack = self.nextTrack
 
         if self.currentTrack:
             self.play()
@@ -557,7 +592,7 @@ class Player(GObject.GObject):
             self.set_playing(True)
 
     @log
-    def set_playlist(self, type, id, model, iter, field):
+    def set_playlist(self, type, id, model, iter, field, discovery_status_field):
         self.stop()
 
         old_playlist = self.playlist
@@ -572,6 +607,7 @@ class Player(GObject.GObject):
         self.playlistId = id
         self.currentTrack = Gtk.TreeRowReference.new(model, model.get_path(iter))
         self.playlistField = field
+        self.discovery_status_field = discovery_status_field
 
         if old_playlist != model:
             self.playlist_insert_handler = model.connect('row-inserted', self._on_playlist_size_changed)
@@ -798,6 +834,8 @@ class Player(GObject.GObject):
         if not self.currentTrack or not self.currentTrack.valid():
             return None
         currentTrack = self.playlist.get_iter(self.currentTrack.get_path())
+        if self.playlist.get_value(currentTrack, self.discovery_status_field) == DiscoveryStatus.FAILED:
+            return None
         return self.playlist.get_value(currentTrack, self.playlistField)
 
 
diff --git a/gnomemusic/view.py b/gnomemusic/view.py
index 801a06e..f759575 100644
--- a/gnomemusic/view.py
+++ b/gnomemusic/view.py
@@ -44,6 +44,7 @@ from gnomemusic.grilo import grilo
 from gnomemusic.query import Query
 from gnomemusic.toolbar import ToolbarState
 import gnomemusic.widgets as Widgets
+from gnomemusic.player import DiscoveryStatus
 from gnomemusic.playlists import Playlists, StaticPlaylists
 from gnomemusic.albumArtCache import AlbumArtCache as albumArtCache
 from gnomemusic import log
@@ -80,7 +81,8 @@ class ViewContainer(Gtk.Stack):
             GObject.TYPE_INT,
             GObject.TYPE_STRING,
             GObject.TYPE_BOOLEAN,
-            GObject.TYPE_BOOLEAN
+            GObject.TYPE_BOOLEAN,
+            GObject.TYPE_INT
         )
         self.view = Gd.MainView(
             shadow_type=Gtk.ShadowType.NONE
@@ -429,7 +431,7 @@ class Songs(ViewContainer):
         except TypeError:
             return
         if self._model.get_value(_iter, 8) != self.errorIconName:
-            self.player.set_playlist('Songs', None, self._model, _iter, 5)
+            self.player.set_playlist('Songs', None, self._model, _iter, 5, 11)
             self.player.set_playing(True)
 
     @log
@@ -815,7 +817,8 @@ class Playlist(ViewContainer):
             GObject.TYPE_INT,
             GObject.TYPE_STRING,
             GObject.TYPE_BOOLEAN,
-            GObject.TYPE_BOOLEAN
+            GObject.TYPE_BOOLEAN,
+            GObject.TYPE_INT
         )
 
         self.playlists_sidebar.set_view_type(Gd.MainViewType.LIST)
@@ -1009,7 +1012,7 @@ class Playlist(ViewContainer):
         if self._model.get_value(_iter, 8) != self.errorIconName:
             self.player.set_playlist(
                 'Playlist', self.current_playlist.get_id(),
-                self._model, _iter, 5
+                self._model, _iter, 5, 11
             )
             self.player.set_playing(True)
 
@@ -1104,7 +1107,8 @@ class Playlist(ViewContainer):
                 GObject.TYPE_INT,
                 GObject.TYPE_STRING,
                 GObject.TYPE_BOOLEAN,
-                GObject.TYPE_BOOLEAN
+                GObject.TYPE_BOOLEAN,
+                GObject.TYPE_INT
             )
             self.view.set_model(self._model)
             GLib.idle_add(grilo.populate_playlist_songs, playlist, self._add_item)
@@ -1246,7 +1250,7 @@ class Playlist(ViewContainer):
 
                     self.iter_to_clean = None
                     self.update_model(self.player, model, nextIter)
-                    self.player.set_playlist('Playlist', playlist.get_id(), model, nextIter, 5)
+                    self.player.set_playlist('Playlist', playlist.get_id(), model, nextIter, 5, 11)
                     self.player.set_playing(True)
 
                 # Update songs count
@@ -1343,9 +1347,9 @@ class Search(ViewContainer):
             self.set_visible_child(self._artistAlbumsWidget)
             self.header_bar.searchbar.show_bar(False)
         elif self._model[_iter][11] == 'song':
-            if self._model.get_value(_iter, 8) != self.errorIconName:
+            if self._model.get_value(_iter, 12) != DiscoveryStatus.FAILED:
                 child_iter = self.songs_model.convert_child_iter_to_iter(_iter)[1]
-                self.player.set_playlist('Search Results', None, self.songs_model, child_iter, 5)
+                self.player.set_playlist('Search Results', None, self.songs_model, child_iter, 5, 12)
                 self.player.set_playing(True)
         else:  # Headers
             if self.view.get_generic_view().row_expanded(path):
@@ -1612,7 +1616,8 @@ class Search(ViewContainer):
             GObject.TYPE_STRING,
             GObject.TYPE_BOOLEAN,
             GObject.TYPE_BOOLEAN,
-            GObject.TYPE_STRING     # type
+            GObject.TYPE_STRING,    # type
+            GObject.TYPE_INT
         )
         self.filter_model = self._model.filter_new(None)
         self.filter_model.set_visible_func(self._filter_visible_func)
diff --git a/gnomemusic/widgets.py b/gnomemusic/widgets.py
index 6c58502..34dbdf0 100644
--- a/gnomemusic/widgets.py
+++ b/gnomemusic/widgets.py
@@ -36,6 +36,7 @@ from gi.repository import GdkPixbuf, Grl
 from gettext import gettext as _, ngettext
 from gnomemusic.grilo import grilo
 from gnomemusic.albumArtCache import AlbumArtCache
+from gnomemusic.player import DiscoveryStatus
 from gnomemusic.playlists import Playlists, StaticPlaylists
 from gnomemusic import log
 import logging
@@ -107,14 +108,14 @@ class AlbumWidget(Gtk.EventBox):
 
         _iter = self.model.get_iter(path)
 
-        if(self.model.get_value(_iter, 7) != ERROR_ICON_NAME):
+        if self.model.get_value(_iter, 10) != DiscoveryStatus.FAILED:
             if (self.iterToClean and self.player.playlistId == self.album):
                 item = self.model.get_value(self.iterToClean, 5)
                 title = AlbumArtCache.get_media_title(item)
                 self.model.set_value(self.iterToClean, 0, title)
                 # Hide now playing icon
                 self.model.set_value(self.iterToClean, 6, False)
-            self.player.set_playlist('Album', self.album, self.model, _iter, 5)
+            self.player.set_playlist('Album', self.album, self.model, _iter, 5, 11)
             self.player.set_playing(True)
 
     @log
@@ -180,6 +181,7 @@ class AlbumWidget(Gtk.EventBox):
             GObject.TYPE_BOOLEAN,
             GObject.TYPE_BOOLEAN,  # icon shown
             GObject.TYPE_BOOLEAN,
+            GObject.TYPE_INT
         )
 
     @log
@@ -362,7 +364,8 @@ class ArtistAlbums(Gtk.Box):
                                    GObject.TYPE_BOOLEAN,  # icon shown
                                    GObject.TYPE_STRING,   # icon
                                    GObject.TYPE_OBJECT,   # song object
-                                   GObject.TYPE_BOOLEAN
+                                   GObject.TYPE_BOOLEAN,
+                                   GObject.TYPE_INT
                                    )
         self.model.connect('row-changed', self._model_row_changed)
 
@@ -642,7 +645,7 @@ class ArtistAlbumWidget(Gtk.Box):
 
         self.player.stop()
         self.player.set_playlist('Artist', self.artist,
-                                 widget.model, widget._iter, 5)
+                                 widget.model, widget._iter, 5, 6)
         self.player.set_playing(True)
 
     @log


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