Commit 8946b0cc authored by Jean Felder's avatar Jean Felder Committed by Marinus Schraal

player: Restore song validation

Song Validation logic was removed with the big core rework. This
commits restores it.
parent e6fe0be2
......@@ -212,6 +212,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():
......@@ -236,6 +239,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:
......@@ -259,6 +265,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:
......@@ -308,6 +317,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)
......
......@@ -22,6 +22,8 @@
# 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 enum import IntEnum
import gi
gi.require_version('Grl', '0.3')
from gi.repository import Grl, GLib, GObject
......@@ -44,6 +46,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__()
......@@ -54,6 +64,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):
......
......@@ -50,14 +50,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
......@@ -79,10 +71,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):
......@@ -100,10 +88,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
......@@ -185,10 +173,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
......@@ -210,10 +202,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)
......@@ -264,11 +260,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
......@@ -294,6 +296,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.
......@@ -322,8 +380,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)
......@@ -350,7 +407,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(
......@@ -535,11 +591,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.
......
......@@ -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):
......
......@@ -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.player import PlayerPlaylist
from gnomemusic.views.baseview import BaseView
......@@ -65,7 +66,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()
......@@ -142,7 +142,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:
......@@ -236,14 +240,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"""
......
......@@ -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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment