diff --git a/docs/changes.rst b/docs/changes.rst
index 12028a17..76f01610 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -35,12 +35,14 @@ greatly improved MPD client support.
- Added new :mod:`mopidy.mixers.GStreamerSoftwareMixer` which now is the
default mixer on all platforms.
- 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:
- Relocate from :mod:`mopidy.mpd` to :mod:`mopidy.frontends.mpd`.
- Split gigantic protocol implementation into eleven modules.
- Search improvements, including support for multi-word search.
- - Fixed ``play "-1"`` and ``playid "-1"`` behaviour when playlist is empty.
+ - Fixed ``play "-1"`` and ``playid "-1"`` behaviour when playlist is empty
+ or when a current track is set.
- Support ``plchanges "-1"`` to work better with MPDroid.
- Support ``pause`` without arguments to work better with MPDroid.
- Support ``plchanges``, ``play``, ``consume``, ``random``, ``repeat``, and
@@ -50,6 +52,7 @@ greatly improved MPD client support.
- Implement ``seek`` and ``seekid``.
- Fix ``playlistfind`` output so the correct song is played when playing
songs directly from search results in GMPC.
+ - Fix ``load`` so that one can append a playlist to the current playlist.
- Backends:
@@ -73,7 +76,10 @@ greatly improved MPD client support.
- :meth:`mopidy.backends.base.BaseBackend()` now accepts an
``output_queue`` which it can use to send messages (i.e. audio data)
to the output process.
-
+ - :meth:`mopidy.backends.base.BaseCurrentPlaylistController.load()` now
+ appends to the existing playlist. Use
+ :meth:`mopidy.backends.base.BaseCurrentPlaylistController.clear()` if you
+ want to clear it first.
0.1.0a3 (2010-08-03)
diff --git a/docs/installation/libspotify.rst b/docs/installation/libspotify.rst
index 911bf39e..629998b9 100644
--- a/docs/installation/libspotify.rst
+++ b/docs/installation/libspotify.rst
@@ -2,15 +2,21 @@
libspotify installation
***********************
-We are working on a
-`libspotify `_ backend.
-To use the libspotify backend you must install libspotify and
-`pyspotify `_.
+Mopidy uses `libspotify
+`_ for playing music from
+the Spotify music service. To use :mod:`mopidy.backends.libspotify` you must
+install libspotify and `pyspotify `_.
.. warning::
- This backend requires a Spotify premium account, and it requires you to get
- an application key from Spotify before use.
+ This backend requires a `Spotify premium account
+ `_.
+
+.. note::
+
+ This product uses SPOTIFY CORE but is not endorsed, certified or otherwise
+ approved in any way by Spotify. Spotify is the registered trade mark of the
+ Spotify Group.
Installing libspotify on Linux
diff --git a/docs/licenses.rst b/docs/licenses.rst
index c7bf9433..c3a13904 100644
--- a/docs/licenses.rst
+++ b/docs/licenses.rst
@@ -2,7 +2,7 @@
Licenses
********
-For a list of contributors, see :ref:`authors`. For details on who have
+For a list of contributors, see :doc:`authors`. For details on who have
contributed what, please refer to our git repository.
Source code license
diff --git a/mopidy/backends/base/current_playlist.py b/mopidy/backends/base/current_playlist.py
index fc17bbee..8aefe8cd 100644
--- a/mopidy/backends/base/current_playlist.py
+++ b/mopidy/backends/base/current_playlist.py
@@ -66,10 +66,9 @@ class BaseCurrentPlaylistController(object):
def clear(self):
"""Clear the current playlist."""
- self.backend.playback.stop()
- self.backend.playback.current_cp_track = None
self._cp_tracks = []
self.version += 1
+ self.backend.playback.on_current_playlist_change()
def get(self, **criteria):
"""
@@ -107,16 +106,15 @@ class BaseCurrentPlaylistController(object):
def load(self, tracks):
"""
- Replace the tracks in the current playlist with the given tracks.
+ Append the given tracks to the current playlist.
:param tracks: tracks to load
:type tracks: list of :class:`mopidy.models.Track`
"""
- self._cp_tracks = []
self.version += 1
for track in tracks:
self.add(track)
- self.backend.playback.new_playlist_loaded_callback()
+ self.backend.playback.on_current_playlist_change()
def move(self, start, end, to_position):
"""
@@ -148,6 +146,7 @@ class BaseCurrentPlaylistController(object):
to_position += 1
self._cp_tracks = new_cp_tracks
self.version += 1
+ self.backend.playback.on_current_playlist_change()
def remove(self, **criteria):
"""
@@ -192,6 +191,7 @@ class BaseCurrentPlaylistController(object):
random.shuffle(shuffled)
self._cp_tracks = before + shuffled + after
self.version += 1
+ self.backend.playback.on_current_playlist_change()
def mpd_format(self, *args, **kwargs):
"""Not a part of the generic backend API."""
diff --git a/mopidy/backends/base/playback.py b/mopidy/backends/base/playback.py
index 08b7932d..973743e5 100644
--- a/mopidy/backends/base/playback.py
+++ b/mopidy/backends/base/playback.py
@@ -287,11 +287,9 @@ class BasePlaybackController(object):
Typically called by :class:`mopidy.process.CoreProcess` after a message
from a library thread is received.
"""
- next_cp_track = self.cp_track_at_eot
- if next_cp_track is not None and self._next(next_cp_track[1]):
- original_cp_track = self.current_cp_track
- self.current_cp_track = next_cp_track
- self.state = self.PLAYING
+ original_cp_track = self.current_cp_track
+ if self.cp_track_at_eot:
+ self.play(self.cp_track_at_eot)
if self.consume:
self.backend.current_playlist.remove(cpid=original_cp_track[0])
@@ -302,48 +300,43 @@ class BasePlaybackController(object):
self.stop()
self.current_cp_track = None
- def new_playlist_loaded_callback(self):
+ def on_current_playlist_change(self):
"""
- Tell the playback controller that a new playlist has been loaded.
+ Tell the playback controller that the current playlist has changed.
- Typically called by :class:`mopidy.process.CoreProcess` after a message
- from a library thread is received.
+ Used by :class:`mopidy.backends.base.BaseCurrentPlaylistController`.
"""
- self.current_cp_track = None
self._first_shuffle = True
self._shuffled = []
- if self.state == self.PLAYING:
- if len(self.backend.current_playlist.tracks) > 0:
- self.play()
- else:
- self.stop()
- elif self.state == self.PAUSED:
+ if not self.backend.current_playlist.cp_tracks:
+ self.stop()
+ self.current_cp_track = None
+ elif (self.current_cp_track not in
+ self.backend.current_playlist.cp_tracks):
+ self.current_cp_track = None
self.stop()
def next(self):
"""Play the next track."""
- original_cp_track = self.current_cp_track
-
if self.state == self.STOPPED:
return
- elif self.cp_track_at_next is not None and self._next(self.next_track):
- self.current_cp_track = self.cp_track_at_next
- self.state = self.PLAYING
- elif self.cp_track_at_next is None:
+
+ original_cp_track = self.current_cp_track
+ if self.cp_track_at_next:
+ self.play(self.cp_track_at_next)
+ else:
self.stop()
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:
self.backend.current_playlist.remove(cpid=original_cp_track[0])
if self.random and self.current_cp_track in self._shuffled:
self._shuffled.remove(self.current_cp_track)
- def _next(self, track):
- return self._play(track)
-
def pause(self):
"""Pause playback."""
if self.state == self.PLAYING and self._pause():
@@ -352,13 +345,16 @@ class BasePlaybackController(object):
def _pause(self):
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.
:param cp_track: track to play
:type cp_track: two-tuple (CPID integer, :class:`mopidy.models.Track`)
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:
@@ -368,13 +364,14 @@ class BasePlaybackController(object):
if self.state == self.PAUSED and cp_track is None:
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.state = self.PLAYING
-
- # TODO Do something sensible when _play() returns False, like calling
- # next(). Adding this todo instead of just implementing it as I want a
- # test case first.
+ if not self._play(cp_track[1]):
+ if on_error_step == 1:
+ self.next()
+ elif on_error_step == -1:
+ self.previous()
if self.random and self.current_cp_track in self._shuffled:
self._shuffled.remove(self.current_cp_track)
@@ -384,14 +381,11 @@ class BasePlaybackController(object):
def previous(self):
"""Play the previous track."""
- if (self.previous_cp_track is not None
- and self.state != self.STOPPED
- and self._previous(self.previous_track)):
- self.current_cp_track = self.previous_cp_track
- self.state = self.PLAYING
-
- def _previous(self, track):
- return self._play(track)
+ if self.previous_cp_track is None:
+ return
+ if self.state == self.STOPPED:
+ return
+ self.play(self.previous_cp_track, on_error_step=-1)
def resume(self):
"""If paused, resume playing the current track."""
diff --git a/mopidy/backends/libspotify/__init__.py b/mopidy/backends/libspotify/__init__.py
index 7a971bc5..f00ec1f0 100644
--- a/mopidy/backends/libspotify/__init__.py
+++ b/mopidy/backends/libspotify/__init__.py
@@ -9,14 +9,18 @@ ENCODING = 'utf-8'
class LibspotifyBackend(BaseBackend):
"""
- A Spotify backend which uses the official `libspotify library
- `_.
-
- `pyspotify `_ is the Python bindings
- for libspotify. It got no documentation, but multiple examples are
- available. Like libspotify, pyspotify's calls are mostly asynchronous.
+ A `Spotify `_ backend which uses the official
+ `libspotify `_
+ library and the `pyspotify `_ Python
+ bindings for libspotify.
**Issues:** http://github.com/jodal/mopidy/issues/labels/backend-libspotify
+
+ .. note::
+
+ This product uses SPOTIFY(R) CORE but is not endorsed, certified or
+ otherwise approved in any way by Spotify. Spotify is the registered
+ trade mark of the Spotify Group.
"""
# Imports inside methods are to prevent loading of __init__.py to fail on
@@ -40,6 +44,7 @@ class LibspotifyBackend(BaseBackend):
def _connect(self):
from .session_manager import LibspotifySessionManager
+ logger.info(u'Mopidy uses SPOTIFY(R) CORE')
logger.info(u'Connecting to Spotify')
spotify = LibspotifySessionManager(
settings.SPOTIFY_USERNAME, settings.SPOTIFY_PASSWORD,
diff --git a/mopidy/backends/libspotify/playback.py b/mopidy/backends/libspotify/playback.py
index 60a5d355..1195e9bc 100644
--- a/mopidy/backends/libspotify/playback.py
+++ b/mopidy/backends/libspotify/playback.py
@@ -26,7 +26,7 @@ class LibspotifyPlaybackController(BasePlaybackController):
def _play(self, track):
self._set_output_state('READY')
if self.state == self.PLAYING:
- self.stop()
+ self.backend.spotify.session.play(0)
if track.uri is None:
return False
try:
diff --git a/mopidy/backends/libspotify/translator.py b/mopidy/backends/libspotify/translator.py
index 3a39aad5..ff8f3c5c 100644
--- a/mopidy/backends/libspotify/translator.py
+++ b/mopidy/backends/libspotify/translator.py
@@ -39,7 +39,7 @@ class LibspotifyTranslator(object):
track_no=spotify_track.index(),
date=date,
length=spotify_track.duration(),
- bitrate=320,
+ bitrate=160,
)
@classmethod
diff --git a/mopidy/frontends/mpd/protocol/current_playlist.py b/mopidy/frontends/mpd/protocol/current_playlist.py
index c10d1dad..17b019e9 100644
--- a/mopidy/frontends/mpd/protocol/current_playlist.py
+++ b/mopidy/frontends/mpd/protocol/current_playlist.py
@@ -341,6 +341,7 @@ def swap(frontend, songpos1, songpos2):
tracks.insert(songpos1, song2)
del tracks[songpos2]
tracks.insert(songpos2, song1)
+ frontend.backend.current_playlist.clear()
frontend.backend.current_playlist.load(tracks)
@handle_pattern(r'^swapid "(?P\d+)" "(?P\d+)"$')
diff --git a/mopidy/frontends/mpd/protocol/playback.py b/mopidy/frontends/mpd/protocol/playback.py
index bfff275e..7abc4509 100644
--- a/mopidy/frontends/mpd/protocol/playback.py
+++ b/mopidy/frontends/mpd/protocol/playback.py
@@ -139,9 +139,7 @@ def playid(frontend, cpid):
cpid = int(cpid)
try:
if cpid == -1:
- if not frontend.backend.current_playlist.cp_tracks:
- return # Fail silently
- cp_track = frontend.backend.current_playlist.cp_tracks[0]
+ cp_track = _get_cp_track_for_play_minus_one(frontend)
else:
cp_track = frontend.backend.current_playlist.get(cpid=cpid)
return frontend.backend.playback.play(cp_track)
@@ -158,10 +156,11 @@ def playpos(frontend, songpos):
Begins playing the playlist at song number ``SONGPOS``.
- *MPoD:*
+ *Many clients:*
- - issues ``play "-1"`` after playlist replacement to start playback at
- the first track.
+ - issue ``play "-1"`` after playlist replacement to start the current
+ track. If the current track is not set, start playback at the first
+ track.
*BitMPC:*
@@ -170,15 +169,21 @@ def playpos(frontend, songpos):
songpos = int(songpos)
try:
if songpos == -1:
- if not frontend.backend.current_playlist.cp_tracks:
- return # Fail silently
- cp_track = frontend.backend.current_playlist.cp_tracks[0]
+ cp_track = _get_cp_track_for_play_minus_one(frontend)
else:
cp_track = frontend.backend.current_playlist.cp_tracks[songpos]
return frontend.backend.playback.play(cp_track)
except IndexError:
raise MpdArgError(u'Bad song index', command=u'play')
+def _get_cp_track_for_play_minus_one(frontend):
+ if not frontend.backend.current_playlist.cp_tracks:
+ return # Fail silently
+ cp_track = frontend.backend.playback.current_cp_track
+ if cp_track is None:
+ cp_track = frontend.backend.current_playlist.cp_tracks[0]
+ return cp_track
+
@handle_pattern(r'^previous$')
def previous(frontend):
"""
diff --git a/mopidy/frontends/mpd/protocol/stored_playlists.py b/mopidy/frontends/mpd/protocol/stored_playlists.py
index ecd8b321..adc455c3 100644
--- a/mopidy/frontends/mpd/protocol/stored_playlists.py
+++ b/mopidy/frontends/mpd/protocol/stored_playlists.py
@@ -86,6 +86,10 @@ def load(frontend, name):
``load {NAME}``
Loads the playlist ``NAME.m3u`` from the playlist directory.
+
+ *Clarifications:*
+
+ - ``load`` appends the given playlist to the current playlist.
"""
matches = frontend.backend.stored_playlists.search(name)
if matches:
@@ -139,9 +143,9 @@ def playlistmove(frontend, name, from_pos, to_pos):
*Clarifications:*
- - The second argument is not a ``SONGID`` as used elsewhere in the
- protocol documentation, but just the ``SONGPOS`` to move *from*,
- i.e. ``playlistmove {NAME} {FROM_SONGPOS} {TO_SONGPOS}``.
+ - The second argument is not a ``SONGID`` as used elsewhere in the protocol
+ documentation, but just the ``SONGPOS`` to move *from*, i.e.
+ ``playlistmove {NAME} {FROM_SONGPOS} {TO_SONGPOS}``.
"""
raise MpdNotImplemented # TODO
diff --git a/tests/backends/base.py b/tests/backends/base.py
index 19f28ba5..05379c57 100644
--- a/tests/backends/base.py
+++ b/tests/backends/base.py
@@ -91,12 +91,6 @@ class BaseCurrentPlaylistControllerTest(object):
self.controller.clear()
self.assertEqual(self.playback.state, self.playback.STOPPED)
- def test_load(self):
- tracks = []
- self.assertNotEqual(id(tracks), id(self.controller.tracks))
- self.controller.load(tracks)
- self.assertEqual(tracks, self.controller.tracks)
-
def test_get_by_uri_returns_unique_match(self):
track = Track(uri='a')
self.controller.load([Track(uri='z'), track, Track(uri='y')])
@@ -136,10 +130,15 @@ class BaseCurrentPlaylistControllerTest(object):
self.controller.load([track1, track2, track3])
self.assertEqual(track2, self.controller.get(uri='b')[1])
- @populate_playlist
- def test_load_replaces_playlist(self):
- self.backend.current_playlist.load([])
- self.assertEqual(len(self.backend.current_playlist.tracks), 0)
+ def test_load_appends_to_the_current_playlist(self):
+ self.controller.load([Track(uri='a'), Track(uri='b')])
+ self.assertEqual(len(self.controller.tracks), 2)
+ self.controller.load([Track(uri='c'), Track(uri='d')])
+ self.assertEqual(len(self.controller.tracks), 4)
+ self.assertEqual(self.controller.tracks[0].uri, 'a')
+ self.assertEqual(self.controller.tracks[1].uri, 'b')
+ self.assertEqual(self.controller.tracks[2].uri, 'c')
+ self.assertEqual(self.controller.tracks[3].uri, 'd')
def test_load_does_not_reset_version(self):
version = self.controller.version
@@ -148,22 +147,17 @@ class BaseCurrentPlaylistControllerTest(object):
@populate_playlist
def test_load_preserves_playing_state(self):
- tracks = self.controller.tracks
- playback = self.playback
-
self.playback.play()
- self.controller.load([tracks[1]])
- self.assertEqual(playback.state, playback.PLAYING)
- self.assertEqual(tracks[1], self.playback.current_track)
+ track = self.playback.current_track
+ self.controller.load(self.controller.tracks[1:2])
+ self.assertEqual(self.playback.state, self.playback.PLAYING)
+ self.assertEqual(self.playback.current_track, track)
@populate_playlist
def test_load_preserves_stopped_state(self):
- tracks = self.controller.tracks
- playback = self.playback
-
- self.controller.load([tracks[2]])
- self.assertEqual(playback.state, playback.STOPPED)
- self.assertEqual(None, self.playback.current_track)
+ self.controller.load(self.controller.tracks[1:2])
+ self.assertEqual(self.playback.state, self.playback.STOPPED)
+ self.assertEqual(self.playback.current_track, None)
@populate_playlist
def test_move_single(self):
@@ -351,6 +345,14 @@ class BasePlaybackControllerTest(object):
self.playback.play(self.current_playlist.cp_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
def test_current_track_after_completed_playlist(self):
self.playback.play(self.current_playlist.cp_tracks[-1])
@@ -417,6 +419,16 @@ class BasePlaybackControllerTest(object):
self.playback.next()
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
def test_previous(self):
self.playback.play()
@@ -457,6 +469,16 @@ class BasePlaybackControllerTest(object):
self.assertEqual(self.playback.state, self.playback.STOPPED)
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
def test_next_track_before_play(self):
self.assertEqual(self.playback.next_track, self.tracks[0])
@@ -575,15 +597,15 @@ class BasePlaybackControllerTest(object):
self.playback.end_of_track_callback()
self.assertEqual(self.playback.current_playlist_position, None)
- def test_new_playlist_loaded_callback_gets_called(self):
- callback = self.playback.new_playlist_loaded_callback
+ def test_on_current_playlist_change_gets_called(self):
+ callback = self.playback.on_current_playlist_change
def wrapper():
wrapper.called = True
return callback()
wrapper.called = False
- self.playback.new_playlist_loaded_callback = wrapper
+ self.playback.on_current_playlist_change = wrapper
self.backend.current_playlist.load([])
self.assert_(wrapper.called)
@@ -608,27 +630,28 @@ class BasePlaybackControllerTest(object):
self.assert_(event.is_set())
@populate_playlist
- def test_new_playlist_loaded_callback_when_playing(self):
+ def test_on_current_playlist_change_when_playing(self):
self.playback.play()
+ current_track = self.playback.current_track
self.backend.current_playlist.load([self.tracks[2]])
self.assertEqual(self.playback.state, self.playback.PLAYING)
- self.assertEqual(self.playback.current_track, self.tracks[2])
+ self.assertEqual(self.playback.current_track, current_track)
@populate_playlist
- def test_new_playlist_loaded_callback_when_stopped(self):
+ def test_on_current_playlist_change_when_stopped(self):
+ current_track = self.playback.current_track
self.backend.current_playlist.load([self.tracks[2]])
self.assertEqual(self.playback.state, self.playback.STOPPED)
self.assertEqual(self.playback.current_track, None)
- self.assertEqual(self.playback.next_track, self.tracks[2])
@populate_playlist
- def test_new_playlist_loaded_callback_when_paused(self):
+ def test_on_current_playlist_change_when_paused(self):
self.playback.play()
self.playback.pause()
+ current_track = self.playback.current_track
self.backend.current_playlist.load([self.tracks[2]])
- self.assertEqual(self.playback.state, self.playback.STOPPED)
- self.assertEqual(self.playback.current_track, None)
- self.assertEqual(self.playback.next_track, self.tracks[2])
+ self.assertEqual(self.playback.state, self.backend.playback.PAUSED)
+ self.assertEqual(self.playback.current_track, current_track)
@populate_playlist
def test_pause_when_stopped(self):
@@ -915,7 +938,7 @@ class BasePlaybackControllerTest(object):
self.playback.random = True
self.assertEqual(self.playback.next_track, self.tracks[2])
self.backend.current_playlist.load(self.tracks[:1])
- self.assertEqual(self.playback.next_track, self.tracks[0])
+ self.assertEqual(self.playback.next_track, self.tracks[1])
@populate_playlist
def test_played_track_during_random_not_played_again(self):
@@ -927,13 +950,9 @@ class BasePlaybackControllerTest(object):
played.append(self.playback.current_track)
self.playback.next()
- def test_playing_track_with_invalid_uri(self):
- self.backend.current_playlist.load([Track(uri='foobar')])
- self.playback.play()
- self.assertEqual(self.playback.state, self.playback.STOPPED)
-
+ @populate_playlist
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)
diff --git a/tests/data/blank.flac b/tests/data/blank.flac
index b838b98e..ae18d36f 100644
Binary files a/tests/data/blank.flac and b/tests/data/blank.flac differ
diff --git a/tests/data/blank.mp3 b/tests/data/blank.mp3
index 3e0b4abb..6aa48cd8 100644
Binary files a/tests/data/blank.mp3 and b/tests/data/blank.mp3 differ
diff --git a/tests/data/blank.ogg b/tests/data/blank.ogg
index 3b1c57a1..e67e428b 100644
Binary files a/tests/data/blank.ogg and b/tests/data/blank.ogg differ
diff --git a/tests/data/blank.wav b/tests/data/blank.wav
index 5217ec6f..0041c7ba 100644
Binary files a/tests/data/blank.wav and b/tests/data/blank.wav differ
diff --git a/tests/frontends/mpd/playback_test.py b/tests/frontends/mpd/playback_test.py
index a1331bb3..ce3130bf 100644
--- a/tests/frontends/mpd/playback_test.py
+++ b/tests/frontends/mpd/playback_test.py
@@ -225,13 +225,25 @@ class PlaybackControlHandlerTest(unittest.TestCase):
self.assertEqual(result[0], u'ACK [2@0] {play} Bad song index')
self.assertEqual(self.b.playback.STOPPED, self.b.playback.state)
- def test_play_minus_one_plays_first_in_playlist(self):
- track = Track()
- self.b.current_playlist.load([track])
+ def test_play_minus_one_plays_first_in_playlist_if_no_current_track(self):
+ self.assertEqual(self.b.playback.current_track, None)
+ self.b.current_playlist.load([Track(uri='a'), Track(uri='b')])
result = self.h.handle_request(u'play "-1"')
self.assert_(u'OK' in result)
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
- self.assertEqual(self.b.playback.current_track, track)
+ self.assertEqual(self.b.playback.current_track.uri, 'a')
+
+ def test_play_minus_one_plays_current_track_if_current_track_is_set(self):
+ self.b.current_playlist.load([Track(uri='a'), Track(uri='b')])
+ self.assertEqual(self.b.playback.current_track, None)
+ self.b.playback.play()
+ self.b.playback.next()
+ self.b.playback.stop()
+ self.assertNotEqual(self.b.playback.current_track, None)
+ result = self.h.handle_request(u'play "-1"')
+ self.assert_(u'OK' in result)
+ self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
+ self.assertEqual(self.b.playback.current_track.uri, 'b')
def test_play_minus_one_on_empty_playlist_does_not_ack(self):
self.b.current_playlist.clear()
@@ -246,13 +258,25 @@ class PlaybackControlHandlerTest(unittest.TestCase):
self.assert_(u'OK' in result)
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
- def test_playid_minus_one_plays_first_in_playlist(self):
- track = Track()
- self.b.current_playlist.load([track])
+ def test_playid_minus_one_plays_first_in_playlist_if_no_current_track(self):
+ self.assertEqual(self.b.playback.current_track, None)
+ self.b.current_playlist.load([Track(uri='a'), Track(uri='b')])
result = self.h.handle_request(u'playid "-1"')
self.assert_(u'OK' in result)
self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
- self.assertEqual(self.b.playback.current_track, track)
+ self.assertEqual(self.b.playback.current_track.uri, 'a')
+
+ def test_play_minus_one_plays_current_track_if_current_track_is_set(self):
+ self.b.current_playlist.load([Track(uri='a'), Track(uri='b')])
+ self.assertEqual(self.b.playback.current_track, None)
+ self.b.playback.play()
+ self.b.playback.next()
+ self.b.playback.stop()
+ self.assertNotEqual(self.b.playback.current_track, None)
+ result = self.h.handle_request(u'playid "-1"')
+ self.assert_(u'OK' in result)
+ self.assertEqual(self.b.playback.PLAYING, self.b.playback.state)
+ self.assertEqual(self.b.playback.current_track.uri, 'b')
def test_playid_minus_one_on_empty_playlist_does_not_ack(self):
self.b.current_playlist.clear()