[gnome-music/wip/jfelder/core-restore-player-validation: 5/6] player: Restore song validation
- From: Jean Felder <jfelder src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/jfelder/core-restore-player-validation: 5/6] player: Restore song validation
- Date: Sun, 14 Jul 2019 21:19:15 +0000 (UTC)
commit 78c4a3dc3d3f9f3a729afea022e8966845fab2e5
Author: Jean Felder <jfelder src gnome org>
Date: Sun Jul 14 13:38:28 2019 +0200
player: Restore song validation
Song Validation logic was removed with the big core rework. This
commits restores it.
gnomemusic/coremodel.py | 12 +++++
gnomemusic/coresong.py | 11 ++++
gnomemusic/player.py | 109 ++++++++++++++++++++++++++++-----------
gnomemusic/songliststore.py | 8 +++
gnomemusic/views/songsview.py | 16 +++---
gnomemusic/widgets/songwidget.py | 16 ++++++
6 files changed, 133 insertions(+), 39 deletions(-)
---
diff --git a/gnomemusic/coremodel.py b/gnomemusic/coremodel.py
index 5cf842f2..caf7bae7 100644
--- a/gnomemusic/coremodel.py
+++ b/gnomemusic/coremodel.py
@@ -171,6 +171,9 @@ class CoreModel(GObject.GObject):
song.bind_property(
"state", coresong, "state",
GObject.BindingFlags.SYNC_CREATE)
+ song.bind_property(
+ "validation", coresong, "validation",
+ GObject.BindingFlags.SYNC_CREATE)
with model.freeze_notify():
@@ -195,6 +198,9 @@ class CoreModel(GObject.GObject):
song.bind_property(
"state", model_song, "state",
GObject.BindingFlags.SYNC_CREATE)
+ song.bind_property(
+ "validation", model_song, "validation",
+ GObject.BindingFlags.SYNC_CREATE)
self.emit("playlist-loaded")
elif playlist_type == PlayerPlaylist.Type.ARTIST:
@@ -218,6 +224,9 @@ class CoreModel(GObject.GObject):
song.bind_property(
"state", model_song, "state",
GObject.BindingFlags.SYNC_CREATE)
+ song.bind_property(
+ "validation", model_song, "validation",
+ GObject.BindingFlags.SYNC_CREATE)
self.emit("playlist-loaded")
elif playlist_type == PlayerPlaylist.Type.SONGS:
@@ -266,6 +275,9 @@ class CoreModel(GObject.GObject):
song.bind_property(
"state", model_song, "state",
GObject.BindingFlags.SYNC_CREATE)
+ song.bind_property(
+ "validation", model_song, "validation",
+ GObject.BindingFlags.SYNC_CREATE)
# self._search_signal_id = self._song_search_model.connect(
# "items-changed", _on_items_changed)
diff --git a/gnomemusic/coresong.py b/gnomemusic/coresong.py
index 793d2d4a..0b525537 100644
--- a/gnomemusic/coresong.py
+++ b/gnomemusic/coresong.py
@@ -1,3 +1,5 @@
+from enum import IntEnum
+
import gi
gi.require_version('Grl', '0.3')
from gi.repository import Grl, GLib, GObject
@@ -20,6 +22,14 @@ class CoreSong(GObject.GObject):
title = GObject.Property(type=str)
track_number = GObject.Property(type=int)
url = GObject.Property(type=str)
+ validation = GObject.Property() # FIXME: How to set an IntEnum type?
+
+ class Validation(IntEnum):
+ """Enum for song validation"""
+ PENDING = 0
+ IN_PROGRESS = 1
+ FAILED = 2
+ SUCCEEDED = 3
def __init__(self, media, coreselection, grilo):
super().__init__()
@@ -30,6 +40,7 @@ class CoreSong(GObject.GObject):
self._selected = False
self.props.grlid = media.get_source() + media.get_id()
+ self.props.validation = CoreSong.Validation.PENDING
self.update(media)
def __eq__(self, other):
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 619987b8..6a64bc42 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -52,14 +52,6 @@ class RepeatMode(IntEnum):
SHUFFLE = 3
-class ValidationStatus(IntEnum):
- """Enum for song validation"""
- PENDING = 0
- IN_PROGRESS = 1
- FAILED = 2
- SUCCEEDED = 3
-
-
class PlayerField(IntEnum):
"""Enum for player model fields"""
SONG = 0
@@ -81,10 +73,6 @@ class PlayerPlaylist(GObject.GObject):
PLAYLIST = 3
SEARCH_RESULT = 4
- __gsignals__ = {
- 'song-validated': (GObject.SignalFlags.RUN_FIRST, None, (int, int)),
- }
-
repeat_mode = GObject.Property(type=int, default=RepeatMode.NONE)
def __repr__(self):
@@ -102,10 +90,10 @@ class PlayerPlaylist(GObject.GObject):
self._type = -1
self._id = -1
- # self._validation_indexes = None
- # self._discoverer = GstPbutils.Discoverer()
- # self._discoverer.connect('discovered', self._on_discovered)
- # self._discoverer.start()
+ self._validation_songs = {}
+ self._discoverer = GstPbutils.Discoverer()
+ self._discoverer.connect("discovered", self._on_discovered)
+ self._discoverer.start()
self._model = self._app.props.coremodel.props.playlist_sort
@@ -187,10 +175,14 @@ class PlayerPlaylist(GObject.GObject):
next_position = self.props.position + 1
self._model[self.props.position].props.state = SongWidget.State.PLAYED
- self._model[next_position].props.state = SongWidget.State.PLAYING
-
self._position = next_position
+ next_song = self._model[next_position]
+ if next_song.props.validation == CoreSong.Validation.FAILED:
+ return self.next()
+
+ next_song.props.state = SongWidget.State.PLAYING
+ self._validate_next_song()
return True
@log
@@ -212,10 +204,14 @@ class PlayerPlaylist(GObject.GObject):
previous_position = self.props.position - 1
self._model[self.props.position].props.state = SongWidget.State.PLAYED
- self._model[previous_position].props.state = SongWidget.State.PLAYING
-
self._position = previous_position
+ previous_song = self._model[previous_position]
+ if previous_song.props.validation == CoreSong.Validation.FAILED:
+ return self.previous()
+
+ self._model[previous_position].props.state = SongWidget.State.PLAYING
+ self._validate_previous_song()
return True
@GObject.Property(type=int, default=0, flags=GObject.ParamFlags.READABLE)
@@ -266,11 +262,17 @@ class PlayerPlaylist(GObject.GObject):
position = 0
song = self._model.get_item(position)
song.props.state = SongWidget.State.PLAYING
+ self._position = position
+ self._validate_song(song)
+ self._validate_next_song()
return song
- for coresong in self._model:
+ for idx, coresong in enumerate(self._model):
if coresong == song:
coresong.props.state = SongWidget.State.PLAYING
+ self._position = idx
+ self._validate_song(song)
+ self._validate_next_song()
return song
return None
@@ -296,6 +298,62 @@ class PlayerPlaylist(GObject.GObject):
elif self.props.repeat_mode in [RepeatMode.NONE, RepeatMode.ALL]:
self._model.set_sort_func(None)
+ def _validate_song(self, coresong):
+ # Song is being processed or has already been processed.
+ # Nothing to do.
+ if coresong.props.validation > CoreSong.Validation.PENDING:
+ return
+
+ url = coresong.props.url
+ if not url:
+ logger.warning(
+ "The item {} doesn't have a URL set.".format(coresong))
+ return
+ if not url.startswith("file://"):
+ logger.debug(
+ "Skipping validation of {} as not a local file".format(url))
+ return
+
+ coresong.props.validation = CoreSong.Validation.IN_PROGRESS
+ self._validation_songs[url] = coresong
+ self._discoverer.discover_uri_async(url)
+
+ def _validate_next_song(self):
+ if self.props.repeat_mode == RepeatMode.SONG:
+ return
+
+ current_position = self.props.position
+ next_position = current_position + 1
+ if next_position == self._model.get_n_items():
+ if self.props.repeat_mode != RepeatMode.ALL:
+ return
+ next_position = 0
+
+ self._validate_song(self._model[next_position])
+
+ def _validate_previous_song(self):
+ if self.props.repeat_mode == RepeatMode.SONG:
+ return
+
+ current_position = self.props.position
+ previous_position = current_position - 1
+ if previous_position < 0:
+ if self.props.repeat_mode != RepeatMode.ALL:
+ return
+ previous_position = self._model.get_n_items() - 1
+
+ self._validate_song(self._model[previous_position])
+
+ def _on_discovered(self, discoverer, info, error):
+ url = info.get_uri()
+ coresong = self._validation_songs[url]
+
+ if error:
+ logger.warning("Info {}: error: {}".format(info, error))
+ coresong.props.validation = CoreSong.Validation.FAILED
+ else:
+ coresong.props.validation = CoreSong.Validation.SUCCEEDED
+
@GObject.Property(type=int, flags=GObject.ParamFlags.READABLE)
def playlist_id(self):
"""Get playlist unique identifier.
@@ -324,8 +382,7 @@ class Player(GObject.GObject):
__gsignals__ = {
'playlist-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
'seek-finished': (GObject.SignalFlags.RUN_FIRST, None, ()),
- 'song-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
- 'song-validated': (GObject.SignalFlags.RUN_FIRST, None, (int, int)),
+ 'song-changed': (GObject.SignalFlags.RUN_FIRST, None, ())
}
state = GObject.Property(type=int, default=Playback.STOPPED)
@@ -352,7 +409,6 @@ class Player(GObject.GObject):
self._gapless_set = False
self._playlist = PlayerPlaylist(self._app)
- self._playlist.connect('song-validated', self._on_song_validated)
self._settings = application.props.settings
self._settings.connect(
@@ -537,11 +593,6 @@ class Player(GObject.GObject):
self._playlist.add_song(song, song_index)
self.emit('playlist-changed')
- @log
- def _on_song_validated(self, playlist, index, status):
- self.emit('song-validated', index, status)
- return True
-
@log
def playing_playlist(self, playlist_type, playlist_id):
"""Test if the current playlist matches type and id.
diff --git a/gnomemusic/songliststore.py b/gnomemusic/songliststore.py
index a460aeb0..b923943e 100644
--- a/gnomemusic/songliststore.py
+++ b/gnomemusic/songliststore.py
@@ -70,6 +70,8 @@ class SongListStore(Gtk.ListStore):
int(coresong.props.favorite), coresong])
coresong.connect(
"notify::favorite", self._on_favorite_changed)
+ coresong.connect(
+ "notify::state", self._on_state_changed)
def _on_favorite_changed(self, coresong, value):
for row in self:
@@ -77,6 +79,12 @@ class SongListStore(Gtk.ListStore):
row[6] = coresong.props.favorite
break
+ def _on_state_changed(self, coresong, value):
+ for row in self:
+ if coresong == row[7]:
+ row[8] = coresong.props.validation
+ break
+
@GObject.Property(
type=Gio.ListStore, default=None, flags=GObject.ParamFlags.READABLE)
def model(self):
diff --git a/gnomemusic/views/songsview.py b/gnomemusic/views/songsview.py
index 7b238091..1d073a24 100644
--- a/gnomemusic/views/songsview.py
+++ b/gnomemusic/views/songsview.py
@@ -27,6 +27,7 @@ from gettext import gettext as _
from gi.repository import Gdk, Gtk, Pango
from gnomemusic import log
+from gnomemusic.coresong import CoreSong
from gnomemusic.grilo import grilo
from gnomemusic.player import PlayerPlaylist
from gnomemusic.views.baseview import BaseView
@@ -66,7 +67,6 @@ class SongsView(BaseView):
self.player = player
self.player.connect('song-changed', self._update_model)
- self.player.connect('song-validated', self._on_song_validated)
self._model = self._view.props.model
self._view.show()
@@ -143,7 +143,11 @@ class SongsView(BaseView):
if current_song is None:
return
- if model[itr][7].props.grlid == current_song.props.grlid:
+ coresong = model[itr][7]
+ if coresong.props.validation == CoreSong.Validation.FAILED:
+ cell.props.icon_name = self._error_icon_name
+ cell.props.visible = True
+ elif coresong.props.grlid == current_song.props.grlid:
cell.props.icon_name = self._now_playing_icon_name
cell.props.visible = True
else:
@@ -238,14 +242,6 @@ class SongsView(BaseView):
return False
- @log
- def _on_song_validated(self, player, index, status):
- if not player.playing_playlist(PlayerPlaylist.Type.SONGS, None):
- return
-
- iter_ = self.model.get_iter_from_string(str(index))
- self.model[iter_][8] = status
-
@log
def _populate(self, data=None):
"""Populates the view"""
diff --git a/gnomemusic/widgets/songwidget.py b/gnomemusic/widgets/songwidget.py
index 71833339..ae3e5780 100644
--- a/gnomemusic/widgets/songwidget.py
+++ b/gnomemusic/widgets/songwidget.py
@@ -154,6 +154,8 @@ class SongWidget(Gtk.EventBox):
self.props.coresong.bind_property(
"state", self, "state",
GObject.BindingFlags.SYNC_CREATE)
+ self.props.coresong.connect(
+ "notify::validation", self._on_validation_changed)
self._number_label.props.no_show_all = True
@@ -284,8 +286,22 @@ class SongWidget(Gtk.EventBox):
style_ctx.remove_class('playing-song-label')
self._play_icon.set_visible(False)
+ coresong = self.props.coresong
+ if coresong.props.validation == CoreSong.Validation.FAILED:
+ self._play_icon.set_visible(True)
+ style_ctx.add_class("dim-label")
+ return
+
if value == SongWidget.State.PLAYED:
style_ctx.add_class('dim-label')
elif value == SongWidget.State.PLAYING:
self._play_icon.set_visible(True)
style_ctx.add_class('playing-song-label')
+
+ def _on_validation_changed(self, coresong, sate):
+ validation_status = coresong.props.validation
+ if validation_status == CoreSong.Validation.FAILED:
+ self._play_icon.props.icon_name = "dialog-error-symbolic"
+ self._play_icon.set_visible(True)
+ else:
+ self._play_icon.props.icon_name = "media-playback-start-symbolic"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]