Play next track at play error

This commit is contained in:
Stein Magnus Jodal 2010-08-14 23:08:42 +02:00
parent b7030b127a
commit 187d3544c4
4 changed files with 54 additions and 31 deletions

View File

@ -35,6 +35,7 @@ greatly improved MPD client support.
- Added new :mod:`mopidy.mixers.GStreamerSoftwareMixer` which now is the - Added new :mod:`mopidy.mixers.GStreamerSoftwareMixer` which now is the
default mixer on all platforms. default mixer on all platforms.
- New setting ``MIXER_MAX_VOLUME`` for capping the maximum output volume. - New setting ``MIXER_MAX_VOLUME`` for capping the maximum output volume.
- If failing to play a track, playback will skip to the next track.
- MPD frontend: - MPD frontend:
- Relocate from :mod:`mopidy.mpd` to :mod:`mopidy.frontends.mpd`. - Relocate from :mod:`mopidy.mpd` to :mod:`mopidy.frontends.mpd`.

View File

@ -272,27 +272,24 @@ class BasePlaybackController(object):
def next(self): def next(self):
"""Play the next track.""" """Play the next track."""
original_cp_track = self.current_cp_track
if self.state == self.STOPPED: if self.state == self.STOPPED:
return return
elif self.next_cp_track is not None and self._next(self.next_track):
self.current_cp_track = self.next_cp_track original_cp_track = self.current_cp_track
self.state = self.PLAYING if self.next_cp_track:
elif self.next_cp_track is None: self.play(self.next_cp_track)
else:
self.stop() self.stop()
self.current_cp_track = None self.current_cp_track = None
# FIXME handle in play aswell? # FIXME This should only be applied when reaching end of track, and not
# when pressing "next"
if self.consume: if self.consume:
self.backend.current_playlist.remove(cpid=original_cp_track[0]) self.backend.current_playlist.remove(cpid=original_cp_track[0])
if self.random and self.current_cp_track in self._shuffled: if self.random and self.current_cp_track in self._shuffled:
self._shuffled.remove(self.current_cp_track) self._shuffled.remove(self.current_cp_track)
def _next(self, track):
return self._play(track)
def pause(self): def pause(self):
"""Pause playback.""" """Pause playback."""
if self.state == self.PLAYING and self._pause(): if self.state == self.PLAYING and self._pause():
@ -301,13 +298,16 @@ class BasePlaybackController(object):
def _pause(self): def _pause(self):
raise NotImplementedError raise NotImplementedError
def play(self, cp_track=None): def play(self, cp_track=None, on_error_step=1):
""" """
Play the given track or the currently active track. Play the given track or the currently active track.
:param cp_track: track to play :param cp_track: track to play
:type cp_track: two-tuple (CPID integer, :class:`mopidy.models.Track`) :type cp_track: two-tuple (CPID integer, :class:`mopidy.models.Track`)
or :class:`None` or :class:`None`
:param on_error_step: direction to step at play error, 1 for next
track (default), -1 for previous track
:type on_error_step: int, -1 or 1
""" """
if cp_track is not None: if cp_track is not None:
@ -317,13 +317,14 @@ class BasePlaybackController(object):
if self.state == self.PAUSED and cp_track is None: if self.state == self.PAUSED and cp_track is None:
self.resume() self.resume()
elif cp_track is not None and self._play(cp_track[1]): elif cp_track is not None:
self.current_cp_track = cp_track self.current_cp_track = cp_track
self.state = self.PLAYING self.state = self.PLAYING
if not self._play(cp_track[1]):
# TODO Do something sensible when _play() returns False, like calling if at_error_step == 1:
# next(). Adding this todo instead of just implementing it as I want a self.next()
# test case first. elif at_error_step == -1:
self.previous()
if self.random and self.current_cp_track in self._shuffled: if self.random and self.current_cp_track in self._shuffled:
self._shuffled.remove(self.current_cp_track) self._shuffled.remove(self.current_cp_track)
@ -333,14 +334,11 @@ class BasePlaybackController(object):
def previous(self): def previous(self):
"""Play the previous track.""" """Play the previous track."""
if (self.previous_cp_track is not None if self.previous_cp_track is None:
and self.state != self.STOPPED return
and self._previous(self.previous_track)): if self.state == self.STOPPED:
self.current_cp_track = self.previous_cp_track return
self.state = self.PLAYING self.play(self.previous_cp_track, on_error_step=-1)
def _previous(self, track):
return self._play(track)
def resume(self): def resume(self):
"""If paused, resume playing the current track.""" """If paused, resume playing the current track."""

View File

@ -26,7 +26,7 @@ class LibspotifyPlaybackController(BasePlaybackController):
def _play(self, track): def _play(self, track):
self._set_output_state('READY') self._set_output_state('READY')
if self.state == self.PLAYING: if self.state == self.PLAYING:
self.stop() self.backend.spotify.session.play(0)
if track.uri is None: if track.uri is None:
return False return False
try: try:

View File

@ -345,6 +345,14 @@ class BasePlaybackControllerTest(object):
self.playback.play(self.current_playlist.cp_tracks[-1]) self.playback.play(self.current_playlist.cp_tracks[-1])
self.assertEqual(self.playback.current_track, self.tracks[-1]) self.assertEqual(self.playback.current_track, self.tracks[-1])
@populate_playlist
def test_play_skips_to_next_track_on_failure(self):
# If _play() returns False, it is a failure.
self.playback._play = lambda track: track != self.tracks[0]
self.playback.play()
self.assertNotEqual(self.playback.current_track, self.tracks[0])
self.assertEqual(self.playback.current_track, self.tracks[1])
@populate_playlist @populate_playlist
def test_current_track_after_completed_playlist(self): def test_current_track_after_completed_playlist(self):
self.playback.play(self.current_playlist.cp_tracks[-1]) self.playback.play(self.current_playlist.cp_tracks[-1])
@ -411,6 +419,16 @@ class BasePlaybackControllerTest(object):
self.playback.next() self.playback.next()
self.assertEqual(self.playback.state, self.playback.STOPPED) self.assertEqual(self.playback.state, self.playback.STOPPED)
@populate_playlist
def test_next_skips_to_next_track_on_failure(self):
# If _play() returns False, it is a failure.
self.playback._play = lambda track: track != self.tracks[1]
self.playback.play()
self.assertEqual(self.playback.current_track, self.tracks[0])
self.playback.next()
self.assertNotEqual(self.playback.current_track, self.tracks[1])
self.assertEqual(self.playback.current_track, self.tracks[2])
@populate_playlist @populate_playlist
def test_previous(self): def test_previous(self):
self.playback.play() self.playback.play()
@ -451,6 +469,16 @@ class BasePlaybackControllerTest(object):
self.assertEqual(self.playback.state, self.playback.STOPPED) self.assertEqual(self.playback.state, self.playback.STOPPED)
self.assertEqual(self.playback.current_track, None) self.assertEqual(self.playback.current_track, None)
@populate_playlist
def test_previous_skips_to_previous_track_on_failure(self):
# If _play() returns False, it is a failure.
self.playback._play = lambda track: track != self.tracks[1]
self.playback.play(self.current_playlist.cp_tracks[2])
self.assertEqual(self.playback.current_track, self.tracks[2])
self.playback.previous()
self.assertNotEqual(self.playback.current_track, self.tracks[1])
self.assertEqual(self.playback.current_track, self.tracks[0])
@populate_playlist @populate_playlist
def test_next_track_before_play(self): def test_next_track_before_play(self):
self.assertEqual(self.playback.next_track, self.tracks[0]) self.assertEqual(self.playback.next_track, self.tracks[0])
@ -906,13 +934,9 @@ class BasePlaybackControllerTest(object):
played.append(self.playback.current_track) played.append(self.playback.current_track)
self.playback.next() self.playback.next()
def test_playing_track_with_invalid_uri(self): @populate_playlist
self.backend.current_playlist.load([Track(uri='foobar')])
self.playback.play()
self.assertEqual(self.playback.state, self.playback.STOPPED)
def test_playing_track_that_isnt_in_playlist(self): def test_playing_track_that_isnt_in_playlist(self):
test = lambda: self.playback.play(self.tracks[0]) test = lambda: self.playback.play((17, Track()))
self.assertRaises(AssertionError, test) self.assertRaises(AssertionError, test)