Commit d83b7de3 authored by Jean Felder's avatar Jean Felder Committed by Jean Felder

player: Refactor player playlist

Separate player logic from the playlist logic.
Rename discovery logic to validation as this is more accurate of the
underlying logic.
PlayerPlaylist object handles the playlist and songs validation
logic. Player object acts as a glue for the ui and the underlying
logic (playlist and validation).
Use Gobject Properties.

There are 4 ways to launch a song:
1. Click on a song in the current view. The set_playlist method is
called.
2. At the end of the current song. The next method is automatically called.
3. click on the next buttom from the PlayerToolbar. The next method is called.
4. click on the previous buttom from the PlayerToolbar. The previous
method is called.

Validation is a very expensive operation, so only do it when it's
needed. See commit message from 6f1cb8d4.

The Validation logic brings 3 features:
- display an error icon if a song cannot be played
- do not load a song that cannot be played
- when the song changes, try to load the next possible one: if the
next song cannot be loaded, try the one after, etc.

In "set_playlist" method, if the song has already been played the
validation information is already known, nothing to add. If the song
has never been played, there is no information yet. In that case,
validate_current_song and validate_next_song need to be called to
trigger the validation mechanism.

In "next" method, call validate_next_song to continue the validation
mechanism if there is a next song.

In "previous" method, call validate_previous_song to continue the validation
mechanism if there is a previous song.

Closes: #60, #154
parent 1ea45617
...@@ -86,12 +86,12 @@ class InhibitSuspend(GObject.GObject): ...@@ -86,12 +86,12 @@ class InhibitSuspend(GObject.GObject):
if self._player.get_playback_status() == Playback.PLAYING: if self._player.get_playback_status() == Playback.PLAYING:
self._inhibit_suspend() self._inhibit_suspend()
# TODO: The additional check for has_next() is necessary # TODO: The additional check for has_next property is necessary
# since after a track is done, the player # since after a track is done, the player
# goes into STOPPED state before it goes back to PLAYING. # goes into STOPPED state before it goes back to PLAYING.
# To be simplified when the player's behavior is corrected. # To be simplified when the player's behavior is corrected.
if (self._player.get_playback_status() == Playback.PAUSED if (self._player.get_playback_status() == Playback.PAUSED
or (self._player.get_playback_status() == Playback.STOPPED or (self._player.get_playback_status() == Playback.STOPPED
and not self._player.has_next())): and not self._player.props.has_next)):
self._uninhibit_suspend() self._uninhibit_suspend()
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
import codecs import codecs
from gnomemusic.gstplayer import Playback from gnomemusic.gstplayer import Playback
from gnomemusic.player import RepeatMode from gnomemusic.player import PlayerField, PlayerPlaylist, RepeatMode
from gnomemusic.grilo import grilo from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists from gnomemusic.playlists import Playlists
from gnomemusic.utils import View from gnomemusic.utils import View
...@@ -238,9 +238,6 @@ class MediaPlayer2Service(Server): ...@@ -238,9 +238,6 @@ class MediaPlayer2Service(Server):
playlists.connect('playlist-deleted', self._on_playlists_count_changed) playlists.connect('playlist-deleted', self._on_playlists_count_changed)
grilo.connect('ready', self._on_grilo_ready) grilo.connect('ready', self._on_grilo_ready)
self.playlists = [] self.playlists = []
self.playlist = None
self.playlist_insert_handler = 0
self.playlist_delete_handler = 0
self.first_song_handler = 0 self.first_song_handler = 0
@log @log
...@@ -255,9 +252,9 @@ class MediaPlayer2Service(Server): ...@@ -255,9 +252,9 @@ class MediaPlayer2Service(Server):
@log @log
def _get_loop_status(self): def _get_loop_status(self):
if self.player.repeat == RepeatMode.NONE: if self.player.props.repeat_mode == RepeatMode.NONE:
return 'None' return 'None'
elif self.player.repeat == RepeatMode.SONG: elif self.player.props.repeat_mode == RepeatMode.SONG:
return 'Track' return 'Track'
else: else:
return 'Playlist' return 'Playlist'
...@@ -265,7 +262,7 @@ class MediaPlayer2Service(Server): ...@@ -265,7 +262,7 @@ class MediaPlayer2Service(Server):
@log @log
def _get_metadata(self, media=None): def _get_metadata(self, media=None):
if not media: if not media:
media = self.player.get_current_media() media = self.player.props.current_song
if not media: if not media:
return {} return {}
...@@ -353,17 +350,17 @@ class MediaPlayer2Service(Server): ...@@ -353,17 +350,17 @@ class MediaPlayer2Service(Server):
@log @log
def _get_media_from_id(self, track_id): def _get_media_from_id(self, track_id):
for track in self.player.playlist: for track in self.player.get_songs():
media = track[self.player.Field.SONG] media = track[PlayerField.SONG]
if track_id == self._get_media_id(media): if track_id == self._get_media_id(media):
return media return media
return None return None
@log @log
def _get_track_list(self): def _get_track_list(self):
if self.player.playlist: if self.player.props.playing:
return [self._get_media_id(track[self.player.Field.SONG]) return [self._get_media_id(song[PlayerField.SONG])
for track in self.player.playlist] for song in self.player.get_songs()]
else: else:
return [] return []
...@@ -400,16 +397,19 @@ class MediaPlayer2Service(Server): ...@@ -400,16 +397,19 @@ class MediaPlayer2Service(Server):
@log @log
def _get_active_playlist(self): def _get_active_playlist(self):
playlist = self._get_playlist_from_id(self.player.playlist_id) \ playlist = None
if self.player.playlist_type == 'Playlist' else None playlist_name = ''
playlistName = utils.get_media_title(playlist) \ if self.player.get_playlist_type() == PlayerPlaylist.Type.PLAYLIST:
if playlist else '' playlist = self._get_playlist_from_id(
return (playlist is not None, self.player.get_playlist_id())
(self._get_playlist_path(playlist), playlistName, '')) playlist_name = utils.get_media_title(playlist)
path = self._get_playlist_path(playlist)
return (playlist is not None, (path, playlist_name, ''))
@log @log
def _on_current_song_changed(self, player, current_iter, data=None): def _on_current_song_changed(self, player, position):
if self.player.repeat == RepeatMode.SONG: if self.player.props.repeat_mode == RepeatMode.SONG:
self.Seeked(0) self.Seeked(0)
self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE, self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE,
...@@ -441,7 +441,7 @@ class MediaPlayer2Service(Server): ...@@ -441,7 +441,7 @@ class MediaPlayer2Service(Server):
self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE, self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE,
{ {
'LoopStatus': GLib.Variant('s', self._get_loop_status()), 'LoopStatus': GLib.Variant('s', self._get_loop_status()),
'Shuffle': GLib.Variant('b', self.player.repeat == RepeatMode.SHUFFLE), 'Shuffle': GLib.Variant('b', self.player.props.repeat_mode == RepeatMode.SHUFFLE),
}, },
[]) [])
...@@ -457,8 +457,8 @@ class MediaPlayer2Service(Server): ...@@ -457,8 +457,8 @@ class MediaPlayer2Service(Server):
def _on_prev_next_invalidated(self, player, data=None): def _on_prev_next_invalidated(self, player, data=None):
self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE, self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYER_IFACE,
{ {
'CanGoNext': GLib.Variant('b', self.player.has_next()), 'CanGoNext': GLib.Variant('b', self.player.props.has_next),
'CanGoPrevious': GLib.Variant('b', self.player.has_previous()), 'CanGoPrevious': GLib.Variant('b', self.player.props.has_previous),
}, },
[]) [])
...@@ -467,7 +467,7 @@ class MediaPlayer2Service(Server): ...@@ -467,7 +467,7 @@ class MediaPlayer2Service(Server):
if self.first_song_handler: if self.first_song_handler:
model.disconnect(self.first_song_handler) model.disconnect(self.first_song_handler)
self.first_song_handler = 0 self.first_song_handler = 0
self.player.set_playlist('Songs', None, model, iter_) self.player.set_playlist(PlayerPlaylist.Type.SONG, None, model, iter_)
self.player.play() self.player.play()
@log @log
...@@ -476,13 +476,6 @@ class MediaPlayer2Service(Server): ...@@ -476,13 +476,6 @@ class MediaPlayer2Service(Server):
@log @log
def _on_playlist_changed(self, player, data=None): def _on_playlist_changed(self, player, data=None):
if self.playlist:
if self.playlist_insert_handler:
self.playlist.disconnect(self.playlist_insert_handler)
if self.playlist_delete_handler:
self.playlist.disconnect(self.playlist_delete_handler)
self.playlist = self.player.playlist
self._on_playlist_modified() self._on_playlist_modified()
self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYLISTS_IFACE, self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_PLAYLISTS_IFACE,
...@@ -491,18 +484,12 @@ class MediaPlayer2Service(Server): ...@@ -491,18 +484,12 @@ class MediaPlayer2Service(Server):
}, },
[]) [])
self.playlist_insert_handler = \
self.playlist.connect('row-inserted', self._on_playlist_modified)
self.playlist_delete_handler = \
self.playlist.connect('row-deleted', self._on_playlist_modified)
@log @log
def _on_playlist_modified(self, path=None, _iter=None, data=None): def _on_playlist_modified(self, path=None, _iter=None, data=None):
if self.player.current_song and self.player.current_song.valid(): if self.player.props.current_song:
path = self.player.current_song.get_path()
current_song = self.player.playlist[path][self.player.Field.SONG]
track_list = self._get_track_list() track_list = self._get_track_list()
self.TrackListReplaced(track_list, self._get_media_id(current_song)) self.TrackListReplaced(
track_list, self._get_media_id(self.player.props.current_song))
self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_TRACKLIST_IFACE, self.PropertiesChanged(MediaPlayer2Service.MEDIA_PLAYER2_TRACKLIST_IFACE,
{ {
'Tracks': GLib.Variant('ao', track_list), 'Tracks': GLib.Variant('ao', track_list),
...@@ -551,7 +538,7 @@ class MediaPlayer2Service(Server): ...@@ -551,7 +538,7 @@ class MediaPlayer2Service(Server):
self.player.stop() self.player.stop()
def Play(self): def Play(self):
if self.player.playlist is not None: if self.player.get_songs():
self.player.play() self.player.play()
elif self.first_song_handler == 0: elif self.first_song_handler == 0:
window = self.app.get_active_window() window = self.app.get_active_window()
...@@ -594,13 +581,9 @@ class MediaPlayer2Service(Server): ...@@ -594,13 +581,9 @@ class MediaPlayer2Service(Server):
pass pass
def GoTo(self, track_id): def GoTo(self, track_id):
for track in self.player.playlist: for index, song in enumerate(self.player.get_songs()):
media = track[self.player.Field.SONG] if track_id == self._get_media_id(song[PlayerField.SONG]):
if track_id == self._get_media_id(media): self.player_play(index)
self.player.set_playlist(
self.player.playlist_type, self.player.playlist_id,
self.player.playlist, track.iter)
self.player.play()
return return
def TrackListReplaced(self, tracks, current_song): def TrackListReplaced(self, tracks, current_song):
...@@ -682,16 +665,16 @@ class MediaPlayer2Service(Server): ...@@ -682,16 +665,16 @@ class MediaPlayer2Service(Server):
'PlaybackStatus': GLib.Variant('s', self._get_playback_status()), 'PlaybackStatus': GLib.Variant('s', self._get_playback_status()),
'LoopStatus': GLib.Variant('s', self._get_loop_status()), 'LoopStatus': GLib.Variant('s', self._get_loop_status()),
'Rate': GLib.Variant('d', 1.0), 'Rate': GLib.Variant('d', 1.0),
'Shuffle': GLib.Variant('b', self.player.repeat == RepeatMode.SHUFFLE), 'Shuffle': GLib.Variant('b', self.player.props.repeat_mode == RepeatMode.SHUFFLE),
'Metadata': GLib.Variant('a{sv}', self._get_metadata()), 'Metadata': GLib.Variant('a{sv}', self._get_metadata()),
'Volume': GLib.Variant('d', self.player.get_volume()), 'Volume': GLib.Variant('d', self.player.get_volume()),
'Position': GLib.Variant('x', self.player.get_position()), 'Position': GLib.Variant('x', self.player.get_position()),
'MinimumRate': GLib.Variant('d', 1.0), 'MinimumRate': GLib.Variant('d', 1.0),
'MaximumRate': GLib.Variant('d', 1.0), 'MaximumRate': GLib.Variant('d', 1.0),
'CanGoNext': GLib.Variant('b', self.player.has_next()), 'CanGoNext': GLib.Variant('b', self.player.props.has_next),
'CanGoPrevious': GLib.Variant('b', self.player.has_previous()), 'CanGoPrevious': GLib.Variant('b', self.player.props.has_previous),
'CanPlay': GLib.Variant('b', self.player.current_song is not None), 'CanPlay': GLib.Variant('b', self.player.props.current_song is not None),
'CanPause': GLib.Variant('b', self.player.current_song is not None), 'CanPause': GLib.Variant('b', self.player.props.current_song is not None),
'CanSeek': GLib.Variant('b', True), 'CanSeek': GLib.Variant('b', True),
'CanControl': GLib.Variant('b', True), 'CanControl': GLib.Variant('b', True),
} }
...@@ -727,16 +710,16 @@ class MediaPlayer2Service(Server): ...@@ -727,16 +710,16 @@ class MediaPlayer2Service(Server):
self.player.set_volume(new_value) self.player.set_volume(new_value)
elif property_name == 'LoopStatus': elif property_name == 'LoopStatus':
if new_value == 'None': if new_value == 'None':
self.player.set_repeat_mode(RepeatMode.NONE) self.player.props.repeat_mode = RepeatMode.NONE
elif new_value == 'Track': elif new_value == 'Track':
self.player.set_repeat_mode(RepeatMode.SONG) self.player.props.repeat_mode = RepeatMode.SONG
elif new_value == 'Playlist': elif new_value == 'Playlist':
self.player.set_repeat_mode(RepeatMode.ALL) self.player.props.repeat_mode = RepeatMode.ALL
elif property_name == 'Shuffle': elif property_name == 'Shuffle':
if new_value: if new_value:
self.player.set_repeat_mode(RepeatMode.SHUFFLE) self.player.props.repeat_mode = RepeatMode.SHUFFLE
else: else:
self.player.set_repeat_mode(RepeatMode.NONE) self.player.props.repeat_mode = RepeatMode.NONE
else: else:
raise Exception( raise Exception(
'org.mpris.MediaPlayer2.GnomeMusic', 'org.mpris.MediaPlayer2.GnomeMusic',
......
This diff is collapsed.
...@@ -28,6 +28,7 @@ from gi.repository import Gdk, GLib, Gtk ...@@ -28,6 +28,7 @@ from gi.repository import Gdk, GLib, Gtk
from gnomemusic import log from gnomemusic import log
from gnomemusic.grilo import grilo from gnomemusic.grilo import grilo
from gnomemusic.player import PlayerPlaylist
from gnomemusic.views.baseview import BaseView from gnomemusic.views.baseview import BaseView
from gnomemusic.widgets.artistalbumswidget import ArtistAlbumsWidget from gnomemusic.widgets.artistalbumswidget import ArtistAlbumsWidget
from gnomemusic.widgets.sidebarrow import SidebarRow from gnomemusic.widgets.sidebarrow import SidebarRow
...@@ -108,7 +109,8 @@ class ArtistsView(BaseView): ...@@ -108,7 +109,8 @@ class ArtistsView(BaseView):
widget = self._artists[artist.casefold()]['widget'] widget = self._artists[artist.casefold()]['widget']
if widget: if widget:
if self.player.playing_playlist('Artist', widget.props.artist): if self.player.playing_playlist(
PlayerPlaylist.Type.ARTIST, widget.artist):
self._artist_albums_widget = widget.get_parent() self._artist_albums_widget = widget.get_parent()
GLib.idle_add( GLib.idle_add(
self._view.set_visible_child, self._artist_albums_widget) self._view.set_visible_child, self._artist_albums_widget)
......
...@@ -28,7 +28,7 @@ from gi.repository import Gio, GLib, GObject, Gtk, Pango ...@@ -28,7 +28,7 @@ from gi.repository import Gio, GLib, GObject, Gtk, Pango
from gnomemusic import log from gnomemusic import log
from gnomemusic.grilo import grilo from gnomemusic.grilo import grilo
from gnomemusic.player import DiscoveryStatus from gnomemusic.player import ValidationStatus, PlayerPlaylist
from gnomemusic.playlists import Playlists, StaticPlaylists from gnomemusic.playlists import Playlists, StaticPlaylists
from gnomemusic.views.baseview import BaseView from gnomemusic.views.baseview import BaseView
from gnomemusic.widgets.notificationspopup import PlaylistNotification from gnomemusic.widgets.notificationspopup import PlaylistNotification
...@@ -131,6 +131,7 @@ class PlaylistView(BaseView): ...@@ -131,6 +131,7 @@ class PlaylistView(BaseView):
self.model.connect('row-deleted', self._on_song_deleted) self.model.connect('row-deleted', self._on_song_deleted)
self.player.connect('song-changed', self._update_model) self.player.connect('song-changed', self._update_model)
self.player.connect('song-validated', self._on_song_validated)
playlists.connect('playlist-created', self._on_playlist_created) playlists.connect('playlist-created', self._on_playlist_created)
playlists.connect('playlist-updated', self._on_playlist_update) playlists.connect('playlist-updated', self._on_playlist_update)
playlists.connect( playlists.connect(
...@@ -226,14 +227,14 @@ class PlaylistView(BaseView): ...@@ -226,14 +227,14 @@ class PlaylistView(BaseView):
def _on_list_widget_icon_render(self, col, cell, model, _iter, data): def _on_list_widget_icon_render(self, col, cell, model, _iter, data):
if not self.player.playing_playlist( if not self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, self._current_playlist.get_id()):
cell.set_visible(False) cell.set_visible(False)
return return
if not model.iter_is_valid(_iter): if not model.iter_is_valid(_iter):
return return
if model[_iter][11] == DiscoveryStatus.FAILED: if model[_iter][11] == ValidationStatus.FAILED:
cell.set_property('icon-name', self._error_icon_name) cell.set_property('icon-name', self._error_icon_name)
cell.set_visible(True) cell.set_visible(True)
elif model[_iter][5].get_url() == self.player.url: elif model[_iter][5].get_url() == self.player.url:
...@@ -243,15 +244,19 @@ class PlaylistView(BaseView): ...@@ -243,15 +244,19 @@ class PlaylistView(BaseView):
cell.set_visible(False) cell.set_visible(False)
@log @log
def _update_model(self, player, playlist, current_iter): def _update_model(self, player, position):
"""Updates model when the song changes
:param Player player: The main player object
:param int position: current song position
"""
if self._iter_to_clean: if self._iter_to_clean:
self._iter_to_clean_model[self._iter_to_clean][10] = False self._iter_to_clean_model[self._iter_to_clean][10] = False
if not player.playing_playlist( if not player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, self._current_playlist.get_id()):
return False return False
pos_str = playlist.get_path(current_iter).to_string() iter_ = self.model.get_iter_from_string(str(position))
iter_ = self.model.get_iter_from_string(pos_str)
self.model[iter_][10] = True self.model[iter_][10] = True
if self.model[iter_][8] != self._error_icon_name: if self.model[iter_][8] != self._error_icon_name:
self._iter_to_clean = iter_.copy() self._iter_to_clean = iter_.copy()
...@@ -304,6 +309,15 @@ class PlaylistView(BaseView): ...@@ -304,6 +309,15 @@ class PlaylistView(BaseView):
self._sidebar.select_row(row) self._sidebar.select_row(row)
self._sidebar.emit('row-activated', row) self._sidebar.emit('row-activated', row)
@log
def _on_song_validated(self, player, index, status):
if not self.player.playing_playlist(
PlayerPlaylist.Type.PLAYLIST, self._current_playlist.get_id()):
return
iter_ = self.model.get_iter_from_string(str(index))
self.model[iter_][11] = status
@log @log
def _on_song_activated(self, widget, path, column): def _on_song_activated(self, widget, path, column):
"""Action performed when clicking on a song """Action performed when clicking on a song
...@@ -327,8 +341,8 @@ class PlaylistView(BaseView): ...@@ -327,8 +341,8 @@ class PlaylistView(BaseView):
_iter = self.model.get_iter(path) _iter = self.model.get_iter(path)
if self.model[_iter][8] != self._error_icon_name: if self.model[_iter][8] != self._error_icon_name:
self.player.set_playlist( self.player.set_playlist(
'Playlist', self._current_playlist.get_id(), self.model, PlayerPlaylist.Type.PLAYLIST,
_iter) self._current_playlist.get_id(), self.model, _iter)
self.player.play() self.player.play()
# 'row-activated' signal is emitted before 'drag-begin' signal. # 'row-activated' signal is emitted before 'drag-begin' signal.
...@@ -376,7 +390,7 @@ class PlaylistView(BaseView): ...@@ -376,7 +390,7 @@ class PlaylistView(BaseView):
def _on_song_deleted(self, model, path): def _on_song_deleted(self, model, path):
"""Save new playlist order after drag and drop operation. """Save new playlist order after drag and drop operation.
Update player's playlist if necessary. Update player's playlist if the playlist is being played.
""" """
if not self._song_drag['active']: if not self._song_drag['active']:
return return
...@@ -390,24 +404,21 @@ class PlaylistView(BaseView): ...@@ -390,24 +404,21 @@ class PlaylistView(BaseView):
first_pos = min(new_pos, prev_pos) first_pos = min(new_pos, prev_pos)
last_pos = max(new_pos, prev_pos) last_pos = max(new_pos, prev_pos)
# update player's playlist. # update player's playlist if necessary
if self.player.playing_playlist( if self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, self._current_playlist.get_id()):
playing_old_path = self.player.current_song.get_path().to_string() if new_pos < prev_pos:
playing_old_pos = int(playing_old_path) prev_pos -= 1
iter_ = model.get_iter_from_string(playing_old_path) else:
# if playing song position has changed new_pos -= 1
if playing_old_pos >= first_pos and playing_old_pos < last_pos: current_index = self.player.playlist_change_position(
current_player_song = self.player.get_current_media() prev_pos, new_pos)
for row in model: if current_index >= 0:
if row[5].get_id() == current_player_song.get_id(): current_iter = model.get_iter_from_string(str(current_index))
iter_ = row.iter self._iter_to_clean = current_iter
self._iter_to_clean = iter_ self._iter_to_clean_model = model
self._iter_to_clean_model = model
break # update playlist's storage
self.player.set_playlist(
'Playlist', self._current_playlist.get_id(), model, iter_)
positions = [] positions = []
songs = [] songs = []
for pos in range(first_pos, last_pos): for pos in range(first_pos, last_pos):
...@@ -658,7 +669,8 @@ class PlaylistView(BaseView): ...@@ -658,7 +669,8 @@ class PlaylistView(BaseView):
or self._sidebar.get_row_at_index(index - 1)) or self._sidebar.get_row_at_index(index - 1))
self._sidebar.remove(selection) self._sidebar.remove(selection)
if self.player.playing_playlist('Playlist', playlist_id): if self.player.playing_playlist(
PlayerPlaylist.Type.PLAYLIST, playlist_id):
self.player.stop() self.player.stop()
self.set_player_visible(False) self.set_player_visible(False)
...@@ -688,10 +700,12 @@ class PlaylistView(BaseView): ...@@ -688,10 +700,12 @@ class PlaylistView(BaseView):
and playlist.get_id() == self._current_playlist.get_id()): and playlist.get_id() == self._current_playlist.get_id()):
iter_ = self._add_song_to_model( iter_ = self._add_song_to_model(
song_todelete['song'], self.model, song_todelete['index']) song_todelete['song'], self.model, song_todelete['index'])
playlist_id = self._current_playlist.get_id()
if self.player.playing_playlist( if self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, playlist_id):
song = self.model[iter_][5]
path = self.model.get_path(iter_) path = self.model.get_path(iter_)
self.player.add_song(self.model, path, iter_) self.player.add_song(song, int(path.to_string()))
self._songs_todelete.pop(media_id) self._songs_todelete.pop(media_id)
@log @log
...@@ -739,23 +753,23 @@ class PlaylistView(BaseView): ...@@ -739,23 +753,23 @@ class PlaylistView(BaseView):
def _on_song_added_to_playlist(self, playlists, playlist, item): def _on_song_added_to_playlist(self, playlists, playlist, item):
if self._is_current_playlist(playlist): if self._is_current_playlist(playlist):
iter_ = self._add_song_to_model(item, self.model) iter_ = self._add_song_to_model(item, self.model)
playlist_id = self._current_playlist.get_id()
if self.player.playing_playlist( if self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, playlist_id):
path = self.model.get_path(iter_) path = self.model.get_path(iter_)
self.player.add_song(self.model, path, iter_) self.player.add_song(item, int(path.to_string()))
@log @log
def _remove_song_from_playlist(self, playlist, item, index): def _remove_song_from_playlist(self, playlist, item, index):
if not self._is_current_playlist(playlist): if not self._is_current_playlist(playlist):
return return
model = self.model
iter_ = model.get_iter_from_string(str(index))
if self.player.playing_playlist( if self.player.playing_playlist(
'Playlist', self._current_playlist.get_id()): PlayerPlaylist.Type.PLAYLIST, self._current_playlist.get_id()):
self.player.remove_song(model, model.get_path(iter_)) self.player.remove_song(index)
model.remove(iter_)
iter_ = self.model.get_iter_from_string(str(index))
self.model.remove(iter_)
self._update_songs_count(self._songs_count - 1) self._update_songs_count(self._songs_count - 1)
......
...@@ -28,7 +28,7 @@ from gi.repository import Gd, Gdk, GdkPixbuf, GObject, Grl, Gtk, Pango ...@@ -28,7 +28,7 @@ from gi.repository import Gd, Gdk, GdkPixbuf, GObject, Grl, Gtk, Pango
from gnomemusic.albumartcache import Art from gnomemusic.albumartcache import Art
from gnomemusic.grilo import grilo from gnomemusic.grilo import grilo
from gnomemusic import log from gnomemusic import log
from gnomemusic.player import DiscoveryStatus from gnomemusic.player import ValidationStatus, PlayerPlaylist
from gnomemusic.playlists import Playlists from gnomemusic.playlists import Playlists
from gnomemusic.query import Query from gnomemusic.query import Query
from gnomemusic.utils import View from gnomemusic.utils import View
...@@ -157,10 +157,11 @@ class SearchView(BaseView): ...@@ -157,10 +157,11 @@ class SearchView(BaseView):
self.set_visible_child(self._artist_albums_widget) self.set_visible_child(self._artist_albums_widget)
self._header_bar.searchbar.reveal(False) self._header_bar.searchbar.reveal(False)
elif self.model[_iter][12] == 'song': elif self.model[_iter][12] == 'song':
if self.model[_iter][11] != DiscoveryStatus.FAILED: if self.model[_iter][11] != ValidationStatus.FAILED:
c_iter = self._songs_model.convert_child_iter_to_iter(_iter)[1] c_iter = self._songs_model.convert_child_iter_to_iter(_iter)[1]
self.player.set_playlist( self.player.set_playlist(
'Search Results', None, self._songs_model, c_iter) PlayerPlaylist.Type.SEARCH_RESULT, None, self._songs_model,
c_iter)
self.player.play() self.player.play()
else: # Headers else: # Headers
if self._view.row_expanded(path): if self._view.row_expanded(path):
...@@ -554,7 +555,7 @@ class SearchView(BaseView): ...@@ -554,7 +555,7 @@ class SearchView(BaseView):
GObject.TYPE_STRING, GObject.TYPE_STRING,
GObject.TYPE_INT, GObject.TYPE_INT,
GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN,
GObject.TYPE_INT, # discovery status GObject.TYPE_INT, # validation status
GObject.TYPE_STRING, # type GObject.TYPE_STRING, # type
object # album art surface object # album art surface
) )
......
...@@ -28,7 +28,7 @@ from gi.repository import Gdk, GLib, Gtk, Pango ...@@ -28,7 +28,7 @@ from gi.repository import Gdk, GLib, Gtk, Pango
from gnomemusic import log from gnomemusic import log
from gnomemusic.grilo import grilo from gnomemusic.grilo import grilo
from gnomemusic.player import DiscoveryStatus from gnomemusic.player import ValidationStatus, PlayerPlaylist
from gnomemusic.views.baseview import BaseView from gnomemusic.views.baseview import BaseView
import gnomemusic.utils as utils import gnomemusic.utils as utils
...@@ -63,6 +63,7 @@ class SongsView(BaseView): ...@@ -63,6 +63,7 @@ class SongsView(BaseView):
self.player = player self.player = player
self.player.connect('song-changed', self._update_model) self.player.connect('song-changed', self._update_model)
self.player.connect('song-validated', self._on_song_validated)
@log @log
def _setup_view(self): def _setup_view(self):
...@@ -154,7 +155,7 @@ class SongsView(BaseView): ...@@ -154,7 +155,7 @@ class SongsView(BaseView):
cell.props.visible = False cell.props.visible = False
return return
if model[itr][11] == DiscoveryStatus.FAILED: if model[itr][11] == ValidationStatus.FAILED:
cell.props.icon_name = self._error_icon_name cell.props.icon_name = self._error_icon_name
cell.props.visible = True cell.props.visible = True
elif model[itr][5].get_url() == track_uri: elif model[itr][5].get_url() == track_uri:
...@@ -202,9 +203,9 @@ class SongsView(BaseView): ...@@ -202,9 +203,9 @@ class SongsView(BaseView):
return return
itr = self.model.get_iter(path) itr = self.model.get_iter(path)
if self.model[itr][8] != self._error_icon_name: self.player.set_playlist(
self.player.set_playlist('Songs', None, self.model, itr) PlayerPlaylist.Type.SONGS, None, self.model, itr)