Merge branch 'develop' into feature/http-frontend
This commit is contained in:
commit
532a915db8
280
docs/changes.rst
280
docs/changes.rst
@ -5,14 +5,30 @@ Changes
|
|||||||
This change log is used to track all major changes to Mopidy.
|
This change log is used to track all major changes to Mopidy.
|
||||||
|
|
||||||
|
|
||||||
v0.9.0 (in development)
|
v0.9.0 (2012-11-21)
|
||||||
=======================
|
===================
|
||||||
|
|
||||||
**Multiple backends support**
|
|
||||||
|
|
||||||
Support for using the local and Spotify backends simultaneously have for a very
|
Support for using the local and Spotify backends simultaneously have for a very
|
||||||
long time been our most requested feature. Finally, it's here!
|
long time been our most requested feature. Finally, it's here!
|
||||||
|
|
||||||
|
**Dependencies**
|
||||||
|
|
||||||
|
- pyspotify >= 1.9, < 1.10 is now required for Spotify support.
|
||||||
|
|
||||||
|
**Documentation**
|
||||||
|
|
||||||
|
- New :ref:`installation` guides, organized by OS and distribution so that you
|
||||||
|
can follow one concise list of instructions instead of jumping around the
|
||||||
|
docs to look for instructions for each dependency.
|
||||||
|
|
||||||
|
- Moved :ref:`raspberrypi-installation` howto from the wiki to the docs.
|
||||||
|
|
||||||
|
- Updated :ref:`mpd-clients` overview.
|
||||||
|
|
||||||
|
- Added :ref:`mpris-clients` and :ref:`upnp-clients` overview.
|
||||||
|
|
||||||
|
**Multiple backends support**
|
||||||
|
|
||||||
- Both the local backend and the Spotify backend are now turned on by default.
|
- Both the local backend and the Spotify backend are now turned on by default.
|
||||||
The local backend is listed first in the :attr:`mopidy.settings.BACKENDS`
|
The local backend is listed first in the :attr:`mopidy.settings.BACKENDS`
|
||||||
setting, and are thus given the highest priority in e.g. search results,
|
setting, and are thus given the highest priority in e.g. search results,
|
||||||
@ -24,8 +40,85 @@ long time been our most requested feature. Finally, it's here!
|
|||||||
As always, see :mod:`mopidy.settings` for the full list of available
|
As always, see :mod:`mopidy.settings` for the full list of available
|
||||||
settings.
|
settings.
|
||||||
|
|
||||||
|
**Spotify backend**
|
||||||
|
|
||||||
|
- The Spotify backend now includes release year and artist on albums.
|
||||||
|
|
||||||
|
- :issue:`233`: The Spotify backend now returns the track if you search for the
|
||||||
|
Spotify track URI.
|
||||||
|
|
||||||
|
- Added support for connecting to the Spotify service through an HTTP or SOCKS
|
||||||
|
proxy, which is supported by pyspotify >= 1.9.
|
||||||
|
|
||||||
|
- Subscriptions to other Spotify user's "starred" playlists are ignored, as
|
||||||
|
they currently isn't fully supported by pyspotify.
|
||||||
|
|
||||||
|
**Local backend**
|
||||||
|
|
||||||
|
- :issue:`236`: The ``mopidy-scan`` command failed to include tags from ALAC
|
||||||
|
files (Apple lossless) because it didn't support multiple tag messages from
|
||||||
|
GStreamer per track it scanned.
|
||||||
|
|
||||||
|
- Added support for search by filename to local backend.
|
||||||
|
|
||||||
|
**MPD frontend**
|
||||||
|
|
||||||
|
- :issue:`218`: The MPD commands ``listplaylist`` and ``listplaylistinfo`` now
|
||||||
|
accepts unquoted playlist names if they don't contain spaces.
|
||||||
|
|
||||||
|
- :issue:`246`: The MPD command ``list album artist ""`` and similar
|
||||||
|
``search``, ``find``, and ``list`` commands with empty filter values caused a
|
||||||
|
:exc:`LookupError`, but should have been ignored by the MPD server.
|
||||||
|
|
||||||
|
- The MPD frontend no longer lowercases search queries. This broke e.g. search
|
||||||
|
by URI, where casing may be essential.
|
||||||
|
|
||||||
|
- The MPD command ``plchanges`` always returned the entire playlist. It now
|
||||||
|
returns an empty response when the client has seen the latest version.
|
||||||
|
|
||||||
|
- The MPD commands ``search`` and ``find`` now allows the key ``file``, which
|
||||||
|
is used by ncmpcpp instead of ``filename``.
|
||||||
|
|
||||||
|
- The MPD commands ``search`` and ``find`` now allow search query values to be
|
||||||
|
empty strings.
|
||||||
|
|
||||||
|
- The MPD command ``listplaylists`` will no longer return playlists without a
|
||||||
|
name. This could crash ncmpcpp.
|
||||||
|
|
||||||
|
- The MPD command ``list`` will no longer return artist names, album names, or
|
||||||
|
dates that are blank.
|
||||||
|
|
||||||
|
- The MPD command ``decoders`` will now return an empty response instead of a
|
||||||
|
"not implemented" error to make the ncmpcpp browse view work the first time
|
||||||
|
it is opened.
|
||||||
|
|
||||||
|
**MPRIS frontend**
|
||||||
|
|
||||||
|
- The MPRIS playlists interface is now supported by our MPRIS frontend. This
|
||||||
|
means that you now can select playlists to queue and play from the Ubuntu
|
||||||
|
Sound Menu.
|
||||||
|
|
||||||
|
**Audio mixers**
|
||||||
|
|
||||||
|
- Made the :mod:`NAD mixer <mopidy.audio.mixers.nad>` responsive to interrupts
|
||||||
|
during amplifier calibration. It will now quit immediately, while previously
|
||||||
|
it completed the calibration first, and then quit, which could take more than
|
||||||
|
15 seconds.
|
||||||
|
|
||||||
|
**Developer support**
|
||||||
|
|
||||||
|
- Added optional background thread for debugging deadlocks. When the feature is
|
||||||
|
enabled via the ``--debug-thread`` option or
|
||||||
|
:attr:`mopidy.settings.DEBUG_THREAD` setting a ``SIGUSR1`` signal will dump
|
||||||
|
the traceback for all running threads.
|
||||||
|
|
||||||
|
- The settings validator will now allow any setting prefixed with ``CUSTOM_``
|
||||||
|
to exist in the settings file.
|
||||||
|
|
||||||
|
**Internal changes**
|
||||||
|
|
||||||
Internally, Mopidy have seen a lot of changes to pave the way for multiple
|
Internally, Mopidy have seen a lot of changes to pave the way for multiple
|
||||||
backends:
|
backends and the future HTTP frontend.
|
||||||
|
|
||||||
- A new layer and actor, "core", has been added to our stack, inbetween the
|
- A new layer and actor, "core", has been added to our stack, inbetween the
|
||||||
frontends and the backends. The responsibility of the core layer and actor is
|
frontends and the backends. The responsibility of the core layer and actor is
|
||||||
@ -36,12 +129,6 @@ backends:
|
|||||||
Frontends no longer know anything about the backends. They just use the
|
Frontends no longer know anything about the backends. They just use the
|
||||||
:ref:`core-api`.
|
:ref:`core-api`.
|
||||||
|
|
||||||
- The base playback provider has been updated with sane default behavior
|
|
||||||
instead of empty functions. By default, the playback provider now lets
|
|
||||||
GStreamer keep track of the current track's time position. The local backend
|
|
||||||
simply uses the base playback provider without any changes. The same applies
|
|
||||||
to any future backend that just needs GStreamer to play an URI for it.
|
|
||||||
|
|
||||||
- The dependency graph between the core controllers and the backend providers
|
- The dependency graph between the core controllers and the backend providers
|
||||||
have been straightened out, so that we don't have any circular dependencies.
|
have been straightened out, so that we don't have any circular dependencies.
|
||||||
The frontend, core, backend, and audio layers are now strictly separate. The
|
The frontend, core, backend, and audio layers are now strictly separate. The
|
||||||
@ -51,118 +138,113 @@ backends:
|
|||||||
broadcasting of events to listeners, through e.g.
|
broadcasting of events to listeners, through e.g.
|
||||||
:class:`mopidy.core.CoreListener` and :class:`mopidy.audio.AudioListener`.
|
:class:`mopidy.core.CoreListener` and :class:`mopidy.audio.AudioListener`.
|
||||||
|
|
||||||
|
See :ref:`concepts` for more details and illustrations of all the relations.
|
||||||
|
|
||||||
- All dependencies are now explicitly passed to the constructors of the
|
- All dependencies are now explicitly passed to the constructors of the
|
||||||
frontends, core, and the backends. This makes testing each layer with
|
frontends, core, and the backends. This makes testing each layer with
|
||||||
dummy/mocked lower layers easier than with the old variant, where
|
dummy/mocked lower layers easier than with the old variant, where
|
||||||
dependencies where looked up in Pykka's actor registry.
|
dependencies where looked up in Pykka's actor registry.
|
||||||
|
|
||||||
- Renamed "current playlist" to "tracklist" everywhere, including the core API
|
- All properties in the core API now got getters, and setters if setting them
|
||||||
used by frontends.
|
is allowed. They are not explictly listed in the docs as they have the same
|
||||||
|
behavior as the documented properties, but they are available and may be
|
||||||
|
used. This is useful for the future HTTP frontend.
|
||||||
|
|
||||||
- Renamed "stored playlists" to "playlists" everywhere, including the core API
|
*Models:*
|
||||||
used by frontends.
|
|
||||||
|
|
||||||
- The playlists part of the core API has been revised to be more focused around
|
|
||||||
the playlist URI, and some redundant functionality has been removed:
|
|
||||||
|
|
||||||
- :attr:`mopidy.core.PlaylistsController.playlists` no longer supports
|
|
||||||
assignment to it. The `playlists` property on the backend layer still does,
|
|
||||||
and all functionality is maintained by assigning to the playlists
|
|
||||||
collections at the backend level.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.PlaylistsController.delete` now accepts an URI, and not
|
|
||||||
a playlist object.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.PlaylistsController.save` now returns the saved
|
|
||||||
playlist. The returned playlist may differ from the saved playlist, and
|
|
||||||
should thus be used instead of the playlist passed to ``save()``.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.PlaylistsController.rename` has been removed, since
|
|
||||||
renaming can be done with ``save()``.
|
|
||||||
|
|
||||||
**Changes**
|
|
||||||
|
|
||||||
- Made the :mod:`NAD mixer <mopidy.audio.mixers.nad>` responsive to interrupts
|
|
||||||
during amplifier calibration. It will now quit immediately, while previously
|
|
||||||
it completed the calibration first, and then quit, which could take more than
|
|
||||||
15 seconds.
|
|
||||||
|
|
||||||
- Added :attr:`mopidy.models.Album.date` attribute. It has the same format as
|
- Added :attr:`mopidy.models.Album.date` attribute. It has the same format as
|
||||||
the existing :attr:`mopidy.models.Track.date`.
|
the existing :attr:`mopidy.models.Track.date`.
|
||||||
|
|
||||||
- The Spotify backend now includes release year and artist on albums.
|
- Added :class:`mopidy.models.ModelJSONEncoder` and
|
||||||
|
:func:`mopidy.models.model_json_decoder` for automatic JSON serialization and
|
||||||
|
deserialization of data structures which contains Mopidy models. This is
|
||||||
|
useful for the future HTTP frontend.
|
||||||
|
|
||||||
- Added support for search by filename to local backend.
|
*Library:*
|
||||||
|
|
||||||
- Added optional background thread for debugging deadlocks. When the feature is
|
- :meth:`mopidy.core.LibraryController.find_exact` and
|
||||||
enabled via the ``--debug-thread`` option or
|
:meth:`mopidy.core.LibraryController.search` now returns plain lists of
|
||||||
:attr:`mopidy.settings.DEBUG_THREAD` setting a ``SIGUSR1`` signal will dump
|
tracks instead of playlist objects.
|
||||||
the traceback for all running threads.
|
|
||||||
|
|
||||||
- Make the entire code base use unicode strings by default, and only fall back
|
- :meth:`mopidy.core.LibraryController.lookup` now returns a list of tracks
|
||||||
to bytestrings where it is required. Another step closer to Python 3.
|
instead of a single track. This makes it possible to support lookup of
|
||||||
|
artist or album URIs which then can expand to a list of tracks.
|
||||||
|
|
||||||
- The settings validator will now allow any setting prefixed with ``CUSTOM_``
|
*Playback:*
|
||||||
to exist in the settings file.
|
|
||||||
|
|
||||||
- The MPD commands ``search`` and ``find`` now allows the key ``file``, which
|
- The base playback provider has been updated with sane default behavior
|
||||||
is used by ncmpcpp instead of ``filename``.
|
instead of empty functions. By default, the playback provider now lets
|
||||||
|
GStreamer keep track of the current track's time position. The local backend
|
||||||
|
simply uses the base playback provider without any changes. Any future
|
||||||
|
backend that just feeds URIs to GStreamer to play can also use the base
|
||||||
|
playback provider without any changes.
|
||||||
|
|
||||||
- The Spotify backend now returns the track if you search for the Spotify track
|
- Removed :attr:`mopidy.core.PlaybackController.track_at_previous`. Use
|
||||||
URI. (Fixes: :issue:`233`)
|
:attr:`mopidy.core.PlaybackController.tl_track_at_previous` instead.
|
||||||
|
|
||||||
- :meth:`mopidy.core.TracklistController.append` now returns a list of the
|
- Removed :attr:`mopidy.core.PlaybackController.track_at_next`. Use
|
||||||
:class:`mopidy.models.TlTrack` instances that was added to the tracklist.
|
:attr:`mopidy.core.PlaybackController.tl_track_at_next` instead.
|
||||||
This makes it easier to start playing one of the tracks that was just
|
|
||||||
appended to the tracklist.
|
- Removed :attr:`mopidy.core.PlaybackController.track_at_eot`. Use
|
||||||
|
:attr:`mopidy.core.PlaybackController.tl_track_at_eot` instead.
|
||||||
|
|
||||||
|
- Removed :attr:`mopidy.core.PlaybackController.current_tlid`. Use
|
||||||
|
:attr:`mopidy.core.PlaybackController.current_tl_track` instead.
|
||||||
|
|
||||||
|
*Playlists:*
|
||||||
|
|
||||||
|
The playlists part of the core API has been revised to be more focused around
|
||||||
|
the playlist URI, and some redundant functionality has been removed:
|
||||||
|
|
||||||
|
- Renamed "stored playlists" to "playlists" everywhere, including the core API
|
||||||
|
used by frontends.
|
||||||
|
|
||||||
|
- :attr:`mopidy.core.PlaylistsController.playlists` no longer supports
|
||||||
|
assignment to it. The `playlists` property on the backend layer still does,
|
||||||
|
and all functionality is maintained by assigning to the playlists collections
|
||||||
|
at the backend level.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.PlaylistsController.delete` now accepts an URI, and not a
|
||||||
|
playlist object.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.PlaylistsController.save` now returns the saved playlist.
|
||||||
|
The returned playlist may differ from the saved playlist, and should thus be
|
||||||
|
used instead of the playlist passed to
|
||||||
|
:meth:`mopidy.core.PlaylistsController.save`.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.PlaylistsController.rename` has been removed, since
|
||||||
|
renaming can be done with :meth:`mopidy.core.PlaylistsController.save`.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.PlaylistsController.get` has been replaced by
|
||||||
|
:meth:`mopidy.core.PlaylistsController.filter`.
|
||||||
|
|
||||||
|
- The event :meth:`mopidy.core.CoreListener.playlist_changed` has been changed
|
||||||
|
to include the playlist that was changed.
|
||||||
|
|
||||||
|
*Tracklist:*
|
||||||
|
|
||||||
|
- Renamed "current playlist" to "tracklist" everywhere, including the core API
|
||||||
|
used by frontends.
|
||||||
|
|
||||||
|
- Removed :meth:`mopidy.core.TracklistController.append`. Use
|
||||||
|
:meth:`mopidy.core.TracklistController.add` instead, which is now capable of
|
||||||
|
adding multiple tracks.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.TracklistController.get` has been replaced by
|
||||||
|
:meth:`mopidy.core.TracklistController.filter`.
|
||||||
|
|
||||||
|
- :meth:`mopidy.core.TracklistController.remove` can now remove multiple
|
||||||
|
tracks, and returns the tracks it removed.
|
||||||
|
|
||||||
- When the tracklist is changed, we now trigger the new
|
- When the tracklist is changed, we now trigger the new
|
||||||
:meth:`mopidy.core.CoreListener.tracklist_changed` event. Previously we
|
:meth:`mopidy.core.CoreListener.tracklist_changed` event. Previously we
|
||||||
triggered :meth:`mopidy.core.CoreListener.playlist_changed`, which is
|
triggered :meth:`mopidy.core.CoreListener.playlist_changed`, which is
|
||||||
intended for stored playlists, not the tracklist.
|
intended for stored playlists, not the tracklist.
|
||||||
|
|
||||||
- The event :meth:`mopidy.core.CoreListener.playlist_changed` has been changed
|
*Towards Python 3 support:*
|
||||||
to include the playlist that was changed.
|
|
||||||
|
|
||||||
- The MPRIS playlists interface is now supported by our MPRIS frontend. This
|
- Make the entire code base use unicode strings by default, and only fall back
|
||||||
means that you now can select playlists to queue and play from the Ubuntu
|
to bytestrings where it is required. Another step closer to Python 3.
|
||||||
Sound Menu.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.LibraryController.find_exact` and
|
|
||||||
:meth:`mopidy.core.LibraryController.search` now returns plain lists of
|
|
||||||
tracks instead of playlist objects.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.TracklistController.get` has been replaced by
|
|
||||||
:meth:`mopidy.core.TracklistController.filter`.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.PlaylistsController.get` has been replaced by
|
|
||||||
:meth:`mopidy.core.PlaylistsController.filter`.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.TracklistController.remove` can now remove multiple
|
|
||||||
tracks, and returns the tracks it removed.
|
|
||||||
|
|
||||||
- :meth:`mopidy.core.LibraryController.lookup` now returns a list of tracks.
|
|
||||||
This makes it possible to support lookup of artist or album URIs which then
|
|
||||||
can expand to a list of tracks.
|
|
||||||
|
|
||||||
**Bug fixes**
|
|
||||||
|
|
||||||
- :issue:`218`: The MPD commands ``listplaylist`` and ``listplaylistinfo`` now
|
|
||||||
accepts unquotes playlist names if they don't contain spaces.
|
|
||||||
|
|
||||||
- The MPD command ``plchanges`` always returned the entire playlist. It now
|
|
||||||
returns an empty response when the client has seen the latest version.
|
|
||||||
|
|
||||||
- MPD no longer lowercases search queries. This broke e.g. search by URI, where
|
|
||||||
casing may be essential.
|
|
||||||
|
|
||||||
- :issue:`236`: The ``mopidy-scan`` command failed to include tags from ALAC
|
|
||||||
files (Apple lossless) because it didn't support multiple tag messages from
|
|
||||||
GStreamer per track it scanned.
|
|
||||||
|
|
||||||
- :issue:`246`: The MPD command ``list album artist ""`` and similar
|
|
||||||
``search``, ``find``, and ``list`` commands with empty filter values caused a
|
|
||||||
:exc:`LookupError`, but should have been ignored by the MPD server.
|
|
||||||
|
|
||||||
|
|
||||||
v0.8.1 (2012-10-30)
|
v0.8.1 (2012-10-30)
|
||||||
|
|||||||
@ -23,7 +23,7 @@ if (isinstance(pykka.__version__, basestring)
|
|||||||
warnings.filterwarnings('ignore', 'could not open display')
|
warnings.filterwarnings('ignore', 'could not open display')
|
||||||
|
|
||||||
|
|
||||||
__version__ = '0.8.1'
|
__version__ = '0.9.0'
|
||||||
|
|
||||||
|
|
||||||
from mopidy import settings as default_settings_module
|
from mopidy import settings as default_settings_module
|
||||||
|
|||||||
@ -37,9 +37,11 @@ class DummyLibraryProvider(base.BaseLibraryProvider):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DummyLibraryProvider, self).__init__(*args, **kwargs)
|
super(DummyLibraryProvider, self).__init__(*args, **kwargs)
|
||||||
self.dummy_library = []
|
self.dummy_library = []
|
||||||
|
self.dummy_find_exact_result = []
|
||||||
|
self.dummy_search_result = []
|
||||||
|
|
||||||
def find_exact(self, **query):
|
def find_exact(self, **query):
|
||||||
return []
|
return self.dummy_find_exact_result
|
||||||
|
|
||||||
def lookup(self, uri):
|
def lookup(self, uri):
|
||||||
return filter(lambda t: uri == t.uri, self.dummy_library)
|
return filter(lambda t: uri == t.uri, self.dummy_library)
|
||||||
@ -48,7 +50,7 @@ class DummyLibraryProvider(base.BaseLibraryProvider):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def search(self, **query):
|
def search(self, **query):
|
||||||
return []
|
return self.dummy_search_result
|
||||||
|
|
||||||
|
|
||||||
class DummyPlaybackProvider(base.BasePlaybackProvider):
|
class DummyPlaybackProvider(base.BasePlaybackProvider):
|
||||||
|
|||||||
@ -21,7 +21,7 @@ https://github.com/mopidy/mopidy/issues?labels=Spotify+backend
|
|||||||
**Dependencies:**
|
**Dependencies:**
|
||||||
|
|
||||||
- libspotify >= 12, < 13 (libspotify12 package from apt.mopidy.com)
|
- libspotify >= 12, < 13 (libspotify12 package from apt.mopidy.com)
|
||||||
- pyspotify >= 1.8, < 1.9 (python-spotify package from apt.mopidy.com)
|
- pyspotify >= 1.9, < 1.10 (python-spotify package from apt.mopidy.com)
|
||||||
|
|
||||||
**Settings:**
|
**Settings:**
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,14 @@ class SpotifyBackend(pykka.ThreadingActor, base.Backend):
|
|||||||
# Fail early if settings are not present
|
# Fail early if settings are not present
|
||||||
username = settings.SPOTIFY_USERNAME
|
username = settings.SPOTIFY_USERNAME
|
||||||
password = settings.SPOTIFY_PASSWORD
|
password = settings.SPOTIFY_PASSWORD
|
||||||
|
proxy = settings.SPOTIFY_PROXY_HOST
|
||||||
|
proxy_username = settings.SPOTIFY_PROXY_USERNAME
|
||||||
|
proxy_password = settings.SPOTIFY_PROXY_PASSWORD
|
||||||
|
|
||||||
self.spotify = SpotifySessionManager(
|
self.spotify = SpotifySessionManager(
|
||||||
username, password, audio=audio, backend_ref=self.actor_ref)
|
username, password, audio=audio, backend_ref=self.actor_ref,
|
||||||
|
proxy=proxy, proxy_username=proxy_username,
|
||||||
|
proxy_password=proxy_password)
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
logger.info('Mopidy uses SPOTIFY(R) CORE')
|
logger.info('Mopidy uses SPOTIFY(R) CORE')
|
||||||
|
|||||||
@ -46,10 +46,11 @@ class SpotifyPlaybackProvider(base.BasePlaybackProvider):
|
|||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
time_position = self.get_time_position()
|
time_position = self.get_time_position()
|
||||||
|
|
||||||
self._timer.resume()
|
self._timer.resume()
|
||||||
|
self.audio.prepare_change()
|
||||||
return self.seek(time_position)
|
result = self.seek(time_position)
|
||||||
|
self.audio.start_playback()
|
||||||
|
return result
|
||||||
|
|
||||||
def seek(self, time_position):
|
def seek(self, time_position):
|
||||||
self.backend.spotify.session.seek(time_position)
|
self.backend.spotify.session.seek(time_position)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import threading
|
|||||||
|
|
||||||
from spotify.manager import SpotifySessionManager as PyspotifySessionManager
|
from spotify.manager import SpotifySessionManager as PyspotifySessionManager
|
||||||
|
|
||||||
from mopidy import settings
|
from mopidy import audio, settings
|
||||||
from mopidy.backends.listener import BackendListener
|
from mopidy.backends.listener import BackendListener
|
||||||
from mopidy.utils import process, versioning
|
from mopidy.utils import process, versioning
|
||||||
|
|
||||||
@ -32,8 +32,12 @@ class SpotifySessionManager(process.BaseThread, PyspotifySessionManager):
|
|||||||
appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key')
|
appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key')
|
||||||
user_agent = 'Mopidy %s' % versioning.get_version()
|
user_agent = 'Mopidy %s' % versioning.get_version()
|
||||||
|
|
||||||
def __init__(self, username, password, audio, backend_ref):
|
def __init__(self, username, password, audio, backend_ref, proxy=None,
|
||||||
PyspotifySessionManager.__init__(self, username, password)
|
proxy_username=None, proxy_password=None):
|
||||||
|
PyspotifySessionManager.__init__(
|
||||||
|
self, username, password, proxy=proxy,
|
||||||
|
proxy_username=proxy_username,
|
||||||
|
proxy_password=proxy_password)
|
||||||
process.BaseThread.__init__(self)
|
process.BaseThread.__init__(self)
|
||||||
self.name = 'SpotifyThread'
|
self.name = 'SpotifyThread'
|
||||||
|
|
||||||
@ -88,7 +92,8 @@ class SpotifySessionManager(process.BaseThread, PyspotifySessionManager):
|
|||||||
logger.info('Spotify connection OK')
|
logger.info('Spotify connection OK')
|
||||||
else:
|
else:
|
||||||
logger.error('Spotify connection error: %s', error)
|
logger.error('Spotify connection error: %s', error)
|
||||||
self.backend.playback.pause()
|
if self.audio.state.get() == audio.PlaybackState.PLAYING:
|
||||||
|
self.backend.playback.pause()
|
||||||
|
|
||||||
def message_to_user(self, session, message):
|
def message_to_user(self, session, message):
|
||||||
"""Callback used by pyspotify"""
|
"""Callback used by pyspotify"""
|
||||||
|
|||||||
@ -56,6 +56,10 @@ def to_mopidy_playlist(spotify_playlist):
|
|||||||
uri = str(Link.from_playlist(spotify_playlist))
|
uri = str(Link.from_playlist(spotify_playlist))
|
||||||
if not spotify_playlist.is_loaded():
|
if not spotify_playlist.is_loaded():
|
||||||
return Playlist(uri=uri, name='[loading...]')
|
return Playlist(uri=uri, name='[loading...]')
|
||||||
|
if not spotify_playlist.name():
|
||||||
|
# Other user's "starred" playlists isn't handled properly by pyspotify
|
||||||
|
# See https://github.com/mopidy/pyspotify/issues/81
|
||||||
|
return
|
||||||
return Playlist(
|
return Playlist(
|
||||||
uri=uri,
|
uri=uri,
|
||||||
name=spotify_playlist.name(),
|
name=spotify_playlist.name(),
|
||||||
|
|||||||
@ -46,14 +46,15 @@ class Core(pykka.ThreadingActor, AudioListener, BackendListener):
|
|||||||
|
|
||||||
self.tracklist = TracklistController(core=self)
|
self.tracklist = TracklistController(core=self)
|
||||||
|
|
||||||
@property
|
def get_uri_schemes(self):
|
||||||
def uri_schemes(self):
|
|
||||||
"""List of URI schemes we can handle"""
|
|
||||||
futures = [b.uri_schemes for b in self.backends]
|
futures = [b.uri_schemes for b in self.backends]
|
||||||
results = pykka.get_all(futures)
|
results = pykka.get_all(futures)
|
||||||
uri_schemes = itertools.chain(*results)
|
uri_schemes = itertools.chain(*results)
|
||||||
return sorted(uri_schemes)
|
return sorted(uri_schemes)
|
||||||
|
|
||||||
|
uri_schemes = property(get_uri_schemes)
|
||||||
|
"""List of URI schemes we can handle"""
|
||||||
|
|
||||||
def reached_end_of_stream(self):
|
def reached_end_of_stream(self):
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
|
|
||||||
|
|||||||
@ -12,56 +12,12 @@ from . import listener
|
|||||||
logger = logging.getLogger('mopidy.core')
|
logger = logging.getLogger('mopidy.core')
|
||||||
|
|
||||||
|
|
||||||
def option_wrapper(name, default):
|
|
||||||
def get_option(self):
|
|
||||||
return getattr(self, name, default)
|
|
||||||
|
|
||||||
def set_option(self, value):
|
|
||||||
if getattr(self, name, default) != value:
|
|
||||||
# pylint: disable = W0212
|
|
||||||
self._trigger_options_changed()
|
|
||||||
# pylint: enable = W0212
|
|
||||||
return setattr(self, name, value)
|
|
||||||
|
|
||||||
return property(get_option, set_option)
|
|
||||||
|
|
||||||
|
|
||||||
class PlaybackController(object):
|
class PlaybackController(object):
|
||||||
# pylint: disable = R0902
|
# pylint: disable = R0902
|
||||||
# Too many instance attributes
|
# Too many instance attributes
|
||||||
|
|
||||||
pykka_traversable = True
|
pykka_traversable = True
|
||||||
|
|
||||||
#: :class:`True`
|
|
||||||
#: Tracks are removed from the playlist when they have been played.
|
|
||||||
#: :class:`False`
|
|
||||||
#: Tracks are not removed from the playlist.
|
|
||||||
consume = option_wrapper('_consume', False)
|
|
||||||
|
|
||||||
#: The currently playing or selected :class:`mopidy.models.TlTrack`, or
|
|
||||||
#: :class:`None`.
|
|
||||||
current_tl_track = None
|
|
||||||
|
|
||||||
#: :class:`True`
|
|
||||||
#: Tracks are selected at random from the playlist.
|
|
||||||
#: :class:`False`
|
|
||||||
#: Tracks are played in the order of the playlist.
|
|
||||||
random = option_wrapper('_random', False)
|
|
||||||
|
|
||||||
#: :class:`True`
|
|
||||||
#: The current playlist is played repeatedly. To repeat a single track,
|
|
||||||
#: select both :attr:`repeat` and :attr:`single`.
|
|
||||||
#: :class:`False`
|
|
||||||
#: The current playlist is played once.
|
|
||||||
repeat = option_wrapper('_repeat', False)
|
|
||||||
|
|
||||||
#: :class:`True`
|
|
||||||
#: Playback is stopped after current song, unless in :attr:`repeat`
|
|
||||||
#: mode.
|
|
||||||
#: :class:`False`
|
|
||||||
#: Playback continues after current song.
|
|
||||||
single = option_wrapper('_single', False)
|
|
||||||
|
|
||||||
def __init__(self, audio, backends, core):
|
def __init__(self, audio, backends, core):
|
||||||
self.audio = audio
|
self.audio = audio
|
||||||
self.backends = backends
|
self.backends = backends
|
||||||
@ -79,42 +35,128 @@ class PlaybackController(object):
|
|||||||
uri_scheme = urlparse.urlparse(uri).scheme
|
uri_scheme = urlparse.urlparse(uri).scheme
|
||||||
return self.backends.with_playback_by_uri_scheme.get(uri_scheme, None)
|
return self.backends.with_playback_by_uri_scheme.get(uri_scheme, None)
|
||||||
|
|
||||||
def _get_tlid(self, tl_track):
|
### Properties
|
||||||
if tl_track is None:
|
|
||||||
return None
|
|
||||||
return tl_track.tlid
|
|
||||||
|
|
||||||
def _get_track(self, tl_track):
|
def get_consume(self):
|
||||||
if tl_track is None:
|
return getattr(self, '_consume', False)
|
||||||
return None
|
|
||||||
return tl_track.track
|
|
||||||
|
|
||||||
@property
|
def set_consume(self, value):
|
||||||
def current_tlid(self):
|
if self.get_consume() != value:
|
||||||
"""
|
self._trigger_options_changed()
|
||||||
The TLID (tracklist ID) of the currently playing or selected
|
return setattr(self, '_consume', value)
|
||||||
track.
|
|
||||||
|
|
||||||
Read-only. Extracted from :attr:`current_tl_track` for convenience.
|
consume = property(get_consume, set_consume)
|
||||||
"""
|
"""
|
||||||
return self._get_tlid(self.current_tl_track)
|
:class:`True`
|
||||||
|
Tracks are removed from the playlist when they have been played.
|
||||||
|
:class:`False`
|
||||||
|
Tracks are not removed from the playlist.
|
||||||
|
"""
|
||||||
|
|
||||||
@property
|
current_tl_track = None
|
||||||
def current_track(self):
|
"""
|
||||||
"""
|
The currently playing or selected :class:`mopidy.models.TlTrack`, or
|
||||||
The currently playing or selected :class:`mopidy.models.Track`.
|
:class:`None`.
|
||||||
|
"""
|
||||||
|
|
||||||
Read-only. Extracted from :attr:`current_tl_track` for convenience.
|
def get_current_track(self):
|
||||||
"""
|
return self.current_tl_track and self.current_tl_track.track
|
||||||
return self._get_track(self.current_tl_track)
|
|
||||||
|
|
||||||
@property
|
current_track = property(get_current_track)
|
||||||
def tracklist_position(self):
|
"""
|
||||||
"""
|
The currently playing or selected :class:`mopidy.models.Track`.
|
||||||
The position of the current track in the tracklist.
|
|
||||||
|
|
||||||
Read-only.
|
Read-only. Extracted from :attr:`current_tl_track` for convenience.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def get_random(self):
|
||||||
|
return getattr(self, '_random', False)
|
||||||
|
|
||||||
|
def set_random(self, value):
|
||||||
|
if self.get_random() != value:
|
||||||
|
self._trigger_options_changed()
|
||||||
|
return setattr(self, '_random', value)
|
||||||
|
|
||||||
|
random = property(get_random, set_random)
|
||||||
|
"""
|
||||||
|
:class:`True`
|
||||||
|
Tracks are selected at random from the playlist.
|
||||||
|
:class:`False`
|
||||||
|
Tracks are played in the order of the playlist.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_repeat(self):
|
||||||
|
return getattr(self, '_repeat', False)
|
||||||
|
|
||||||
|
def set_repeat(self, value):
|
||||||
|
if self.get_repeat() != value:
|
||||||
|
self._trigger_options_changed()
|
||||||
|
return setattr(self, '_repeat', value)
|
||||||
|
|
||||||
|
repeat = property(get_repeat, set_repeat)
|
||||||
|
"""
|
||||||
|
:class:`True`
|
||||||
|
The current playlist is played repeatedly. To repeat a single track,
|
||||||
|
select both :attr:`repeat` and :attr:`single`.
|
||||||
|
:class:`False`
|
||||||
|
The current playlist is played once.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_single(self):
|
||||||
|
return getattr(self, '_single', False)
|
||||||
|
|
||||||
|
def set_single(self, value):
|
||||||
|
if self.get_single() != value:
|
||||||
|
self._trigger_options_changed()
|
||||||
|
return setattr(self, '_single', value)
|
||||||
|
|
||||||
|
single = property(get_single, set_single)
|
||||||
|
"""
|
||||||
|
:class:`True`
|
||||||
|
Playback is stopped after current song, unless in :attr:`repeat`
|
||||||
|
mode.
|
||||||
|
:class:`False`
|
||||||
|
Playback continues after current song.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def set_state(self, new_state):
|
||||||
|
(old_state, self._state) = (self.state, new_state)
|
||||||
|
logger.debug('Changing state: %s -> %s', old_state, new_state)
|
||||||
|
|
||||||
|
self._trigger_playback_state_changed(old_state, new_state)
|
||||||
|
|
||||||
|
state = property(get_state, set_state)
|
||||||
|
"""
|
||||||
|
The playback state. Must be :attr:`PLAYING`, :attr:`PAUSED`, or
|
||||||
|
:attr:`STOPPED`.
|
||||||
|
|
||||||
|
Possible states and transitions:
|
||||||
|
|
||||||
|
.. digraph:: state_transitions
|
||||||
|
|
||||||
|
"STOPPED" -> "PLAYING" [ label="play" ]
|
||||||
|
"STOPPED" -> "PAUSED" [ label="pause" ]
|
||||||
|
"PLAYING" -> "STOPPED" [ label="stop" ]
|
||||||
|
"PLAYING" -> "PAUSED" [ label="pause" ]
|
||||||
|
"PLAYING" -> "PLAYING" [ label="play" ]
|
||||||
|
"PAUSED" -> "PLAYING" [ label="resume" ]
|
||||||
|
"PAUSED" -> "STOPPED" [ label="stop" ]
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_time_position(self):
|
||||||
|
backend = self._get_backend()
|
||||||
|
if backend:
|
||||||
|
return backend.playback.get_time_position().get()
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
time_position = property(get_time_position)
|
||||||
|
"""Time position in milliseconds."""
|
||||||
|
|
||||||
|
def get_tracklist_position(self):
|
||||||
if self.current_tl_track is None:
|
if self.current_tl_track is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@ -122,25 +164,14 @@ class PlaybackController(object):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
tracklist_position = property(get_tracklist_position)
|
||||||
def track_at_eot(self):
|
"""
|
||||||
"""
|
The position of the current track in the tracklist.
|
||||||
The track that will be played at the end of the current track.
|
|
||||||
|
|
||||||
Read-only. A :class:`mopidy.models.Track` extracted from
|
Read-only.
|
||||||
:attr:`tl_track_at_eot` for convenience.
|
"""
|
||||||
"""
|
|
||||||
return self._get_track(self.tl_track_at_eot)
|
|
||||||
|
|
||||||
@property
|
def get_tl_track_at_eot(self):
|
||||||
def tl_track_at_eot(self):
|
|
||||||
"""
|
|
||||||
The track that will be played at the end of the current track.
|
|
||||||
|
|
||||||
Read-only. A :class:`mopidy.models.TlTrack`.
|
|
||||||
|
|
||||||
Not necessarily the same track as :attr:`tl_track_at_next`.
|
|
||||||
"""
|
|
||||||
# pylint: disable = R0911
|
# pylint: disable = R0911
|
||||||
# Too many return statements
|
# Too many return statements
|
||||||
|
|
||||||
@ -173,28 +204,16 @@ class PlaybackController(object):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
tl_track_at_eot = property(get_tl_track_at_eot)
|
||||||
def track_at_next(self):
|
"""
|
||||||
"""
|
The track that will be played at the end of the current track.
|
||||||
The track that will be played if calling :meth:`next()`.
|
|
||||||
|
|
||||||
Read-only. A :class:`mopidy.models.Track` extracted from
|
Read-only. A :class:`mopidy.models.TlTrack`.
|
||||||
:attr:`tl_track_at_next` for convenience.
|
|
||||||
"""
|
|
||||||
return self._get_track(self.tl_track_at_next)
|
|
||||||
|
|
||||||
@property
|
Not necessarily the same track as :attr:`tl_track_at_next`.
|
||||||
def tl_track_at_next(self):
|
"""
|
||||||
"""
|
|
||||||
The track that will be played if calling :meth:`next()`.
|
|
||||||
|
|
||||||
Read-only. A :class:`mopidy.models.TlTrack`.
|
def get_tl_track_at_next(self):
|
||||||
|
|
||||||
For normal playback this is the next track in the playlist. If repeat
|
|
||||||
is enabled the next track can loop around the playlist. When random is
|
|
||||||
enabled this should be a random track, all tracks should be played once
|
|
||||||
before the list repeats.
|
|
||||||
"""
|
|
||||||
tl_tracks = self.core.tracklist.tl_tracks
|
tl_tracks = self.core.tracklist.tl_tracks
|
||||||
|
|
||||||
if not tl_tracks:
|
if not tl_tracks:
|
||||||
@ -221,27 +240,19 @@ class PlaybackController(object):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
tl_track_at_next = property(get_tl_track_at_next)
|
||||||
def track_at_previous(self):
|
"""
|
||||||
"""
|
The track that will be played if calling :meth:`next()`.
|
||||||
The track that will be played if calling :meth:`previous()`.
|
|
||||||
|
|
||||||
Read-only. A :class:`mopidy.models.Track` extracted from
|
Read-only. A :class:`mopidy.models.TlTrack`.
|
||||||
:attr:`tl_track_at_previous` for convenience.
|
|
||||||
"""
|
|
||||||
return self._get_track(self.tl_track_at_previous)
|
|
||||||
|
|
||||||
@property
|
For normal playback this is the next track in the playlist. If repeat
|
||||||
def tl_track_at_previous(self):
|
is enabled the next track can loop around the playlist. When random is
|
||||||
"""
|
enabled this should be a random track, all tracks should be played once
|
||||||
The track that will be played if calling :meth:`previous()`.
|
before the list repeats.
|
||||||
|
"""
|
||||||
|
|
||||||
A :class:`mopidy.models.TlTrack`.
|
def get_tl_track_at_previous(self):
|
||||||
|
|
||||||
For normal playback this is the previous track in the playlist. If
|
|
||||||
random and/or consume is enabled it should return the current track
|
|
||||||
instead.
|
|
||||||
"""
|
|
||||||
if self.repeat or self.consume or self.random:
|
if self.repeat or self.consume or self.random:
|
||||||
return self.current_tl_track
|
return self.current_tl_track
|
||||||
|
|
||||||
@ -250,59 +261,36 @@ class PlaybackController(object):
|
|||||||
|
|
||||||
return self.core.tracklist.tl_tracks[self.tracklist_position - 1]
|
return self.core.tracklist.tl_tracks[self.tracklist_position - 1]
|
||||||
|
|
||||||
@property
|
tl_track_at_previous = property(get_tl_track_at_previous)
|
||||||
def state(self):
|
"""
|
||||||
"""
|
The track that will be played if calling :meth:`previous()`.
|
||||||
The playback state. Must be :attr:`PLAYING`, :attr:`PAUSED`, or
|
|
||||||
:attr:`STOPPED`.
|
|
||||||
|
|
||||||
Possible states and transitions:
|
A :class:`mopidy.models.TlTrack`.
|
||||||
|
|
||||||
.. digraph:: state_transitions
|
For normal playback this is the previous track in the playlist. If
|
||||||
|
random and/or consume is enabled it should return the current track
|
||||||
|
instead.
|
||||||
|
"""
|
||||||
|
|
||||||
"STOPPED" -> "PLAYING" [ label="play" ]
|
def get_volume(self):
|
||||||
"STOPPED" -> "PAUSED" [ label="pause" ]
|
|
||||||
"PLAYING" -> "STOPPED" [ label="stop" ]
|
|
||||||
"PLAYING" -> "PAUSED" [ label="pause" ]
|
|
||||||
"PLAYING" -> "PLAYING" [ label="play" ]
|
|
||||||
"PAUSED" -> "PLAYING" [ label="resume" ]
|
|
||||||
"PAUSED" -> "STOPPED" [ label="stop" ]
|
|
||||||
"""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@state.setter # noqa
|
|
||||||
def state(self, new_state):
|
|
||||||
(old_state, self._state) = (self.state, new_state)
|
|
||||||
logger.debug('Changing state: %s -> %s', old_state, new_state)
|
|
||||||
|
|
||||||
self._trigger_playback_state_changed(old_state, new_state)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def time_position(self):
|
|
||||||
"""Time position in milliseconds."""
|
|
||||||
backend = self._get_backend()
|
|
||||||
if backend:
|
|
||||||
return backend.playback.get_time_position().get()
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
@property
|
|
||||||
def volume(self):
|
|
||||||
"""Volume as int in range [0..100] or :class:`None`"""
|
|
||||||
if self.audio:
|
if self.audio:
|
||||||
return self.audio.get_volume().get()
|
return self.audio.get_volume().get()
|
||||||
else:
|
else:
|
||||||
# For testing
|
# For testing
|
||||||
return self._volume
|
return self._volume
|
||||||
|
|
||||||
@volume.setter # noqa
|
def set_volume(self, volume):
|
||||||
def volume(self, volume):
|
|
||||||
if self.audio:
|
if self.audio:
|
||||||
self.audio.set_volume(volume)
|
self.audio.set_volume(volume)
|
||||||
else:
|
else:
|
||||||
# For testing
|
# For testing
|
||||||
self._volume = volume
|
self._volume = volume
|
||||||
|
|
||||||
|
volume = property(get_volume, set_volume)
|
||||||
|
"""Volume as int in range [0..100] or :class:`None`"""
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
def change_track(self, tl_track, on_error_step=1):
|
def change_track(self, tl_track, on_error_step=1):
|
||||||
"""
|
"""
|
||||||
Change to the given track, keeping the current playback state.
|
Change to the given track, keeping the current playback state.
|
||||||
@ -324,6 +312,8 @@ class PlaybackController(object):
|
|||||||
def on_end_of_track(self):
|
def on_end_of_track(self):
|
||||||
"""
|
"""
|
||||||
Tell the playback controller that end of track is reached.
|
Tell the playback controller that end of track is reached.
|
||||||
|
|
||||||
|
Used by event handler in :class:`mopidy.core.Core`.
|
||||||
"""
|
"""
|
||||||
if self.state == PlaybackState.STOPPED:
|
if self.state == PlaybackState.STOPPED:
|
||||||
return
|
return
|
||||||
@ -343,7 +333,7 @@ class PlaybackController(object):
|
|||||||
"""
|
"""
|
||||||
Tell the playback controller that the current playlist has changed.
|
Tell the playback controller that the current playlist has changed.
|
||||||
|
|
||||||
Used by :class:`mopidy.core.CurrentPlaylistController`.
|
Used by :class:`mopidy.core.TracklistController`.
|
||||||
"""
|
"""
|
||||||
self._first_shuffle = True
|
self._first_shuffle = True
|
||||||
self._shuffled = []
|
self._shuffled = []
|
||||||
|
|||||||
@ -15,18 +15,19 @@ class PlaylistsController(object):
|
|||||||
self.backends = backends
|
self.backends = backends
|
||||||
self.core = core
|
self.core = core
|
||||||
|
|
||||||
@property
|
def get_playlists(self):
|
||||||
def playlists(self):
|
|
||||||
"""
|
|
||||||
The available playlists.
|
|
||||||
|
|
||||||
Read-only. List of :class:`mopidy.models.Playlist`.
|
|
||||||
"""
|
|
||||||
futures = [
|
futures = [
|
||||||
b.playlists.playlists for b in self.backends.with_playlists]
|
b.playlists.playlists for b in self.backends.with_playlists]
|
||||||
results = pykka.get_all(futures)
|
results = pykka.get_all(futures)
|
||||||
return list(itertools.chain(*results))
|
return list(itertools.chain(*results))
|
||||||
|
|
||||||
|
playlists = property(get_playlists)
|
||||||
|
"""
|
||||||
|
The available playlists.
|
||||||
|
|
||||||
|
Read-only. List of :class:`mopidy.models.Playlist`.
|
||||||
|
"""
|
||||||
|
|
||||||
def create(self, name, uri_scheme=None):
|
def create(self, name, uri_scheme=None):
|
||||||
"""
|
"""
|
||||||
Create a new playlist.
|
Create a new playlist.
|
||||||
|
|||||||
@ -20,89 +20,77 @@ class TracklistController(object):
|
|||||||
self._tl_tracks = []
|
self._tl_tracks = []
|
||||||
self._version = 0
|
self._version = 0
|
||||||
|
|
||||||
@property
|
def get_tl_tracks(self):
|
||||||
def tl_tracks(self):
|
|
||||||
"""
|
|
||||||
List of :class:`mopidy.models.TlTrack`.
|
|
||||||
|
|
||||||
Read-only.
|
|
||||||
"""
|
|
||||||
return self._tl_tracks[:]
|
return self._tl_tracks[:]
|
||||||
|
|
||||||
@property
|
tl_tracks = property(get_tl_tracks)
|
||||||
def tracks(self):
|
"""
|
||||||
"""
|
List of :class:`mopidy.models.TlTrack`.
|
||||||
List of :class:`mopidy.models.Track` in the tracklist.
|
|
||||||
|
|
||||||
Read-only.
|
Read-only.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def get_tracks(self):
|
||||||
return [tl_track.track for tl_track in self._tl_tracks]
|
return [tl_track.track for tl_track in self._tl_tracks]
|
||||||
|
|
||||||
@property
|
tracks = property(get_tracks)
|
||||||
def length(self):
|
"""
|
||||||
"""
|
List of :class:`mopidy.models.Track` in the tracklist.
|
||||||
Length of the tracklist.
|
|
||||||
"""
|
Read-only.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_length(self):
|
||||||
return len(self._tl_tracks)
|
return len(self._tl_tracks)
|
||||||
|
|
||||||
@property
|
length = property(get_length)
|
||||||
def version(self):
|
"""Length of the tracklist."""
|
||||||
"""
|
|
||||||
The tracklist version. Integer which is increased every time the
|
def get_version(self):
|
||||||
tracklist is changed. Is not reset before Mopidy is restarted.
|
|
||||||
"""
|
|
||||||
return self._version
|
return self._version
|
||||||
|
|
||||||
@version.setter # noqa
|
def _increase_version(self):
|
||||||
def version(self, version):
|
self._version += 1
|
||||||
self._version = version
|
|
||||||
self._core.playback.on_tracklist_change()
|
self._core.playback.on_tracklist_change()
|
||||||
self._trigger_tracklist_changed()
|
self._trigger_tracklist_changed()
|
||||||
|
|
||||||
def add(self, track, at_position=None, increase_version=True):
|
version = property(get_version)
|
||||||
|
"""
|
||||||
|
The tracklist version.
|
||||||
|
|
||||||
|
Read-only. Integer which is increased every time the tracklist is changed.
|
||||||
|
Is not reset before Mopidy is restarted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add(self, tracks, at_position=None):
|
||||||
"""
|
"""
|
||||||
Add the track to the end of, or at the given position in the tracklist.
|
Add the track or list of tracks to the tracklist.
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
If ``at_position`` is given, the tracks placed at the given position in
|
||||||
event.
|
the tracklist. If ``at_position`` is not given, the tracks are appended
|
||||||
|
to the end of the tracklist.
|
||||||
|
|
||||||
:param track: track to add
|
Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.
|
||||||
:type track: :class:`mopidy.models.Track`
|
|
||||||
|
:param tracks: tracks to add
|
||||||
|
:type tracks: list of :class:`mopidy.models.Track`
|
||||||
:param at_position: position in tracklist to add track
|
:param at_position: position in tracklist to add track
|
||||||
:type at_position: int or :class:`None`
|
:type at_position: int or :class:`None`
|
||||||
:param increase_version: if the tracklist version should be increased
|
:rtype: list of :class:`mopidy.models.TlTrack`
|
||||||
:type increase_version: :class:`True` or :class:`False`
|
|
||||||
:rtype: :class:`mopidy.models.TlTrack` that was added to the tracklist
|
|
||||||
"""
|
|
||||||
assert at_position <= len(self._tl_tracks), \
|
|
||||||
'at_position can not be greater than tracklist length'
|
|
||||||
tl_track = TlTrack(self._next_tlid, track)
|
|
||||||
if at_position is not None:
|
|
||||||
self._tl_tracks.insert(at_position, tl_track)
|
|
||||||
else:
|
|
||||||
self._tl_tracks.append(tl_track)
|
|
||||||
if increase_version:
|
|
||||||
self.version += 1
|
|
||||||
self._next_tlid += 1
|
|
||||||
return tl_track
|
|
||||||
|
|
||||||
def append(self, tracks):
|
|
||||||
"""
|
|
||||||
Append the given tracks to the tracklist.
|
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
|
||||||
event.
|
|
||||||
|
|
||||||
:param tracks: tracks to append
|
|
||||||
:type tracks: list of :class:`mopidy.models.Track`
|
|
||||||
:rtype: list of class:`mopidy.models.TlTrack`
|
|
||||||
"""
|
"""
|
||||||
tl_tracks = []
|
tl_tracks = []
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
tl_tracks.append(self.add(track, increase_version=False))
|
tl_track = TlTrack(self._next_tlid, track)
|
||||||
|
self._next_tlid += 1
|
||||||
|
if at_position is not None:
|
||||||
|
self._tl_tracks.insert(at_position, tl_track)
|
||||||
|
at_position += 1
|
||||||
|
else:
|
||||||
|
self._tl_tracks.append(tl_track)
|
||||||
|
tl_tracks.append(tl_track)
|
||||||
|
|
||||||
if tracks:
|
if tl_tracks:
|
||||||
self.version += 1
|
self._increase_version()
|
||||||
|
|
||||||
return tl_tracks
|
return tl_tracks
|
||||||
|
|
||||||
@ -110,11 +98,10 @@ class TracklistController(object):
|
|||||||
"""
|
"""
|
||||||
Clear the tracklist.
|
Clear the tracklist.
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.
|
||||||
event.
|
|
||||||
"""
|
"""
|
||||||
self._tl_tracks = []
|
self._tl_tracks = []
|
||||||
self.version += 1
|
self._increase_version()
|
||||||
|
|
||||||
def filter(self, **criteria):
|
def filter(self, **criteria):
|
||||||
"""
|
"""
|
||||||
@ -156,8 +143,7 @@ class TracklistController(object):
|
|||||||
"""
|
"""
|
||||||
Move the tracks in the slice ``[start:end]`` to ``to_position``.
|
Move the tracks in the slice ``[start:end]`` to ``to_position``.
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.
|
||||||
event.
|
|
||||||
|
|
||||||
:param start: position of first track to move
|
:param start: position of first track to move
|
||||||
:type start: int
|
:type start: int
|
||||||
@ -184,7 +170,7 @@ class TracklistController(object):
|
|||||||
new_tl_tracks.insert(to_position, tl_track)
|
new_tl_tracks.insert(to_position, tl_track)
|
||||||
to_position += 1
|
to_position += 1
|
||||||
self._tl_tracks = new_tl_tracks
|
self._tl_tracks = new_tl_tracks
|
||||||
self.version += 1
|
self._increase_version()
|
||||||
|
|
||||||
def remove(self, **criteria):
|
def remove(self, **criteria):
|
||||||
"""
|
"""
|
||||||
@ -192,8 +178,7 @@ class TracklistController(object):
|
|||||||
|
|
||||||
Uses :meth:`filter()` to lookup the tracks to remove.
|
Uses :meth:`filter()` to lookup the tracks to remove.
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.
|
||||||
event.
|
|
||||||
|
|
||||||
:param criteria: on or more criteria to match by
|
:param criteria: on or more criteria to match by
|
||||||
:type criteria: dict
|
:type criteria: dict
|
||||||
@ -203,7 +188,7 @@ class TracklistController(object):
|
|||||||
for tl_track in tl_tracks:
|
for tl_track in tl_tracks:
|
||||||
position = self._tl_tracks.index(tl_track)
|
position = self._tl_tracks.index(tl_track)
|
||||||
del self._tl_tracks[position]
|
del self._tl_tracks[position]
|
||||||
self.version += 1
|
self._increase_version()
|
||||||
return tl_tracks
|
return tl_tracks
|
||||||
|
|
||||||
def shuffle(self, start=None, end=None):
|
def shuffle(self, start=None, end=None):
|
||||||
@ -211,8 +196,7 @@ class TracklistController(object):
|
|||||||
Shuffles the entire tracklist. If ``start`` and ``end`` is given only
|
Shuffles the entire tracklist. If ``start`` and ``end`` is given only
|
||||||
shuffles the slice ``[start:end]``.
|
shuffles the slice ``[start:end]``.
|
||||||
|
|
||||||
Triggers the :method:`mopidy.core.CoreListener.tracklist_changed`
|
Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.
|
||||||
event.
|
|
||||||
|
|
||||||
:param start: position of first track to shuffle
|
:param start: position of first track to shuffle
|
||||||
:type start: int or :class:`None`
|
:type start: int or :class:`None`
|
||||||
@ -236,7 +220,7 @@ class TracklistController(object):
|
|||||||
after = tl_tracks[end or len(tl_tracks):]
|
after = tl_tracks[end or len(tl_tracks):]
|
||||||
random.shuffle(shuffled)
|
random.shuffle(shuffled)
|
||||||
self._tl_tracks = before + shuffled + after
|
self._tl_tracks = before + shuffled + after
|
||||||
self.version += 1
|
self._increase_version()
|
||||||
|
|
||||||
def slice(self, start, end):
|
def slice(self, start, end):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -56,10 +56,11 @@ def handle_request(pattern, auth_required=True):
|
|||||||
if match is not None:
|
if match is not None:
|
||||||
mpd_commands.add(
|
mpd_commands.add(
|
||||||
MpdCommand(name=match.group(), auth_required=auth_required))
|
MpdCommand(name=match.group(), auth_required=auth_required))
|
||||||
if pattern in request_handlers:
|
compiled_pattern = re.compile(pattern, flags=re.UNICODE)
|
||||||
|
if compiled_pattern in request_handlers:
|
||||||
raise ValueError('Tried to redefine handler for %s with %s' % (
|
raise ValueError('Tried to redefine handler for %s with %s' % (
|
||||||
pattern, func))
|
pattern, func))
|
||||||
request_handlers[pattern] = func
|
request_handlers[compiled_pattern] = func
|
||||||
func.__doc__ = ' - *Pattern:* ``%s``\n\n%s' % (
|
func.__doc__ = ' - *Pattern:* ``%s``\n\n%s' % (
|
||||||
pattern, func.__doc__ or '')
|
pattern, func.__doc__ or '')
|
||||||
return func
|
return func
|
||||||
|
|||||||
@ -24,7 +24,7 @@ def add(context, uri):
|
|||||||
return
|
return
|
||||||
tracks = context.core.library.lookup(uri).get()
|
tracks = context.core.library.lookup(uri).get()
|
||||||
if tracks:
|
if tracks:
|
||||||
context.core.tracklist.append(tracks)
|
context.core.tracklist.add(tracks)
|
||||||
return
|
return
|
||||||
raise MpdNoExistError('directory or file not found', command='add')
|
raise MpdNoExistError('directory or file not found', command='add')
|
||||||
|
|
||||||
@ -57,14 +57,8 @@ def addid(context, uri, songpos=None):
|
|||||||
raise MpdNoExistError('No such song', command='addid')
|
raise MpdNoExistError('No such song', command='addid')
|
||||||
if songpos and songpos > context.core.tracklist.length.get():
|
if songpos and songpos > context.core.tracklist.length.get():
|
||||||
raise MpdArgError('Bad song index', command='addid')
|
raise MpdArgError('Bad song index', command='addid')
|
||||||
first_tl_track = None
|
tl_tracks = context.core.tracklist.add(tracks, at_position=songpos).get()
|
||||||
for track in tracks:
|
return ('Id', tl_tracks[0].tlid)
|
||||||
tl_track = context.core.tracklist.add(track, at_position=songpos).get()
|
|
||||||
if songpos is not None:
|
|
||||||
songpos += 1
|
|
||||||
if first_tl_track is None:
|
|
||||||
first_tl_track = tl_track
|
|
||||||
return ('Id', first_tl_track.tlid)
|
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^delete "(?P<start>\d+):(?P<end>\d+)*"$')
|
@handle_request(r'^delete "(?P<start>\d+):(?P<end>\d+)*"$')
|
||||||
@ -110,7 +104,8 @@ def deleteid(context, tlid):
|
|||||||
Deletes the song ``SONGID`` from the playlist
|
Deletes the song ``SONGID`` from the playlist
|
||||||
"""
|
"""
|
||||||
tlid = int(tlid)
|
tlid = int(tlid)
|
||||||
if context.core.playback.current_tlid.get() == tlid:
|
tl_track = context.core.playback.current_tl_track.get()
|
||||||
|
if tl_track and tl_track.tlid == tlid:
|
||||||
context.core.playback.next()
|
context.core.playback.next()
|
||||||
tl_tracks = context.core.tracklist.remove(tlid=tlid).get()
|
tl_tracks = context.core.tracklist.remove(tlid=tlid).get()
|
||||||
if not tl_tracks:
|
if not tl_tracks:
|
||||||
@ -237,7 +232,6 @@ def playlistid(context, tlid=None):
|
|||||||
|
|
||||||
|
|
||||||
@handle_request(r'^playlistinfo$')
|
@handle_request(r'^playlistinfo$')
|
||||||
@handle_request(r'^playlistinfo "-1"$')
|
|
||||||
@handle_request(r'^playlistinfo "(?P<songpos>-?\d+)"$')
|
@handle_request(r'^playlistinfo "(?P<songpos>-?\d+)"$')
|
||||||
@handle_request(r'^playlistinfo "(?P<start>\d+):(?P<end>\d+)*"$')
|
@handle_request(r'^playlistinfo "(?P<start>\d+):(?P<end>\d+)*"$')
|
||||||
def playlistinfo(context, songpos=None, start=None, end=None):
|
def playlistinfo(context, songpos=None, start=None, end=None):
|
||||||
@ -255,6 +249,8 @@ def playlistinfo(context, songpos=None, start=None, end=None):
|
|||||||
- uses negative indexes, like ``playlistinfo "-1"``, to request
|
- uses negative indexes, like ``playlistinfo "-1"``, to request
|
||||||
the entire playlist
|
the entire playlist
|
||||||
"""
|
"""
|
||||||
|
if songpos == '-1':
|
||||||
|
songpos = None
|
||||||
if songpos is not None:
|
if songpos is not None:
|
||||||
songpos = int(songpos)
|
songpos = int(songpos)
|
||||||
tl_track = context.core.tracklist.tl_tracks.get()[songpos]
|
tl_track = context.core.tracklist.tl_tracks.get()[songpos]
|
||||||
@ -274,7 +270,7 @@ def playlistinfo(context, songpos=None, start=None, end=None):
|
|||||||
|
|
||||||
|
|
||||||
@handle_request(r'^playlistsearch "(?P<tag>[^"]+)" "(?P<needle>[^"]+)"$')
|
@handle_request(r'^playlistsearch "(?P<tag>[^"]+)" "(?P<needle>[^"]+)"$')
|
||||||
@handle_request(r'^playlistsearch (?P<tag>\S+) "(?P<needle>[^"]+)"$')
|
@handle_request(r'^playlistsearch (?P<tag>\w+) "(?P<needle>[^"]+)"$')
|
||||||
def playlistsearch(context, tag, needle):
|
def playlistsearch(context, tag, needle):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, current playlist section:*
|
*musicpd.org, current playlist section:*
|
||||||
@ -376,7 +372,7 @@ def swap(context, songpos1, songpos2):
|
|||||||
del tracks[songpos2]
|
del tracks[songpos2]
|
||||||
tracks.insert(songpos2, song1)
|
tracks.insert(songpos2, song1)
|
||||||
context.core.tracklist.clear()
|
context.core.tracklist.clear()
|
||||||
context.core.tracklist.append(tracks)
|
context.core.tracklist.add(tracks)
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^swapid "(?P<tlid1>\d+)" "(?P<tlid2>\d+)"$')
|
@handle_request(r'^swapid "(?P<tlid1>\d+)" "(?P<tlid2>\d+)"$')
|
||||||
|
|||||||
@ -52,7 +52,7 @@ def count(context, tag, needle):
|
|||||||
|
|
||||||
@handle_request(
|
@handle_request(
|
||||||
r'^find (?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile[name]*|'
|
r'^find (?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile[name]*|'
|
||||||
r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$')
|
r'[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$')
|
||||||
def find(context, mpd_query):
|
def find(context, mpd_query):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, music database section:*
|
*musicpd.org, music database section:*
|
||||||
@ -250,7 +250,8 @@ def _list_artist(context, query):
|
|||||||
tracks = context.core.library.find_exact(**query).get()
|
tracks = context.core.library.find_exact(**query).get()
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
for artist in track.artists:
|
for artist in track.artists:
|
||||||
artists.add(('Artist', artist.name))
|
if artist.name:
|
||||||
|
artists.add(('Artist', artist.name))
|
||||||
return artists
|
return artists
|
||||||
|
|
||||||
|
|
||||||
@ -258,7 +259,7 @@ def _list_album(context, query):
|
|||||||
albums = set()
|
albums = set()
|
||||||
tracks = context.core.library.find_exact(**query).get()
|
tracks = context.core.library.find_exact(**query).get()
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
if track.album is not None:
|
if track.album and track.album.name:
|
||||||
albums.add(('Album', track.album.name))
|
albums.add(('Album', track.album.name))
|
||||||
return albums
|
return albums
|
||||||
|
|
||||||
@ -267,7 +268,7 @@ def _list_date(context, query):
|
|||||||
dates = set()
|
dates = set()
|
||||||
tracks = context.core.library.find_exact(**query).get()
|
tracks = context.core.library.find_exact(**query).get()
|
||||||
for track in tracks:
|
for track in tracks:
|
||||||
if track.date is not None:
|
if track.date:
|
||||||
dates.add(('Date', track.date))
|
dates.add(('Date', track.date))
|
||||||
return dates
|
return dates
|
||||||
|
|
||||||
@ -334,7 +335,7 @@ def rescan(context, uri=None):
|
|||||||
|
|
||||||
@handle_request(
|
@handle_request(
|
||||||
r'^search (?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile[name]*|'
|
r'^search (?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile[name]*|'
|
||||||
r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$')
|
r'[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$')
|
||||||
def search(context, mpd_query):
|
def search(context, mpd_query):
|
||||||
"""
|
"""
|
||||||
*musicpd.org, music database section:*
|
*musicpd.org, music database section:*
|
||||||
|
|||||||
@ -329,9 +329,9 @@ def seek(context, songpos, seconds):
|
|||||||
|
|
||||||
- issues ``seek 1 120`` without quotes around the arguments.
|
- issues ``seek 1 120`` without quotes around the arguments.
|
||||||
"""
|
"""
|
||||||
if context.core.playback.tracklist_position != songpos:
|
if context.core.playback.tracklist_position.get() != songpos:
|
||||||
playpos(context, songpos)
|
playpos(context, songpos)
|
||||||
context.core.playback.seek(int(seconds) * 1000)
|
context.core.playback.seek(int(seconds) * 1000).get()
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^seekid "(?P<tlid>\d+)" "(?P<seconds>\d+)"$')
|
@handle_request(r'^seekid "(?P<tlid>\d+)" "(?P<seconds>\d+)"$')
|
||||||
@ -343,9 +343,10 @@ def seekid(context, tlid, seconds):
|
|||||||
|
|
||||||
Seeks to the position ``TIME`` (in seconds) of song ``SONGID``.
|
Seeks to the position ``TIME`` (in seconds) of song ``SONGID``.
|
||||||
"""
|
"""
|
||||||
if context.core.playback.current_tlid != tlid:
|
tl_track = context.core.playback.current_tl_track.get()
|
||||||
|
if not tl_track or tl_track.tlid != tlid:
|
||||||
playid(context, tlid)
|
playid(context, tlid)
|
||||||
context.core.playback.seek(int(seconds) * 1000)
|
context.core.playback.seek(int(seconds) * 1000).get()
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^setvol (?P<volume>[-+]*\d+)$')
|
@handle_request(r'^setvol (?P<volume>[-+]*\d+)$')
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from mopidy.frontends.mpd.protocol import handle_request, mpd_commands
|
from mopidy.frontends.mpd.protocol import handle_request, mpd_commands
|
||||||
from mopidy.frontends.mpd.exceptions import MpdNotImplemented
|
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^commands$', auth_required=False)
|
@handle_request(r'^commands$', auth_required=False)
|
||||||
@ -47,8 +46,15 @@ def decoders(context):
|
|||||||
mime_type: audio/mpeg
|
mime_type: audio/mpeg
|
||||||
plugin: mpcdec
|
plugin: mpcdec
|
||||||
suffix: mpc
|
suffix: mpc
|
||||||
|
|
||||||
|
*Clarifications:*
|
||||||
|
|
||||||
|
- ncmpcpp asks for decoders the first time you open the browse view. By
|
||||||
|
returning nothing and OK instead of an not implemented error, we avoid
|
||||||
|
"Not implemented" showing up in the ncmpcpp interface, and we get the
|
||||||
|
list of playlists without having to enter the browse interface twice.
|
||||||
"""
|
"""
|
||||||
raise MpdNotImplemented # TODO
|
return # TODO
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^notcommands$', auth_required=False)
|
@handle_request(r'^notcommands$', auth_required=False)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ from mopidy.frontends.mpd.protocol import handle_request
|
|||||||
from mopidy.frontends.mpd.translator import playlist_to_mpd_format
|
from mopidy.frontends.mpd.translator import playlist_to_mpd_format
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^listplaylist (?P<name>\S+)$')
|
@handle_request(r'^listplaylist (?P<name>\w+)$')
|
||||||
@handle_request(r'^listplaylist "(?P<name>[^"]+)"$')
|
@handle_request(r'^listplaylist "(?P<name>[^"]+)"$')
|
||||||
def listplaylist(context, name):
|
def listplaylist(context, name):
|
||||||
"""
|
"""
|
||||||
@ -29,7 +29,7 @@ def listplaylist(context, name):
|
|||||||
return ['file: %s' % t.uri for t in playlists[0].tracks]
|
return ['file: %s' % t.uri for t in playlists[0].tracks]
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^listplaylistinfo (?P<name>\S+)$')
|
@handle_request(r'^listplaylistinfo (?P<name>\w+)$')
|
||||||
@handle_request(r'^listplaylistinfo "(?P<name>[^"]+)"$')
|
@handle_request(r'^listplaylistinfo "(?P<name>[^"]+)"$')
|
||||||
def listplaylistinfo(context, name):
|
def listplaylistinfo(context, name):
|
||||||
"""
|
"""
|
||||||
@ -70,9 +70,16 @@ def listplaylists(context):
|
|||||||
Last-Modified: 2010-02-06T02:10:25Z
|
Last-Modified: 2010-02-06T02:10:25Z
|
||||||
playlist: b
|
playlist: b
|
||||||
Last-Modified: 2010-02-06T02:11:08Z
|
Last-Modified: 2010-02-06T02:11:08Z
|
||||||
|
|
||||||
|
*Clarifications:*
|
||||||
|
|
||||||
|
- ncmpcpp 0.5.10 segfaults if we return 'playlist: ' on a line, so we must
|
||||||
|
ignore playlists without names, which isn't very useful anyway.
|
||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
for playlist in context.core.playlists.playlists.get():
|
for playlist in context.core.playlists.playlists.get():
|
||||||
|
if not playlist.name:
|
||||||
|
continue
|
||||||
result.append(('playlist', playlist.name))
|
result.append(('playlist', playlist.name))
|
||||||
last_modified = (
|
last_modified = (
|
||||||
playlist.last_modified or dt.datetime.now()).isoformat()
|
playlist.last_modified or dt.datetime.now()).isoformat()
|
||||||
@ -101,7 +108,7 @@ def load(context, name):
|
|||||||
playlists = context.core.playlists.filter(name=name).get()
|
playlists = context.core.playlists.filter(name=name).get()
|
||||||
if not playlists:
|
if not playlists:
|
||||||
raise MpdNoExistError('No such playlist', command='load')
|
raise MpdNoExistError('No such playlist', command='load')
|
||||||
context.core.tracklist.append(playlists[0].tracks)
|
context.core.tracklist.add(playlists[0].tracks)
|
||||||
|
|
||||||
|
|
||||||
@handle_request(r'^playlistadd "(?P<name>[^"]+)" "(?P<uri>[^"]+)"$')
|
@handle_request(r'^playlistadd "(?P<name>[^"]+)" "(?P<uri>[^"]+)"$')
|
||||||
|
|||||||
@ -281,7 +281,7 @@ class MprisObject(dbus.service.Object):
|
|||||||
# is added to the backend.
|
# is added to the backend.
|
||||||
tracks = self.core.library.lookup(uri).get()
|
tracks = self.core.library.lookup(uri).get()
|
||||||
if tracks:
|
if tracks:
|
||||||
tl_tracks = self.core.tracklist.append(tracks).get()
|
tl_tracks = self.core.tracklist.add(tracks).get()
|
||||||
self.core.playback.play(tl_tracks[0])
|
self.core.playback.play(tl_tracks[0])
|
||||||
else:
|
else:
|
||||||
logger.debug('Track with URI "%s" not found in library.', uri)
|
logger.debug('Track with URI "%s" not found in library.', uri)
|
||||||
@ -419,8 +419,8 @@ class MprisObject(dbus.service.Object):
|
|||||||
if not self.get_CanControl():
|
if not self.get_CanControl():
|
||||||
return False
|
return False
|
||||||
return (
|
return (
|
||||||
self.core.playback.current_track.get() is not None or
|
self.core.playback.current_tl_track.get() is not None or
|
||||||
self.core.playback.track_at_next.get() is not None)
|
self.core.playback.tl_track_at_next.get() is not None)
|
||||||
|
|
||||||
def get_CanPause(self):
|
def get_CanPause(self):
|
||||||
if not self.get_CanControl():
|
if not self.get_CanControl():
|
||||||
@ -449,7 +449,7 @@ class MprisObject(dbus.service.Object):
|
|||||||
playlist_uri = self.get_playlist_uri(playlist_id)
|
playlist_uri = self.get_playlist_uri(playlist_id)
|
||||||
playlist = self.core.playlists.lookup(playlist_uri).get()
|
playlist = self.core.playlists.lookup(playlist_uri).get()
|
||||||
if playlist and playlist.tracks:
|
if playlist and playlist.tracks:
|
||||||
tl_tracks = self.core.tracklist.append(playlist.tracks).get()
|
tl_tracks = self.core.tracklist.add(playlist.tracks).get()
|
||||||
self.core.playback.play(tl_tracks[0])
|
self.core.playback.play(tl_tracks[0])
|
||||||
|
|
||||||
@dbus.service.method(dbus_interface=PLAYLISTS_IFACE)
|
@dbus.service.method(dbus_interface=PLAYLISTS_IFACE)
|
||||||
|
|||||||
@ -251,3 +251,34 @@ SPOTIFY_PASSWORD = ''
|
|||||||
#:
|
#:
|
||||||
#: SPOTIFY_BITRATE = 160
|
#: SPOTIFY_BITRATE = 160
|
||||||
SPOTIFY_BITRATE = 160
|
SPOTIFY_BITRATE = 160
|
||||||
|
|
||||||
|
#: Spotify proxy host.
|
||||||
|
#:
|
||||||
|
#: Used by :mod:`mopidy.backends.spotify`.
|
||||||
|
#:
|
||||||
|
#: Example::
|
||||||
|
#:
|
||||||
|
#: SPOTIFY_PROXY_HOST = u'protocol://host:port'
|
||||||
|
#:
|
||||||
|
#: Default::
|
||||||
|
#:
|
||||||
|
#: SPOTIFY_PROXY_HOST = None
|
||||||
|
SPOTIFY_PROXY_HOST = None
|
||||||
|
|
||||||
|
#: Spotify proxy username.
|
||||||
|
#:
|
||||||
|
#: Used by :mod:`mopidy.backends.spotify`.
|
||||||
|
#:
|
||||||
|
#: Default::
|
||||||
|
#:
|
||||||
|
#: SPOTIFY_PROXY_USERNAME = None
|
||||||
|
SPOTIFY_PROXY_USERNAME = None
|
||||||
|
|
||||||
|
#: Spotify proxy password.
|
||||||
|
#:
|
||||||
|
#: Used by :mod:`mopidy.backends.spotify`
|
||||||
|
#:
|
||||||
|
#: Default::
|
||||||
|
#:
|
||||||
|
#: SPOTIFY_PROXY_PASSWORD = None
|
||||||
|
SPOTIFY_PROXY_PASSWORD = None
|
||||||
|
|||||||
1
requirements/spotify.txt
Normal file
1
requirements/spotify.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
pyspotify >= 1.9, < 1.10
|
||||||
@ -1,10 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
def populate_playlist(func):
|
def populate_tracklist(func):
|
||||||
def wrapper(self):
|
def wrapper(self):
|
||||||
for track in self.tracks:
|
self.tl_tracks = self.core.tracklist.add(self.tracks)
|
||||||
self.core.tracklist.add(track)
|
|
||||||
return func(self)
|
return func(self)
|
||||||
|
|
||||||
wrapper.__name__ = func.__name__
|
wrapper.__name__ = func.__name__
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from mopidy.core import PlaybackState
|
|||||||
from mopidy.models import Track
|
from mopidy.models import Track
|
||||||
|
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
from tests.backends.base import populate_playlist
|
from tests.backends.base import populate_tracklist
|
||||||
|
|
||||||
# TODO Test 'playlist repeat', e.g. repeat=1,single=0
|
# TODO Test 'playlist repeat', e.g. repeat=1,single=0
|
||||||
|
|
||||||
@ -40,35 +40,35 @@ class PlaybackControllerTest(object):
|
|||||||
def test_play_with_empty_playlist_return_value(self):
|
def test_play_with_empty_playlist_return_value(self):
|
||||||
self.assertEqual(self.playback.play(), None)
|
self.assertEqual(self.playback.play(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_state(self):
|
def test_play_state(self):
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_return_value(self):
|
def test_play_return_value(self):
|
||||||
self.assertEqual(self.playback.play(), None)
|
self.assertEqual(self.playback.play(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_track_state(self):
|
def test_play_track_state(self):
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_track_return_value(self):
|
def test_play_track_return_value(self):
|
||||||
self.assertEqual(self.playback.play(
|
self.assertEqual(self.playback.play(
|
||||||
self.tracklist.tl_tracks[-1]), None)
|
self.tracklist.tl_tracks[-1]), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_when_playing(self):
|
def test_play_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
track = self.playback.current_track
|
track = self.playback.current_track
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(track, self.playback.current_track)
|
self.assertEqual(track, self.playback.current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_when_paused(self):
|
def test_play_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
track = self.playback.current_track
|
track = self.playback.current_track
|
||||||
@ -77,7 +77,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
self.assertEqual(track, self.playback.current_track)
|
self.assertEqual(track, self.playback.current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_when_pause_after_next(self):
|
def test_play_when_pause_after_next(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
@ -88,17 +88,17 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
self.assertEqual(track, self.playback.current_track)
|
self.assertEqual(track, self.playback.current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_sets_current_track(self):
|
def test_play_sets_current_track(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_track_sets_current_track(self):
|
def test_play_track_sets_current_track(self):
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[-1])
|
self.assertEqual(self.playback.current_track, self.tracks[-1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_skips_to_next_track_on_failure(self):
|
def test_play_skips_to_next_track_on_failure(self):
|
||||||
# If backend's play() returns False, it is a failure.
|
# If backend's play() returns False, it is a failure.
|
||||||
self.backend.playback.play = lambda track: track != self.tracks[0]
|
self.backend.playback.play = lambda track: track != self.tracks[0]
|
||||||
@ -106,7 +106,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertNotEqual(self.playback.current_track, self.tracks[0])
|
self.assertNotEqual(self.playback.current_track, self.tracks[0])
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_current_track_after_completed_playlist(self):
|
def test_current_track_after_completed_playlist(self):
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
@ -118,14 +118,14 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.assertEqual(self.playback.current_track, None)
|
self.assertEqual(self.playback.current_track, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous(self):
|
def test_previous(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_more(self):
|
def test_previous_more(self):
|
||||||
self.playback.play() # At track 0
|
self.playback.play() # At track 0
|
||||||
self.playback.next() # At track 1
|
self.playback.next() # At track 1
|
||||||
@ -133,13 +133,13 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.previous() # At track 1
|
self.playback.previous() # At track 1
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_return_value(self):
|
def test_previous_return_value(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.previous(), None)
|
self.assertEqual(self.playback.previous(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_does_not_trigger_playback(self):
|
def test_previous_does_not_trigger_playback(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
@ -147,7 +147,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_at_start_of_playlist(self):
|
def test_previous_at_start_of_playlist(self):
|
||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
@ -158,7 +158,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.assertEqual(self.playback.current_track, None)
|
self.assertEqual(self.playback.current_track, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_skips_to_previous_track_on_failure(self):
|
def test_previous_skips_to_previous_track_on_failure(self):
|
||||||
# If backend's play() returns False, it is a failure.
|
# If backend's play() returns False, it is a failure.
|
||||||
self.backend.playback.play = lambda track: track != self.tracks[1]
|
self.backend.playback.play = lambda track: track != self.tracks[1]
|
||||||
@ -168,7 +168,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next(self):
|
def test_next(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -181,17 +181,17 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.tracklist_position, old_position + 1)
|
self.playback.tracklist_position, old_position + 1)
|
||||||
self.assertNotEqual(self.playback.current_track.uri, old_uri)
|
self.assertNotEqual(self.playback.current_track.uri, old_uri)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_return_value(self):
|
def test_next_return_value(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.next(), None)
|
self.assertEqual(self.playback.next(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_does_not_trigger_playback(self):
|
def test_next_does_not_trigger_playback(self):
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_at_end_of_playlist(self):
|
def test_next_at_end_of_playlist(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ class PlaybackControllerTest(object):
|
|||||||
|
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_until_end_of_playlist_and_play_from_start(self):
|
def test_next_until_end_of_playlist_and_play_from_start(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_skips_to_next_track_on_failure(self):
|
def test_next_skips_to_next_track_on_failure(self):
|
||||||
# If backend's play() returns False, it is a failure.
|
# If backend's play() returns False, it is a failure.
|
||||||
self.backend.playback.play = lambda track: track != self.tracks[1]
|
self.backend.playback.play = lambda track: track != self.tracks[1]
|
||||||
@ -232,54 +232,54 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[2])
|
self.assertEqual(self.playback.current_track, self.tracks[2])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_before_play(self):
|
def test_next_track_before_play(self):
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_during_play(self):
|
def test_next_track_during_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_after_previous(self):
|
def test_next_track_after_previous(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
def test_next_track_empty_playlist(self):
|
def test_next_track_empty_playlist(self):
|
||||||
self.assertEqual(self.playback.track_at_next, None)
|
self.assertEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_at_end_of_playlist(self):
|
def test_next_track_at_end_of_playlist(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracklist.tl_tracks[1:]:
|
for _ in self.tracklist.tl_tracks[1:]:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.track_at_next, None)
|
self.assertEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_at_end_of_playlist_with_repeat(self):
|
def test_next_track_at_end_of_playlist_with_repeat(self):
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracks[1:]:
|
for _ in self.tracks[1:]:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_with_random(self):
|
def test_next_track_with_random(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[2])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_with_consume(self):
|
def test_next_with_consume(self):
|
||||||
self.playback.consume = True
|
self.playback.consume = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertIn(self.tracks[0], self.tracklist.tracks)
|
self.assertIn(self.tracks[0], self.tracklist.tracks)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_with_single_and_repeat(self):
|
def test_next_with_single_and_repeat(self):
|
||||||
self.playback.single = True
|
self.playback.single = True
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
@ -287,7 +287,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_with_random(self):
|
def test_next_with_random(self):
|
||||||
# FIXME feels very fragile
|
# FIXME feels very fragile
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
@ -296,15 +296,15 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_next_track_with_random_after_append_playlist(self):
|
def test_next_track_with_random_after_append_playlist(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[2])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2])
|
||||||
self.tracklist.append(self.tracks[:1])
|
self.tracklist.add(self.tracks[:1])
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track(self):
|
def test_end_of_track(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -317,17 +317,17 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.tracklist_position, old_position + 1)
|
self.playback.tracklist_position, old_position + 1)
|
||||||
self.assertNotEqual(self.playback.current_track.uri, old_uri)
|
self.assertNotEqual(self.playback.current_track.uri, old_uri)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_return_value(self):
|
def test_end_of_track_return_value(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.on_end_of_track(), None)
|
self.assertEqual(self.playback.on_end_of_track(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_does_not_trigger_playback(self):
|
def test_end_of_track_does_not_trigger_playback(self):
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_at_end_of_playlist(self):
|
def test_end_of_track_at_end_of_playlist(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ class PlaybackControllerTest(object):
|
|||||||
|
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_until_end_of_playlist_and_play_from_start(self):
|
def test_end_of_track_until_end_of_playlist_and_play_from_start(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_skips_to_next_track_on_failure(self):
|
def test_end_of_track_skips_to_next_track_on_failure(self):
|
||||||
# If backend's play() returns False, it is a failure.
|
# If backend's play() returns False, it is a failure.
|
||||||
self.backend.playback.play = lambda track: track != self.tracks[1]
|
self.backend.playback.play = lambda track: track != self.tracks[1]
|
||||||
@ -368,54 +368,54 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
self.assertNotEqual(self.playback.current_track, self.tracks[1])
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[2])
|
self.assertEqual(self.playback.current_track, self.tracks[2])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_before_play(self):
|
def test_end_of_track_track_before_play(self):
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_during_play(self):
|
def test_end_of_track_track_during_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_after_previous(self):
|
def test_end_of_track_track_after_previous(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
def test_end_of_track_track_empty_playlist(self):
|
def test_end_of_track_track_empty_playlist(self):
|
||||||
self.assertEqual(self.playback.track_at_next, None)
|
self.assertEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_at_end_of_playlist(self):
|
def test_end_of_track_track_at_end_of_playlist(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracklist.tl_tracks[1:]:
|
for _ in self.tracklist.tl_tracks[1:]:
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.track_at_next, None)
|
self.assertEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_at_end_of_playlist_with_repeat(self):
|
def test_end_of_track_track_at_end_of_playlist_with_repeat(self):
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracks[1:]:
|
for _ in self.tracks[1:]:
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_with_random(self):
|
def test_end_of_track_track_with_random(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[2])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_with_consume(self):
|
def test_end_of_track_with_consume(self):
|
||||||
self.playback.consume = True
|
self.playback.consume = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertNotIn(self.tracks[0], self.tracklist.tracks)
|
self.assertNotIn(self.tracks[0], self.tracklist.tracks)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_with_random(self):
|
def test_end_of_track_with_random(self):
|
||||||
# FIXME feels very fragile
|
# FIXME feels very fragile
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
@ -424,87 +424,89 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_track_with_random_after_append_playlist(self):
|
def test_end_of_track_track_with_random_after_append_playlist(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[2])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[2])
|
||||||
self.tracklist.append(self.tracks[:1])
|
self.tracklist.add(self.tracks[:1])
|
||||||
self.assertEqual(self.playback.track_at_next, self.tracks[1])
|
self.assertEqual(self.playback.tl_track_at_next, self.tl_tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_before_play(self):
|
def test_previous_track_before_play(self):
|
||||||
self.assertEqual(self.playback.track_at_previous, None)
|
self.assertEqual(self.playback.tl_track_at_previous, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_after_play(self):
|
def test_previous_track_after_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.track_at_previous, None)
|
self.assertEqual(self.playback.tl_track_at_previous, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_after_next(self):
|
def test_previous_track_after_next(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.track_at_previous, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_after_previous(self):
|
def test_previous_track_after_previous(self):
|
||||||
self.playback.play() # At track 0
|
self.playback.play() # At track 0
|
||||||
self.playback.next() # At track 1
|
self.playback.next() # At track 1
|
||||||
self.playback.next() # At track 2
|
self.playback.next() # At track 2
|
||||||
self.playback.previous() # At track 1
|
self.playback.previous() # At track 1
|
||||||
self.assertEqual(self.playback.track_at_previous, self.tracks[0])
|
self.assertEqual(self.playback.tl_track_at_previous, self.tl_tracks[0])
|
||||||
|
|
||||||
def test_previous_track_empty_playlist(self):
|
def test_previous_track_empty_playlist(self):
|
||||||
self.assertEqual(self.playback.track_at_previous, None)
|
self.assertEqual(self.playback.tl_track_at_previous, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_with_consume(self):
|
def test_previous_track_with_consume(self):
|
||||||
self.playback.consume = True
|
self.playback.consume = True
|
||||||
for _ in self.tracks:
|
for _ in self.tracks:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.playback.track_at_previous, self.playback.current_track)
|
self.playback.tl_track_at_previous,
|
||||||
|
self.playback.current_tl_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_track_with_random(self):
|
def test_previous_track_with_random(self):
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
for _ in self.tracks:
|
for _ in self.tracks:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.playback.track_at_previous, self.playback.current_track)
|
self.playback.tl_track_at_previous,
|
||||||
|
self.playback.current_tl_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_initial_current_track(self):
|
def test_initial_current_track(self):
|
||||||
self.assertEqual(self.playback.current_track, None)
|
self.assertEqual(self.playback.current_track, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_current_track_during_play(self):
|
def test_current_track_during_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_current_track_after_next(self):
|
def test_current_track_after_next(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_initial_tracklist_position(self):
|
def test_initial_tracklist_position(self):
|
||||||
self.assertEqual(self.playback.tracklist_position, None)
|
self.assertEqual(self.playback.tracklist_position, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_tracklist_position_during_play(self):
|
def test_tracklist_position_during_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.tracklist_position, 0)
|
self.assertEqual(self.playback.tracklist_position, 0)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_tracklist_position_after_next(self):
|
def test_tracklist_position_after_next(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.tracklist_position, 1)
|
self.assertEqual(self.playback.tracklist_position, 1)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_tracklist_position_at_end_of_playlist(self):
|
def test_tracklist_position_at_end_of_playlist(self):
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
@ -519,12 +521,12 @@ class PlaybackControllerTest(object):
|
|||||||
wrapper.called = False
|
wrapper.called = False
|
||||||
|
|
||||||
self.playback.on_tracklist_change = wrapper
|
self.playback.on_tracklist_change = wrapper
|
||||||
self.tracklist.append([Track()])
|
self.tracklist.add([Track()])
|
||||||
|
|
||||||
self.assert_(wrapper.called)
|
self.assert_(wrapper.called)
|
||||||
|
|
||||||
@unittest.SkipTest # Blocks for 10ms
|
@unittest.SkipTest # Blocks for 10ms
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_track_callback_gets_called(self):
|
def test_end_of_track_callback_gets_called(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
result = self.playback.seek(self.tracks[0].length - 10)
|
result = self.playback.seek(self.tracks[0].length - 10)
|
||||||
@ -532,78 +534,78 @@ class PlaybackControllerTest(object):
|
|||||||
message = self.core_queue.get(True, 1)
|
message = self.core_queue.get(True, 1)
|
||||||
self.assertEqual('end_of_track', message['command'])
|
self.assertEqual('end_of_track', message['command'])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_on_tracklist_change_when_playing(self):
|
def test_on_tracklist_change_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
current_track = self.playback.current_track
|
current_track = self.playback.current_track
|
||||||
self.tracklist.append([self.tracks[2]])
|
self.tracklist.add([self.tracks[2]])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
self.assertEqual(self.playback.current_track, current_track)
|
self.assertEqual(self.playback.current_track, current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_on_tracklist_change_when_stopped(self):
|
def test_on_tracklist_change_when_stopped(self):
|
||||||
self.tracklist.append([self.tracks[2]])
|
self.tracklist.add([self.tracks[2]])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.assertEqual(self.playback.current_track, None)
|
self.assertEqual(self.playback.current_track, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_on_tracklist_change_when_paused(self):
|
def test_on_tracklist_change_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
current_track = self.playback.current_track
|
current_track = self.playback.current_track
|
||||||
self.tracklist.append([self.tracks[2]])
|
self.tracklist.add([self.tracks[2]])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
||||||
self.assertEqual(self.playback.current_track, current_track)
|
self.assertEqual(self.playback.current_track, current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_pause_when_stopped(self):
|
def test_pause_when_stopped(self):
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_pause_when_playing(self):
|
def test_pause_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_pause_when_paused(self):
|
def test_pause_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
self.assertEqual(self.playback.state, PlaybackState.PAUSED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_pause_return_value(self):
|
def test_pause_return_value(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.pause(), None)
|
self.assertEqual(self.playback.pause(), None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_resume_when_stopped(self):
|
def test_resume_when_stopped(self):
|
||||||
self.playback.resume()
|
self.playback.resume()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_resume_when_playing(self):
|
def test_resume_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.resume()
|
self.playback.resume()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_resume_when_paused(self):
|
def test_resume_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.playback.resume()
|
self.playback.resume()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_resume_return_value(self):
|
def test_resume_return_value(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
self.assertEqual(self.playback.resume(), None)
|
self.assertEqual(self.playback.resume(), None)
|
||||||
|
|
||||||
@unittest.SkipTest # Uses sleep and might not work with LocalBackend
|
@unittest.SkipTest # Uses sleep and might not work with LocalBackend
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_resume_continues_from_right_position(self):
|
def test_resume_continues_from_right_position(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
@ -611,12 +613,12 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.resume()
|
self.playback.resume()
|
||||||
self.assertNotEqual(self.playback.time_position, 0)
|
self.assertNotEqual(self.playback.time_position, 0)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_stopped(self):
|
def test_seek_when_stopped(self):
|
||||||
result = self.playback.seek(1000)
|
result = self.playback.seek(1000)
|
||||||
self.assert_(result, 'Seek return value was %s' % result)
|
self.assert_(result, 'Seek return value was %s' % result)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_stopped_updates_position(self):
|
def test_seek_when_stopped_updates_position(self):
|
||||||
self.playback.seek(1000)
|
self.playback.seek(1000)
|
||||||
position = self.playback.time_position
|
position = self.playback.time_position
|
||||||
@ -629,18 +631,18 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.seek(0)
|
self.playback.seek(0)
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_stopped_triggers_play(self):
|
def test_seek_when_stopped_triggers_play(self):
|
||||||
self.playback.seek(0)
|
self.playback.seek(0)
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_playing(self):
|
def test_seek_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
result = self.playback.seek(self.tracks[0].length - 1000)
|
result = self.playback.seek(self.tracks[0].length - 1000)
|
||||||
self.assert_(result, 'Seek return value was %s' % result)
|
self.assert_(result, 'Seek return value was %s' % result)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_playing_updates_position(self):
|
def test_seek_when_playing_updates_position(self):
|
||||||
length = self.tracklist.tracks[0].length
|
length = self.tracklist.tracks[0].length
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
@ -648,14 +650,14 @@ class PlaybackControllerTest(object):
|
|||||||
position = self.playback.time_position
|
position = self.playback.time_position
|
||||||
self.assertGreaterEqual(position, length - 1010)
|
self.assertGreaterEqual(position, length - 1010)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_paused(self):
|
def test_seek_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
result = self.playback.seek(self.tracks[0].length - 1000)
|
result = self.playback.seek(self.tracks[0].length - 1000)
|
||||||
self.assert_(result, 'Seek return value was %s' % result)
|
self.assert_(result, 'Seek return value was %s' % result)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_paused_updates_position(self):
|
def test_seek_when_paused_updates_position(self):
|
||||||
length = self.tracklist.tracks[0].length
|
length = self.tracklist.tracks[0].length
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
@ -664,7 +666,7 @@ class PlaybackControllerTest(object):
|
|||||||
position = self.playback.time_position
|
position = self.playback.time_position
|
||||||
self.assertGreaterEqual(position, length - 1010)
|
self.assertGreaterEqual(position, length - 1010)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_when_paused_triggers_play(self):
|
def test_seek_when_paused_triggers_play(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
@ -672,34 +674,34 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@unittest.SkipTest
|
@unittest.SkipTest
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_beyond_end_of_song(self):
|
def test_seek_beyond_end_of_song(self):
|
||||||
# FIXME need to decide return value
|
# FIXME need to decide return value
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
result = self.playback.seek(self.tracks[0].length * 100)
|
result = self.playback.seek(self.tracks[0].length * 100)
|
||||||
self.assert_(not result, 'Seek return value was %s' % result)
|
self.assert_(not result, 'Seek return value was %s' % result)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_beyond_end_of_song_jumps_to_next_song(self):
|
def test_seek_beyond_end_of_song_jumps_to_next_song(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.seek(self.tracks[0].length * 100)
|
self.playback.seek(self.tracks[0].length * 100)
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_beyond_end_of_song_for_last_track(self):
|
def test_seek_beyond_end_of_song_for_last_track(self):
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.playback.seek(self.tracklist.tracks[-1].length * 100)
|
self.playback.seek(self.tracklist.tracks[-1].length * 100)
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@unittest.SkipTest
|
@unittest.SkipTest
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_beyond_start_of_song(self):
|
def test_seek_beyond_start_of_song(self):
|
||||||
# FIXME need to decide return value
|
# FIXME need to decide return value
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
result = self.playback.seek(-1000)
|
result = self.playback.seek(-1000)
|
||||||
self.assert_(not result, 'Seek return value was %s' % result)
|
self.assert_(not result, 'Seek return value was %s' % result)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_seek_beyond_start_of_song_update_postion(self):
|
def test_seek_beyond_start_of_song_update_postion(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.seek(-1000)
|
self.playback.seek(-1000)
|
||||||
@ -707,18 +709,18 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertGreaterEqual(position, 0)
|
self.assertGreaterEqual(position, 0)
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_stop_when_stopped(self):
|
def test_stop_when_stopped(self):
|
||||||
self.playback.stop()
|
self.playback.stop()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_stop_when_playing(self):
|
def test_stop_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.stop()
|
self.playback.stop()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_stop_when_paused(self):
|
def test_stop_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.pause()
|
self.playback.pause()
|
||||||
@ -736,7 +738,7 @@ class PlaybackControllerTest(object):
|
|||||||
|
|
||||||
self.assertEqual(self.playback.time_position, 0)
|
self.assertEqual(self.playback.time_position, 0)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_time_position_when_stopped_with_playlist(self):
|
def test_time_position_when_stopped_with_playlist(self):
|
||||||
future = mock.Mock()
|
future = mock.Mock()
|
||||||
future.get = mock.Mock(return_value=0)
|
future.get = mock.Mock(return_value=0)
|
||||||
@ -745,7 +747,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertEqual(self.playback.time_position, 0)
|
self.assertEqual(self.playback.time_position, 0)
|
||||||
|
|
||||||
@unittest.SkipTest # Uses sleep and does might not work with LocalBackend
|
@unittest.SkipTest # Uses sleep and does might not work with LocalBackend
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_time_position_when_playing(self):
|
def test_time_position_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
first = self.playback.time_position
|
first = self.playback.time_position
|
||||||
@ -754,7 +756,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.assertGreater(second, first)
|
self.assertGreater(second, first)
|
||||||
|
|
||||||
@unittest.SkipTest # Uses sleep
|
@unittest.SkipTest # Uses sleep
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_time_position_when_paused(self):
|
def test_time_position_when_paused(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
@ -764,13 +766,13 @@ class PlaybackControllerTest(object):
|
|||||||
second = self.playback.time_position
|
second = self.playback.time_position
|
||||||
self.assertEqual(first, second)
|
self.assertEqual(first, second)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_with_consume(self):
|
def test_play_with_consume(self):
|
||||||
self.playback.consume = True
|
self.playback.consume = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_playlist_is_empty_after_all_tracks_are_played_with_consume(self):
|
def test_playlist_is_empty_after_all_tracks_are_played_with_consume(self):
|
||||||
self.playback.consume = True
|
self.playback.consume = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
@ -778,14 +780,14 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(len(self.tracklist.tracks), 0)
|
self.assertEqual(len(self.tracklist.tracks), 0)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_play_with_random(self):
|
def test_play_with_random(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[2])
|
self.assertEqual(self.playback.current_track, self.tracks[2])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_previous_with_random(self):
|
def test_previous_with_random(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
@ -795,13 +797,13 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.previous()
|
self.playback.previous()
|
||||||
self.assertEqual(self.playback.current_track, current_track)
|
self.assertEqual(self.playback.current_track, current_track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_song_starts_next_track(self):
|
def test_end_of_song_starts_next_track(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[1])
|
self.assertEqual(self.playback.current_track, self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_song_with_single_and_repeat_starts_same(self):
|
def test_end_of_song_with_single_and_repeat_starts_same(self):
|
||||||
self.playback.single = True
|
self.playback.single = True
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
@ -809,7 +811,7 @@ class PlaybackControllerTest(object):
|
|||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
self.assertEqual(self.playback.current_track, self.tracks[0])
|
self.assertEqual(self.playback.current_track, self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_end_of_playlist_stops(self):
|
def test_end_of_playlist_stops(self):
|
||||||
self.playback.play(self.tracklist.tl_tracks[-1])
|
self.playback.play(self.tracklist.tl_tracks[-1])
|
||||||
self.playback.on_end_of_track()
|
self.playback.on_end_of_track()
|
||||||
@ -824,34 +826,34 @@ class PlaybackControllerTest(object):
|
|||||||
def test_consume_off_by_default(self):
|
def test_consume_off_by_default(self):
|
||||||
self.assertEqual(self.playback.consume, False)
|
self.assertEqual(self.playback.consume, False)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_random_until_end_of_playlist(self):
|
def test_random_until_end_of_playlist(self):
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracks[1:]:
|
for _ in self.tracks[1:]:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertEqual(self.playback.track_at_next, None)
|
self.assertEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_random_until_end_of_playlist_and_play_from_start(self):
|
def test_random_until_end_of_playlist_and_play_from_start(self):
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
for _ in self.tracks:
|
for _ in self.tracks:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertNotEqual(self.playback.track_at_next, None)
|
self.assertNotEqual(self.playback.tl_track_at_next, None)
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_random_until_end_of_playlist_with_repeat(self):
|
def test_random_until_end_of_playlist_with_repeat(self):
|
||||||
self.playback.repeat = True
|
self.playback.repeat = True
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
for _ in self.tracks:
|
for _ in self.tracks:
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
self.assertNotEqual(self.playback.track_at_next, None)
|
self.assertNotEqual(self.playback.tl_track_at_next, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_played_track_during_random_not_played_again(self):
|
def test_played_track_during_random_not_played_again(self):
|
||||||
self.playback.random = True
|
self.playback.random = True
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
@ -861,7 +863,7 @@ class PlaybackControllerTest(object):
|
|||||||
played.append(self.playback.current_track)
|
played.append(self.playback.current_track)
|
||||||
self.playback.next()
|
self.playback.next()
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_playing_track_that_isnt_in_playlist(self):
|
def test_playing_track_that_isnt_in_playlist(self):
|
||||||
test = lambda: self.playback.play((17, Track()))
|
test = lambda: self.playback.play((17, Track()))
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from mopidy import audio, core
|
|||||||
from mopidy.core import PlaybackState
|
from mopidy.core import PlaybackState
|
||||||
from mopidy.models import TlTrack, Playlist, Track
|
from mopidy.models import TlTrack, Playlist, Track
|
||||||
|
|
||||||
from tests.backends.base import populate_playlist
|
from tests.backends.base import populate_tracklist
|
||||||
|
|
||||||
|
|
||||||
class TracklistControllerTest(object):
|
class TracklistControllerTest(object):
|
||||||
@ -30,54 +30,56 @@ class TracklistControllerTest(object):
|
|||||||
def test_length(self):
|
def test_length(self):
|
||||||
self.assertEqual(0, len(self.controller.tl_tracks))
|
self.assertEqual(0, len(self.controller.tl_tracks))
|
||||||
self.assertEqual(0, self.controller.length)
|
self.assertEqual(0, self.controller.length)
|
||||||
self.controller.append(self.tracks)
|
self.controller.add(self.tracks)
|
||||||
self.assertEqual(3, len(self.controller.tl_tracks))
|
self.assertEqual(3, len(self.controller.tl_tracks))
|
||||||
self.assertEqual(3, self.controller.length)
|
self.assertEqual(3, self.controller.length)
|
||||||
|
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
for track in self.tracks:
|
for track in self.tracks:
|
||||||
tl_track = self.controller.add(track)
|
tl_tracks = self.controller.add([track])
|
||||||
self.assertEqual(track, self.controller.tracks[-1])
|
self.assertEqual(track, self.controller.tracks[-1])
|
||||||
self.assertEqual(tl_track, self.controller.tl_tracks[-1])
|
self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1])
|
||||||
self.assertEqual(track, tl_track.track)
|
self.assertEqual(track, tl_tracks[0].track)
|
||||||
|
|
||||||
def test_add_at_position(self):
|
def test_add_at_position(self):
|
||||||
for track in self.tracks[:-1]:
|
for track in self.tracks[:-1]:
|
||||||
tl_track = self.controller.add(track, 0)
|
tl_tracks = self.controller.add([track], 0)
|
||||||
self.assertEqual(track, self.controller.tracks[0])
|
self.assertEqual(track, self.controller.tracks[0])
|
||||||
self.assertEqual(tl_track, self.controller.tl_tracks[0])
|
self.assertEqual(tl_tracks[0], self.controller.tl_tracks[0])
|
||||||
self.assertEqual(track, tl_track.track)
|
self.assertEqual(track, tl_tracks[0].track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_add_at_position_outside_of_playlist(self):
|
def test_add_at_position_outside_of_playlist(self):
|
||||||
test = lambda: self.controller.add(
|
for track in self.tracks:
|
||||||
self.tracks[0], len(self.tracks) + 2)
|
tl_tracks = self.controller.add([track], len(self.tracks) + 2)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertEqual(track, self.controller.tracks[-1])
|
||||||
|
self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1])
|
||||||
|
self.assertEqual(track, tl_tracks[0].track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_filter_by_tlid(self):
|
def test_filter_by_tlid(self):
|
||||||
tl_track = self.controller.tl_tracks[1]
|
tl_track = self.controller.tl_tracks[1]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[tl_track], self.controller.filter(tlid=tl_track.tlid))
|
[tl_track], self.controller.filter(tlid=tl_track.tlid))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_filter_by_uri(self):
|
def test_filter_by_uri(self):
|
||||||
tl_track = self.controller.tl_tracks[1]
|
tl_track = self.controller.tl_tracks[1]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[tl_track], self.controller.filter(uri=tl_track.track.uri))
|
[tl_track], self.controller.filter(uri=tl_track.track.uri))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_filter_by_uri_returns_nothing_for_invalid_uri(self):
|
def test_filter_by_uri_returns_nothing_for_invalid_uri(self):
|
||||||
self.assertEqual([], self.controller.filter(uri='foobar'))
|
self.assertEqual([], self.controller.filter(uri='foobar'))
|
||||||
|
|
||||||
def test_filter_by_uri_returns_single_match(self):
|
def test_filter_by_uri_returns_single_match(self):
|
||||||
track = Track(uri='a')
|
track = Track(uri='a')
|
||||||
self.controller.append([Track(uri='z'), track, Track(uri='y')])
|
self.controller.add([Track(uri='z'), track, Track(uri='y')])
|
||||||
self.assertEqual(track, self.controller.filter(uri='a')[0].track)
|
self.assertEqual(track, self.controller.filter(uri='a')[0].track)
|
||||||
|
|
||||||
def test_filter_by_uri_returns_multiple_matches(self):
|
def test_filter_by_uri_returns_multiple_matches(self):
|
||||||
track = Track(uri='a')
|
track = Track(uri='a')
|
||||||
self.controller.append([Track(uri='z'), track, track])
|
self.controller.add([Track(uri='z'), track, track])
|
||||||
tl_tracks = self.controller.filter(uri='a')
|
tl_tracks = self.controller.filter(uri='a')
|
||||||
self.assertEqual(track, tl_tracks[0].track)
|
self.assertEqual(track, tl_tracks[0].track)
|
||||||
self.assertEqual(track, tl_tracks[1].track)
|
self.assertEqual(track, tl_tracks[1].track)
|
||||||
@ -91,7 +93,7 @@ class TracklistControllerTest(object):
|
|||||||
track1 = Track(uri='a', name='x')
|
track1 = Track(uri='a', name='x')
|
||||||
track2 = Track(uri='b', name='x')
|
track2 = Track(uri='b', name='x')
|
||||||
track3 = Track(uri='b', name='y')
|
track3 = Track(uri='b', name='y')
|
||||||
self.controller.append([track1, track2, track3])
|
self.controller.add([track1, track2, track3])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
track1, self.controller.filter(uri='a', name='x')[0].track)
|
track1, self.controller.filter(uri='a', name='x')[0].track)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -103,10 +105,10 @@ class TracklistControllerTest(object):
|
|||||||
track1 = Track()
|
track1 = Track()
|
||||||
track2 = Track(uri='b')
|
track2 = Track(uri='b')
|
||||||
track3 = Track()
|
track3 = Track()
|
||||||
self.controller.append([track1, track2, track3])
|
self.controller.add([track1, track2, track3])
|
||||||
self.assertEqual(track2, self.controller.filter(uri='b')[0].track)
|
self.assertEqual(track2, self.controller.filter(uri='b')[0].track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
self.controller.clear()
|
self.controller.clear()
|
||||||
self.assertEqual(len(self.controller.tracks), 0)
|
self.assertEqual(len(self.controller.tracks), 0)
|
||||||
@ -115,49 +117,49 @@ class TracklistControllerTest(object):
|
|||||||
self.controller.clear()
|
self.controller.clear()
|
||||||
self.assertEqual(len(self.controller.tracks), 0)
|
self.assertEqual(len(self.controller.tracks), 0)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_clear_when_playing(self):
|
def test_clear_when_playing(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
self.controller.clear()
|
self.controller.clear()
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
|
|
||||||
def test_append_appends_to_the_tracklist(self):
|
def test_add_appends_to_the_tracklist(self):
|
||||||
self.controller.append([Track(uri='a'), Track(uri='b')])
|
self.controller.add([Track(uri='a'), Track(uri='b')])
|
||||||
self.assertEqual(len(self.controller.tracks), 2)
|
self.assertEqual(len(self.controller.tracks), 2)
|
||||||
self.controller.append([Track(uri='c'), Track(uri='d')])
|
self.controller.add([Track(uri='c'), Track(uri='d')])
|
||||||
self.assertEqual(len(self.controller.tracks), 4)
|
self.assertEqual(len(self.controller.tracks), 4)
|
||||||
self.assertEqual(self.controller.tracks[0].uri, 'a')
|
self.assertEqual(self.controller.tracks[0].uri, 'a')
|
||||||
self.assertEqual(self.controller.tracks[1].uri, 'b')
|
self.assertEqual(self.controller.tracks[1].uri, 'b')
|
||||||
self.assertEqual(self.controller.tracks[2].uri, 'c')
|
self.assertEqual(self.controller.tracks[2].uri, 'c')
|
||||||
self.assertEqual(self.controller.tracks[3].uri, 'd')
|
self.assertEqual(self.controller.tracks[3].uri, 'd')
|
||||||
|
|
||||||
def test_append_does_not_reset_version(self):
|
def test_add_does_not_reset_version(self):
|
||||||
version = self.controller.version
|
version = self.controller.version
|
||||||
self.controller.append([])
|
self.controller.add([])
|
||||||
self.assertEqual(self.controller.version, version)
|
self.assertEqual(self.controller.version, version)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_append_preserves_playing_state(self):
|
def test_add_preserves_playing_state(self):
|
||||||
self.playback.play()
|
self.playback.play()
|
||||||
track = self.playback.current_track
|
track = self.playback.current_track
|
||||||
self.controller.append(self.controller.tracks[1:2])
|
self.controller.add(self.controller.tracks[1:2])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
self.assertEqual(self.playback.state, PlaybackState.PLAYING)
|
||||||
self.assertEqual(self.playback.current_track, track)
|
self.assertEqual(self.playback.current_track, track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_append_preserves_stopped_state(self):
|
def test_add_preserves_stopped_state(self):
|
||||||
self.controller.append(self.controller.tracks[1:2])
|
self.controller.add(self.controller.tracks[1:2])
|
||||||
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
self.assertEqual(self.playback.state, PlaybackState.STOPPED)
|
||||||
self.assertEqual(self.playback.current_track, None)
|
self.assertEqual(self.playback.current_track, None)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_append_returns_the_tl_tracks_that_was_added(self):
|
def test_add_returns_the_tl_tracks_that_was_added(self):
|
||||||
tl_tracks = self.controller.append(self.controller.tracks[1:2])
|
tl_tracks = self.controller.add(self.controller.tracks[1:2])
|
||||||
self.assertEqual(tl_tracks[0].track, self.controller.tracks[1])
|
self.assertEqual(tl_tracks[0].track, self.controller.tracks[1])
|
||||||
|
|
||||||
def test_index_returns_index_of_track(self):
|
def test_index_returns_index_of_track(self):
|
||||||
tl_tracks = self.controller.append(self.tracks)
|
tl_tracks = self.controller.add(self.tracks)
|
||||||
self.assertEquals(0, self.controller.index(tl_tracks[0]))
|
self.assertEquals(0, self.controller.index(tl_tracks[0]))
|
||||||
self.assertEquals(1, self.controller.index(tl_tracks[1]))
|
self.assertEquals(1, self.controller.index(tl_tracks[1]))
|
||||||
self.assertEquals(2, self.controller.index(tl_tracks[2]))
|
self.assertEquals(2, self.controller.index(tl_tracks[2]))
|
||||||
@ -166,14 +168,14 @@ class TracklistControllerTest(object):
|
|||||||
test = lambda: self.controller.index(TlTrack(0, Track()))
|
test = lambda: self.controller.index(TlTrack(0, Track()))
|
||||||
self.assertRaises(ValueError, test)
|
self.assertRaises(ValueError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_move_single(self):
|
def test_move_single(self):
|
||||||
self.controller.move(0, 0, 2)
|
self.controller.move(0, 0, 2)
|
||||||
|
|
||||||
tracks = self.controller.tracks
|
tracks = self.controller.tracks
|
||||||
self.assertEqual(tracks[2], self.tracks[0])
|
self.assertEqual(tracks[2], self.tracks[0])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_move_group(self):
|
def test_move_group(self):
|
||||||
self.controller.move(0, 2, 1)
|
self.controller.move(0, 2, 1)
|
||||||
|
|
||||||
@ -181,25 +183,25 @@ class TracklistControllerTest(object):
|
|||||||
self.assertEqual(tracks[1], self.tracks[0])
|
self.assertEqual(tracks[1], self.tracks[0])
|
||||||
self.assertEqual(tracks[2], self.tracks[1])
|
self.assertEqual(tracks[2], self.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_moving_track_outside_of_playlist(self):
|
def test_moving_track_outside_of_playlist(self):
|
||||||
tracks = len(self.controller.tracks)
|
tracks = len(self.controller.tracks)
|
||||||
test = lambda: self.controller.move(0, 0, tracks + 5)
|
test = lambda: self.controller.move(0, 0, tracks + 5)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_move_group_outside_of_playlist(self):
|
def test_move_group_outside_of_playlist(self):
|
||||||
tracks = len(self.controller.tracks)
|
tracks = len(self.controller.tracks)
|
||||||
test = lambda: self.controller.move(0, 2, tracks + 5)
|
test = lambda: self.controller.move(0, 2, tracks + 5)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_move_group_out_of_range(self):
|
def test_move_group_out_of_range(self):
|
||||||
tracks = len(self.controller.tracks)
|
tracks = len(self.controller.tracks)
|
||||||
test = lambda: self.controller.move(tracks + 2, tracks + 3, 0)
|
test = lambda: self.controller.move(tracks + 2, tracks + 3, 0)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_move_group_invalid_group(self):
|
def test_move_group_invalid_group(self):
|
||||||
test = lambda: self.controller.move(2, 1, 0)
|
test = lambda: self.controller.move(2, 1, 0)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
@ -209,7 +211,7 @@ class TracklistControllerTest(object):
|
|||||||
tracks2 = self.controller.tracks
|
tracks2 = self.controller.tracks
|
||||||
self.assertNotEqual(id(tracks1), id(tracks2))
|
self.assertNotEqual(id(tracks1), id(tracks2))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_remove(self):
|
def test_remove(self):
|
||||||
track1 = self.controller.tracks[1]
|
track1 = self.controller.tracks[1]
|
||||||
track2 = self.controller.tracks[2]
|
track2 = self.controller.tracks[2]
|
||||||
@ -219,14 +221,14 @@ class TracklistControllerTest(object):
|
|||||||
self.assertNotIn(track1, self.controller.tracks)
|
self.assertNotIn(track1, self.controller.tracks)
|
||||||
self.assertEqual(track2, self.controller.tracks[1])
|
self.assertEqual(track2, self.controller.tracks[1])
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_removing_track_that_does_not_exist_does_nothing(self):
|
def test_removing_track_that_does_not_exist_does_nothing(self):
|
||||||
self.controller.remove(uri='/nonexistant')
|
self.controller.remove(uri='/nonexistant')
|
||||||
|
|
||||||
def test_removing_from_empty_playlist_does_nothing(self):
|
def test_removing_from_empty_playlist_does_nothing(self):
|
||||||
self.controller.remove(uri='/nonexistant')
|
self.controller.remove(uri='/nonexistant')
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_shuffle(self):
|
def test_shuffle(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.controller.shuffle()
|
self.controller.shuffle()
|
||||||
@ -236,7 +238,7 @@ class TracklistControllerTest(object):
|
|||||||
self.assertNotEqual(self.tracks, shuffled_tracks)
|
self.assertNotEqual(self.tracks, shuffled_tracks)
|
||||||
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_shuffle_subset(self):
|
def test_shuffle_subset(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.controller.shuffle(1, 3)
|
self.controller.shuffle(1, 3)
|
||||||
@ -247,18 +249,18 @@ class TracklistControllerTest(object):
|
|||||||
self.assertEqual(self.tracks[0], shuffled_tracks[0])
|
self.assertEqual(self.tracks[0], shuffled_tracks[0])
|
||||||
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_shuffle_invalid_subset(self):
|
def test_shuffle_invalid_subset(self):
|
||||||
test = lambda: self.controller.shuffle(3, 1)
|
test = lambda: self.controller.shuffle(3, 1)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_shuffle_superset(self):
|
def test_shuffle_superset(self):
|
||||||
tracks = len(self.controller.tracks)
|
tracks = len(self.controller.tracks)
|
||||||
test = lambda: self.controller.shuffle(1, tracks + 5)
|
test = lambda: self.controller.shuffle(1, tracks + 5)
|
||||||
self.assertRaises(AssertionError, test)
|
self.assertRaises(AssertionError, test)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_shuffle_open_subset(self):
|
def test_shuffle_open_subset(self):
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
self.controller.shuffle(1)
|
self.controller.shuffle(1)
|
||||||
@ -269,24 +271,24 @@ class TracklistControllerTest(object):
|
|||||||
self.assertEqual(self.tracks[0], shuffled_tracks[0])
|
self.assertEqual(self.tracks[0], shuffled_tracks[0])
|
||||||
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
self.assertEqual(set(self.tracks), set(shuffled_tracks))
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_slice_returns_a_subset_of_tracks(self):
|
def test_slice_returns_a_subset_of_tracks(self):
|
||||||
track_slice = self.controller.slice(1, 3)
|
track_slice = self.controller.slice(1, 3)
|
||||||
self.assertEqual(2, len(track_slice))
|
self.assertEqual(2, len(track_slice))
|
||||||
self.assertEqual(self.tracks[1], track_slice[0].track)
|
self.assertEqual(self.tracks[1], track_slice[0].track)
|
||||||
self.assertEqual(self.tracks[2], track_slice[1].track)
|
self.assertEqual(self.tracks[2], track_slice[1].track)
|
||||||
|
|
||||||
@populate_playlist
|
@populate_tracklist
|
||||||
def test_slice_returns_empty_list_if_indexes_outside_tracks_list(self):
|
def test_slice_returns_empty_list_if_indexes_outside_tracks_list(self):
|
||||||
self.assertEqual(0, len(self.controller.slice(7, 8)))
|
self.assertEqual(0, len(self.controller.slice(7, 8)))
|
||||||
self.assertEqual(0, len(self.controller.slice(-1, 1)))
|
self.assertEqual(0, len(self.controller.slice(-1, 1)))
|
||||||
|
|
||||||
def test_version_does_not_change_when_appending_nothing(self):
|
def test_version_does_not_change_when_adding_nothing(self):
|
||||||
version = self.controller.version
|
version = self.controller.version
|
||||||
self.controller.append([])
|
self.controller.add([])
|
||||||
self.assertEquals(version, self.controller.version)
|
self.assertEquals(version, self.controller.version)
|
||||||
|
|
||||||
def test_version_increases_when_appending_something(self):
|
def test_version_increases_when_adding_something(self):
|
||||||
version = self.controller.version
|
version = self.controller.version
|
||||||
self.controller.append([Track()])
|
self.controller.add([Track()])
|
||||||
self.assertLess(version, self.controller.version)
|
self.assertLess(version, self.controller.version)
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class LocalPlaybackControllerTest(PlaybackControllerTest, unittest.TestCase):
|
|||||||
def add_track(self, path):
|
def add_track(self, path):
|
||||||
uri = path_to_uri(path_to_data_dir(path))
|
uri = path_to_uri(path_to_data_dir(path))
|
||||||
track = Track(uri=uri, length=4464)
|
track = Track(uri=uri, length=4464)
|
||||||
self.tracklist.add(track)
|
self.tracklist.add([track])
|
||||||
|
|
||||||
def test_uri_scheme(self):
|
def test_uri_scheme(self):
|
||||||
self.assertIn('file', self.core.uri_schemes)
|
self.assertIn('file', self.core.uri_schemes)
|
||||||
|
|||||||
@ -26,14 +26,14 @@ class BackendEventsTest(unittest.TestCase):
|
|||||||
self.assertEqual(send.call_args[0][0], 'playlists_loaded')
|
self.assertEqual(send.call_args[0][0], 'playlists_loaded')
|
||||||
|
|
||||||
def test_pause_sends_track_playback_paused_event(self, send):
|
def test_pause_sends_track_playback_paused_event(self, send):
|
||||||
self.core.tracklist.add(Track(uri='dummy:a'))
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play().get()
|
self.core.playback.play().get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.playback.pause().get()
|
self.core.playback.pause().get()
|
||||||
self.assertEqual(send.call_args[0][0], 'track_playback_paused')
|
self.assertEqual(send.call_args[0][0], 'track_playback_paused')
|
||||||
|
|
||||||
def test_resume_sends_track_playback_resumed(self, send):
|
def test_resume_sends_track_playback_resumed(self, send):
|
||||||
self.core.tracklist.add(Track(uri='dummy:a'))
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause().get()
|
self.core.playback.pause().get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
@ -41,20 +41,20 @@ class BackendEventsTest(unittest.TestCase):
|
|||||||
self.assertEqual(send.call_args[0][0], 'track_playback_resumed')
|
self.assertEqual(send.call_args[0][0], 'track_playback_resumed')
|
||||||
|
|
||||||
def test_play_sends_track_playback_started_event(self, send):
|
def test_play_sends_track_playback_started_event(self, send):
|
||||||
self.core.tracklist.add(Track(uri='dummy:a'))
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.playback.play().get()
|
self.core.playback.play().get()
|
||||||
self.assertEqual(send.call_args[0][0], 'track_playback_started')
|
self.assertEqual(send.call_args[0][0], 'track_playback_started')
|
||||||
|
|
||||||
def test_stop_sends_track_playback_ended_event(self, send):
|
def test_stop_sends_track_playback_ended_event(self, send):
|
||||||
self.core.tracklist.add(Track(uri='dummy:a'))
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play().get()
|
self.core.playback.play().get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.playback.stop().get()
|
self.core.playback.stop().get()
|
||||||
self.assertEqual(send.call_args_list[0][0][0], 'track_playback_ended')
|
self.assertEqual(send.call_args_list[0][0][0], 'track_playback_ended')
|
||||||
|
|
||||||
def test_seek_sends_seeked_event(self, send):
|
def test_seek_sends_seeked_event(self, send):
|
||||||
self.core.tracklist.add(Track(uri='dummy:a', length=40000))
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play().get()
|
self.core.playback.play().get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.playback.seek(1000).get()
|
self.core.playback.seek(1000).get()
|
||||||
@ -62,35 +62,30 @@ class BackendEventsTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_tracklist_add_sends_tracklist_changed_event(self, send):
|
def test_tracklist_add_sends_tracklist_changed_event(self, send):
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.tracklist.add(Track(uri='dummy:a')).get()
|
self.core.tracklist.add([Track(uri='dummy:a')]).get()
|
||||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
|
||||||
|
|
||||||
def test_tracklist_append_sends_tracklist_changed_event(self, send):
|
|
||||||
send.reset_mock()
|
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')]).get()
|
|
||||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||||
|
|
||||||
def test_tracklist_clear_sends_tracklist_changed_event(self, send):
|
def test_tracklist_clear_sends_tracklist_changed_event(self, send):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')]).get()
|
self.core.tracklist.add([Track(uri='dummy:a')]).get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.tracklist.clear().get()
|
self.core.tracklist.clear().get()
|
||||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||||
|
|
||||||
def test_tracklist_move_sends_tracklist_changed_event(self, send):
|
def test_tracklist_move_sends_tracklist_changed_event(self, send):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(uri='dummy:a'), Track(uri='dummy:b')]).get()
|
[Track(uri='dummy:a'), Track(uri='dummy:b')]).get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.tracklist.move(0, 1, 1).get()
|
self.core.tracklist.move(0, 1, 1).get()
|
||||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||||
|
|
||||||
def test_tracklist_remove_sends_tracklist_changed_event(self, send):
|
def test_tracklist_remove_sends_tracklist_changed_event(self, send):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')]).get()
|
self.core.tracklist.add([Track(uri='dummy:a')]).get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.tracklist.remove(uri='dummy:a').get()
|
self.core.tracklist.remove(uri='dummy:a').get()
|
||||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||||
|
|
||||||
def test_tracklist_shuffle_sends_tracklist_changed_event(self, send):
|
def test_tracklist_shuffle_sends_tracklist_changed_event(self, send):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(uri='dummy:a'), Track(uri='dummy:b')]).get()
|
[Track(uri='dummy:a'), Track(uri='dummy:b')]).get()
|
||||||
send.reset_mock()
|
send.reset_mock()
|
||||||
self.core.tracklist.shuffle().get()
|
self.core.tracklist.shuffle().get()
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class CorePlaybackTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.core = Core(audio=None, backends=[
|
self.core = Core(audio=None, backends=[
|
||||||
self.backend1, self.backend2, self.backend3])
|
self.backend1, self.backend2, self.backend3])
|
||||||
self.core.tracklist.append(self.tracks)
|
self.core.tracklist.add(self.tracks)
|
||||||
|
|
||||||
self.tl_tracks = self.core.tracklist.tl_tracks
|
self.tl_tracks = self.core.tracklist.tl_tracks
|
||||||
self.unplayable_tl_track = self.tl_tracks[2]
|
self.unplayable_tl_track = self.tl_tracks[2]
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
needle = Track(uri='dummy://foo')
|
needle = Track(uri='dummy://foo')
|
||||||
self.backend.library.dummy_library = [
|
self.backend.library.dummy_library = [
|
||||||
Track(), Track(), needle, Track()]
|
Track(), Track(), needle, Track()]
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
needle = Track(uri='dummy://foo')
|
needle = Track(uri='dummy://foo')
|
||||||
self.backend.library.dummy_library = [
|
self.backend.library.dummy_library = [
|
||||||
Track(), Track(), needle, Track()]
|
Track(), Track(), needle, Track()]
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
needle = Track(uri='dummy://foo')
|
needle = Track(uri='dummy://foo')
|
||||||
self.backend.library.dummy_library = [
|
self.backend.library.dummy_library = [
|
||||||
Track(), Track(), needle, Track()]
|
Track(), Track(), needle, Track()]
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
needle = Track(uri='dummy://foo')
|
needle = Track(uri='dummy://foo')
|
||||||
self.backend.library.dummy_library = [
|
self.backend.library.dummy_library = [
|
||||||
Track(), Track(), needle, Track()]
|
Track(), Track(), needle, Track()]
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [50@0] {addid} No such song')
|
self.assertEqualResponse('ACK [50@0] {addid} No such song')
|
||||||
|
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_delete_songpos(self):
|
def test_delete_songpos(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_delete_songpos_out_of_bounds(self):
|
def test_delete_songpos_out_of_bounds(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [2@0] {delete} Bad song index')
|
self.assertEqualResponse('ACK [2@0] {delete} Bad song index')
|
||||||
|
|
||||||
def test_delete_open_range(self):
|
def test_delete_open_range(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_delete_closed_range(self):
|
def test_delete_closed_range(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_delete_range_out_of_bounds(self):
|
def test_delete_range_out_of_bounds(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(), Track(), Track(), Track(), Track()])
|
[Track(), Track(), Track(), Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 5)
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [2@0] {delete} Bad song index')
|
self.assertEqualResponse('ACK [2@0] {delete} Bad song index')
|
||||||
|
|
||||||
def test_deleteid(self):
|
def test_deleteid(self):
|
||||||
self.core.tracklist.append([Track(), Track()])
|
self.core.tracklist.add([Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
||||||
|
|
||||||
self.sendRequest('deleteid "1"')
|
self.sendRequest('deleteid "1"')
|
||||||
@ -143,7 +143,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_deleteid_does_not_exist(self):
|
def test_deleteid_does_not_exist(self):
|
||||||
self.core.tracklist.append([Track(), Track()])
|
self.core.tracklist.add([Track(), Track()])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
||||||
|
|
||||||
self.sendRequest('deleteid "12345"')
|
self.sendRequest('deleteid "12345"')
|
||||||
@ -151,7 +151,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [50@0] {deleteid} No such song')
|
self.assertEqualResponse('ACK [50@0] {deleteid} No such song')
|
||||||
|
|
||||||
def test_move_songpos(self):
|
def test_move_songpos(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -167,7 +167,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_move_open_range(self):
|
def test_move_open_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -183,7 +183,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_move_closed_range(self):
|
def test_move_closed_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -199,7 +199,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_moveid(self):
|
def test_moveid(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -237,8 +237,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('OK')
|
self.assertEqualResponse('OK')
|
||||||
|
|
||||||
def test_playlistfind_by_filename_in_tracklist(self):
|
def test_playlistfind_by_filename_in_tracklist(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='file:///exists')])
|
||||||
Track(uri='file:///exists')])
|
|
||||||
|
|
||||||
self.sendRequest('playlistfind filename "file:///exists"')
|
self.sendRequest('playlistfind filename "file:///exists"')
|
||||||
self.assertInResponse('file: file:///exists')
|
self.assertInResponse('file: file:///exists')
|
||||||
@ -247,7 +246,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playlistid_without_songid(self):
|
def test_playlistid_without_songid(self):
|
||||||
self.core.tracklist.append([Track(name='a'), Track(name='b')])
|
self.core.tracklist.add([Track(name='a'), Track(name='b')])
|
||||||
|
|
||||||
self.sendRequest('playlistid')
|
self.sendRequest('playlistid')
|
||||||
self.assertInResponse('Title: a')
|
self.assertInResponse('Title: a')
|
||||||
@ -255,7 +254,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playlistid_with_songid(self):
|
def test_playlistid_with_songid(self):
|
||||||
self.core.tracklist.append([Track(name='a'), Track(name='b')])
|
self.core.tracklist.add([Track(name='a'), Track(name='b')])
|
||||||
|
|
||||||
self.sendRequest('playlistid "1"')
|
self.sendRequest('playlistid "1"')
|
||||||
self.assertNotInResponse('Title: a')
|
self.assertNotInResponse('Title: a')
|
||||||
@ -265,13 +264,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playlistid_with_not_existing_songid_fails(self):
|
def test_playlistid_with_not_existing_songid_fails(self):
|
||||||
self.core.tracklist.append([Track(name='a'), Track(name='b')])
|
self.core.tracklist.add([Track(name='a'), Track(name='b')])
|
||||||
|
|
||||||
self.sendRequest('playlistid "25"')
|
self.sendRequest('playlistid "25"')
|
||||||
self.assertEqualResponse('ACK [50@0] {playlistid} No such song')
|
self.assertEqualResponse('ACK [50@0] {playlistid} No such song')
|
||||||
|
|
||||||
def test_playlistinfo_without_songpos_or_range(self):
|
def test_playlistinfo_without_songpos_or_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -294,7 +293,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
def test_playlistinfo_with_songpos(self):
|
def test_playlistinfo_with_songpos(self):
|
||||||
# Make the track's CPID not match the playlist position
|
# Make the track's CPID not match the playlist position
|
||||||
self.core.tracklist.tlid = 17
|
self.core.tracklist.tlid = 17
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -320,7 +319,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqual(response1, response2)
|
self.assertEqual(response1, response2)
|
||||||
|
|
||||||
def test_playlistinfo_with_open_range(self):
|
def test_playlistinfo_with_open_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -341,7 +340,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playlistinfo_with_closed_range(self):
|
def test_playlistinfo_with_closed_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -372,7 +371,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [0@0] {} Not implemented')
|
self.assertEqualResponse('ACK [0@0] {} Not implemented')
|
||||||
|
|
||||||
def test_plchanges_with_lower_version_returns_changes(self):
|
def test_plchanges_with_lower_version_returns_changes(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||||
|
|
||||||
self.sendRequest('plchanges "0"')
|
self.sendRequest('plchanges "0"')
|
||||||
@ -382,7 +381,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_plchanges_with_equal_version_returns_nothing(self):
|
def test_plchanges_with_equal_version_returns_nothing(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||||
|
|
||||||
self.assertEqual(self.core.tracklist.version.get(), 1)
|
self.assertEqual(self.core.tracklist.version.get(), 1)
|
||||||
@ -393,7 +392,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_plchanges_with_greater_version_returns_nothing(self):
|
def test_plchanges_with_greater_version_returns_nothing(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||||
|
|
||||||
self.assertEqual(self.core.tracklist.version.get(), 1)
|
self.assertEqual(self.core.tracklist.version.get(), 1)
|
||||||
@ -404,7 +403,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_plchanges_with_minus_one_returns_entire_playlist(self):
|
def test_plchanges_with_minus_one_returns_entire_playlist(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||||
|
|
||||||
self.sendRequest('plchanges "-1"')
|
self.sendRequest('plchanges "-1"')
|
||||||
@ -414,7 +413,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_plchanges_without_quotes_works(self):
|
def test_plchanges_without_quotes_works(self):
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(name='a'), Track(name='b'), Track(name='c')])
|
[Track(name='a'), Track(name='b'), Track(name='c')])
|
||||||
|
|
||||||
self.sendRequest('plchanges 0')
|
self.sendRequest('plchanges 0')
|
||||||
@ -424,7 +423,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_plchangesposid(self):
|
def test_plchangesposid(self):
|
||||||
self.core.tracklist.append([Track(), Track(), Track()])
|
self.core.tracklist.add([Track(), Track(), Track()])
|
||||||
|
|
||||||
self.sendRequest('plchangesposid "0"')
|
self.sendRequest('plchangesposid "0"')
|
||||||
tl_tracks = self.core.tracklist.tl_tracks.get()
|
tl_tracks = self.core.tracklist.tl_tracks.get()
|
||||||
@ -437,7 +436,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_shuffle_without_range(self):
|
def test_shuffle_without_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -448,7 +447,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_shuffle_with_open_range(self):
|
def test_shuffle_with_open_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -464,7 +463,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_shuffle_with_closed_range(self):
|
def test_shuffle_with_closed_range(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -480,7 +479,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_swap(self):
|
def test_swap(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -496,7 +495,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_swapid(self):
|
def test_swapid(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(name='a'), Track(name='b'), Track(name='c'),
|
Track(name='a'), Track(name='b'), Track(name='c'),
|
||||||
Track(name='d'), Track(name='e'), Track(name='f'),
|
Track(name='d'), Track(name='e'), Track(name='f'),
|
||||||
])
|
])
|
||||||
@ -512,13 +511,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_swapid_with_first_id_unknown_should_ack(self):
|
def test_swapid_with_first_id_unknown_should_ack(self):
|
||||||
self.core.tracklist.append([Track()])
|
self.core.tracklist.add([Track()])
|
||||||
self.sendRequest('swapid "0" "4"')
|
self.sendRequest('swapid "0" "4"')
|
||||||
self.assertEqualResponse(
|
self.assertEqualResponse(
|
||||||
'ACK [50@0] {swapid} No such song')
|
'ACK [50@0] {swapid} No such song')
|
||||||
|
|
||||||
def test_swapid_with_second_id_unknown_should_ack(self):
|
def test_swapid_with_second_id_unknown_should_ack(self):
|
||||||
self.core.tracklist.append([Track()])
|
self.core.tracklist.add([Track()])
|
||||||
self.sendRequest('swapid "4" "0"')
|
self.sendRequest('swapid "4" "0"')
|
||||||
self.assertEqualResponse(
|
self.assertEqualResponse(
|
||||||
'ACK [50@0] {swapid} No such song')
|
'ACK [50@0] {swapid} No such song')
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from mopidy.models import Album, Artist, Track
|
||||||
|
|
||||||
from tests.frontends.mpd import protocol
|
from tests.frontends.mpd import protocol
|
||||||
|
|
||||||
|
|
||||||
@ -119,6 +121,10 @@ class MusicDatabaseFindTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('find album "album_what" artist "artist_what"')
|
self.sendRequest('find album "album_what" artist "artist_what"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_find_without_filter_value(self):
|
||||||
|
self.sendRequest('find "album" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
|
||||||
class MusicDatabaseListTest(protocol.BaseTestCase):
|
class MusicDatabaseListTest(protocol.BaseTestCase):
|
||||||
def test_list_foo_returns_ack(self):
|
def test_list_foo_returns_ack(self):
|
||||||
@ -173,6 +179,18 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
|
|||||||
'list "artist" "artist" "anartist" "album" "analbum"')
|
'list "artist" "artist" "anartist" "album" "analbum"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_artist_without_filter_value(self):
|
||||||
|
self.sendRequest('list "artist" "artist" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_artist_should_not_return_artists_without_names(self):
|
||||||
|
self.backend.library.dummy_find_exact_result = [
|
||||||
|
Track(artists=[Artist(name='')])]
|
||||||
|
|
||||||
|
self.sendRequest('list "artist"')
|
||||||
|
self.assertNotInResponse('Artist: ')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
### Album
|
### Album
|
||||||
|
|
||||||
def test_list_album_with_quotes(self):
|
def test_list_album_with_quotes(self):
|
||||||
@ -191,6 +209,10 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('list "album" "anartist"')
|
self.sendRequest('list "album" "anartist"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_album_with_artist_name_without_filter_value(self):
|
||||||
|
self.sendRequest('list "album" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_list_album_by_artist(self):
|
def test_list_album_by_artist(self):
|
||||||
self.sendRequest('list "album" "artist" "anartist"')
|
self.sendRequest('list "album" "artist" "anartist"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -216,6 +238,18 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
|
|||||||
'list "album" "artist" "anartist" "album" "analbum"')
|
'list "album" "artist" "anartist" "album" "analbum"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_album_without_filter_value(self):
|
||||||
|
self.sendRequest('list "album" "artist" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_album_should_not_return_albums_without_names(self):
|
||||||
|
self.backend.library.dummy_find_exact_result = [
|
||||||
|
Track(album=Album(name=''))]
|
||||||
|
|
||||||
|
self.sendRequest('list "album"')
|
||||||
|
self.assertNotInResponse('Album: ')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
### Date
|
### Date
|
||||||
|
|
||||||
def test_list_date_with_quotes(self):
|
def test_list_date_with_quotes(self):
|
||||||
@ -259,6 +293,17 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('list "date" "artist" "anartist" "album" "analbum"')
|
self.sendRequest('list "date" "artist" "anartist" "album" "analbum"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_date_without_filter_value(self):
|
||||||
|
self.sendRequest('list "date" "artist" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_date_should_not_return_blank_dates(self):
|
||||||
|
self.backend.library.dummy_find_exact_result = [Track(date='')]
|
||||||
|
|
||||||
|
self.sendRequest('list "date"')
|
||||||
|
self.assertNotInResponse('Date: ')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
### Genre
|
### Genre
|
||||||
|
|
||||||
def test_list_genre_with_quotes(self):
|
def test_list_genre_with_quotes(self):
|
||||||
@ -303,6 +348,10 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
|
|||||||
'list "genre" "artist" "anartist" "album" "analbum"')
|
'list "genre" "artist" "anartist" "album" "analbum"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_list_genre_without_filter_value(self):
|
||||||
|
self.sendRequest('list "genre" "artist" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
|
||||||
class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
||||||
def test_search_album(self):
|
def test_search_album(self):
|
||||||
@ -313,6 +362,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search album "analbum"')
|
self.sendRequest('search album "analbum"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_album_without_filter_value(self):
|
||||||
|
self.sendRequest('search "album" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_artist(self):
|
def test_search_artist(self):
|
||||||
self.sendRequest('search "artist" "anartist"')
|
self.sendRequest('search "artist" "anartist"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -321,6 +374,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search artist "anartist"')
|
self.sendRequest('search artist "anartist"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_artist_without_filter_value(self):
|
||||||
|
self.sendRequest('search "artist" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_filename(self):
|
def test_search_filename(self):
|
||||||
self.sendRequest('search "filename" "afilename"')
|
self.sendRequest('search "filename" "afilename"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -329,6 +386,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search filename "afilename"')
|
self.sendRequest('search filename "afilename"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_filename_without_filter_value(self):
|
||||||
|
self.sendRequest('search "filename" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_file(self):
|
def test_search_file(self):
|
||||||
self.sendRequest('search "file" "afilename"')
|
self.sendRequest('search "file" "afilename"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -337,6 +398,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search file "afilename"')
|
self.sendRequest('search file "afilename"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_file_without_filter_value(self):
|
||||||
|
self.sendRequest('search "file" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_title(self):
|
def test_search_title(self):
|
||||||
self.sendRequest('search "title" "atitle"')
|
self.sendRequest('search "title" "atitle"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -345,6 +410,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search title "atitle"')
|
self.sendRequest('search title "atitle"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_title_without_filter_value(self):
|
||||||
|
self.sendRequest('search "title" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_any(self):
|
def test_search_any(self):
|
||||||
self.sendRequest('search "any" "anything"')
|
self.sendRequest('search "any" "anything"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -353,6 +422,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search any "anything"')
|
self.sendRequest('search any "anything"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_any_without_filter_value(self):
|
||||||
|
self.sendRequest('search "any" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_date(self):
|
def test_search_date(self):
|
||||||
self.sendRequest('search "date" "2002-01-01"')
|
self.sendRequest('search "date" "2002-01-01"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -365,6 +438,10 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase):
|
|||||||
self.sendRequest('search Date "2005"')
|
self.sendRequest('search Date "2005"')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_search_date_without_filter_value(self):
|
||||||
|
self.sendRequest('search "date" ""')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_search_else_should_fail(self):
|
def test_search_else_should_fail(self):
|
||||||
self.sendRequest('search "sometype" "something"')
|
self.sendRequest('search "sometype" "something"')
|
||||||
self.assertEqualResponse('ACK [2@0] {search} incorrect arguments')
|
self.assertEqualResponse('ACK [2@0] {search} incorrect arguments')
|
||||||
|
|||||||
@ -168,7 +168,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_pause_off(self):
|
def test_pause_off(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play "0"')
|
self.sendRequest('play "0"')
|
||||||
self.sendRequest('pause "1"')
|
self.sendRequest('pause "1"')
|
||||||
@ -177,7 +177,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_pause_on(self):
|
def test_pause_on(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play "0"')
|
self.sendRequest('play "0"')
|
||||||
self.sendRequest('pause "1"')
|
self.sendRequest('pause "1"')
|
||||||
@ -185,7 +185,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_pause_toggle(self):
|
def test_pause_toggle(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play "0"')
|
self.sendRequest('play "0"')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
@ -200,28 +200,28 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_without_pos(self):
|
def test_play_without_pos(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play')
|
self.sendRequest('play')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_with_pos(self):
|
def test_play_with_pos(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play "0"')
|
self.sendRequest('play "0"')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_with_pos_without_quotes(self):
|
def test_play_with_pos_without_quotes(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('play 0')
|
self.sendRequest('play 0')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_with_pos_out_of_bounds(self):
|
def test_play_with_pos_out_of_bounds(self):
|
||||||
self.core.tracklist.append([])
|
self.core.tracklist.add([])
|
||||||
|
|
||||||
self.sendRequest('play "0"')
|
self.sendRequest('play "0"')
|
||||||
self.assertEqual(STOPPED, self.core.playback.state.get())
|
self.assertEqual(STOPPED, self.core.playback.state.get())
|
||||||
@ -229,10 +229,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_play_minus_one_plays_first_in_playlist_if_no_current_track(self):
|
def test_play_minus_one_plays_first_in_playlist_if_no_current_track(self):
|
||||||
self.assertEqual(self.core.playback.current_track.get(), None)
|
self.assertEqual(self.core.playback.current_track.get(), None)
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'),
|
|
||||||
Track(uri='dummy:b'),
|
|
||||||
])
|
|
||||||
|
|
||||||
self.sendRequest('play "-1"')
|
self.sendRequest('play "-1"')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
@ -241,10 +238,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_minus_one_plays_current_track_if_current_track_is_set(self):
|
def test_play_minus_one_plays_current_track_if_current_track_is_set(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'),
|
|
||||||
Track(uri='dummy:b'),
|
|
||||||
])
|
|
||||||
self.assertEqual(self.core.playback.current_track.get(), None)
|
self.assertEqual(self.core.playback.current_track.get(), None)
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
@ -266,8 +260,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_minus_is_ignored_if_playing(self):
|
def test_play_minus_is_ignored_if_playing(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
Track(uri='dummy:a', length=40000)])
|
|
||||||
self.core.playback.seek(30000)
|
self.core.playback.seek(30000)
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
self.core.playback.time_position.get(), 30000)
|
self.core.playback.time_position.get(), 30000)
|
||||||
@ -280,8 +273,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_play_minus_one_resumes_if_paused(self):
|
def test_play_minus_one_resumes_if_paused(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
Track(uri='dummy:a', length=40000)])
|
|
||||||
self.core.playback.seek(30000)
|
self.core.playback.seek(30000)
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
self.core.playback.time_position.get(), 30000)
|
self.core.playback.time_position.get(), 30000)
|
||||||
@ -296,14 +288,14 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid(self):
|
def test_playid(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('playid "0"')
|
self.sendRequest('playid "0"')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid_without_quotes(self):
|
def test_playid_without_quotes(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('playid 0')
|
self.sendRequest('playid 0')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
@ -311,10 +303,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_playid_minus_1_plays_first_in_playlist_if_no_current_track(self):
|
def test_playid_minus_1_plays_first_in_playlist_if_no_current_track(self):
|
||||||
self.assertEqual(self.core.playback.current_track.get(), None)
|
self.assertEqual(self.core.playback.current_track.get(), None)
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'),
|
|
||||||
Track(uri='dummy:b'),
|
|
||||||
])
|
|
||||||
|
|
||||||
self.sendRequest('playid "-1"')
|
self.sendRequest('playid "-1"')
|
||||||
self.assertEqual(PLAYING, self.core.playback.state.get())
|
self.assertEqual(PLAYING, self.core.playback.state.get())
|
||||||
@ -323,10 +312,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid_minus_1_plays_current_track_if_current_track_is_set(self):
|
def test_playid_minus_1_plays_current_track_if_current_track_is_set(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'),
|
|
||||||
Track(uri='dummy:b'),
|
|
||||||
])
|
|
||||||
self.assertEqual(self.core.playback.current_track.get(), None)
|
self.assertEqual(self.core.playback.current_track.get(), None)
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
@ -348,7 +334,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid_minus_is_ignored_if_playing(self):
|
def test_playid_minus_is_ignored_if_playing(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.seek(30000)
|
self.core.playback.seek(30000)
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
self.core.playback.time_position.get(), 30000)
|
self.core.playback.time_position.get(), 30000)
|
||||||
@ -361,7 +347,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid_minus_one_resumes_if_paused(self):
|
def test_playid_minus_one_resumes_if_paused(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.seek(30000)
|
self.core.playback.seek(30000)
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
self.core.playback.time_position.get(), 30000)
|
self.core.playback.time_position.get(), 30000)
|
||||||
@ -376,7 +362,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_playid_which_does_not_exist(self):
|
def test_playid_which_does_not_exist(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
|
|
||||||
self.sendRequest('playid "12345"')
|
self.sendRequest('playid "12345"')
|
||||||
self.assertInResponse('ACK [50@0] {playid} No such song')
|
self.assertInResponse('ACK [50@0] {playid} No such song')
|
||||||
@ -386,7 +372,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_seek(self):
|
def test_seek(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
|
|
||||||
self.sendRequest('seek "0"')
|
self.sendRequest('seek "0"')
|
||||||
self.sendRequest('seek "0" "30"')
|
self.sendRequest('seek "0" "30"')
|
||||||
@ -395,7 +381,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_seek_with_songpos(self):
|
def test_seek_with_songpos(self):
|
||||||
seek_track = Track(uri='dummy:b', length=40000)
|
seek_track = Track(uri='dummy:b', length=40000)
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(uri='dummy:a', length=40000), seek_track])
|
[Track(uri='dummy:a', length=40000), seek_track])
|
||||||
|
|
||||||
self.sendRequest('seek "1" "30"')
|
self.sendRequest('seek "1" "30"')
|
||||||
@ -403,7 +389,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_seek_without_quotes(self):
|
def test_seek_without_quotes(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
|
|
||||||
self.sendRequest('seek 0')
|
self.sendRequest('seek 0')
|
||||||
self.sendRequest('seek 0 30')
|
self.sendRequest('seek 0 30')
|
||||||
@ -412,7 +398,7 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_seekid(self):
|
def test_seekid(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.sendRequest('seekid "0" "30"')
|
self.sendRequest('seekid "0" "30"')
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
self.core.playback.time_position.get(), 30000)
|
self.core.playback.time_position.get(), 30000)
|
||||||
@ -420,11 +406,11 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_seekid_with_tlid(self):
|
def test_seekid_with_tlid(self):
|
||||||
seek_track = Track(uri='dummy:b', length=40000)
|
seek_track = Track(uri='dummy:b', length=40000)
|
||||||
self.core.tracklist.append(
|
self.core.tracklist.add(
|
||||||
[Track(uri='dummy:a', length=40000), seek_track])
|
[Track(uri='dummy:a', length=40000), seek_track])
|
||||||
|
|
||||||
self.sendRequest('seekid "1" "30"')
|
self.sendRequest('seekid "1" "30"')
|
||||||
self.assertEqual(1, self.core.playback.current_tlid.get())
|
self.assertEqual(1, self.core.playback.current_tl_track.get().tlid)
|
||||||
self.assertEqual(seek_track, self.core.playback.current_track.get())
|
self.assertEqual(seek_track, self.core.playback.current_track.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class ReflectionHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_decoders(self):
|
def test_decoders(self):
|
||||||
self.sendRequest('decoders')
|
self.sendRequest('decoders')
|
||||||
self.assertInResponse('ACK [0@0] {} Not implemented')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_notcommands_returns_only_kill_and_ok(self):
|
def test_notcommands_returns_only_kill_and_ok(self):
|
||||||
response = self.sendRequest('notcommands')
|
response = self.sendRequest('notcommands')
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class IssueGH17RegressionTest(protocol.BaseTestCase):
|
|||||||
- Press next until you get to the unplayable track
|
- Press next until you get to the unplayable track
|
||||||
"""
|
"""
|
||||||
def test(self):
|
def test(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:a'),
|
Track(uri='dummy:a'),
|
||||||
Track(uri='dummy:b'),
|
Track(uri='dummy:b'),
|
||||||
Track(uri='dummy:error'),
|
Track(uri='dummy:error'),
|
||||||
@ -59,7 +59,7 @@ class IssueGH18RegressionTest(protocol.BaseTestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
||||||
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
@ -95,7 +95,7 @@ class IssueGH22RegressionTest(protocol.BaseTestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
||||||
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
||||||
random.seed(1)
|
random.seed(1)
|
||||||
@ -124,7 +124,7 @@ class IssueGH69RegressionTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
self.core.playlists.create('foo')
|
self.core.playlists.create('foo')
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
Track(uri='dummy:a'), Track(uri='dummy:b'), Track(uri='dummy:c'),
|
||||||
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
Track(uri='dummy:d'), Track(uri='dummy:e'), Track(uri='dummy:f')])
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class StatusHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_currentsong(self):
|
def test_currentsong(self):
|
||||||
track = Track()
|
track = Track()
|
||||||
self.core.tracklist.append([track])
|
self.core.tracklist.add([track])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.sendRequest('currentsong')
|
self.sendRequest('currentsong')
|
||||||
self.assertInResponse('file: ')
|
self.assertInResponse('file: ')
|
||||||
|
|||||||
@ -10,18 +10,18 @@ from tests.frontends.mpd import protocol
|
|||||||
class PlaylistsHandlerTest(protocol.BaseTestCase):
|
class PlaylistsHandlerTest(protocol.BaseTestCase):
|
||||||
def test_listplaylist(self):
|
def test_listplaylist(self):
|
||||||
self.backend.playlists.playlists = [
|
self.backend.playlists.playlists = [
|
||||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
Playlist(name='name', tracks=[Track(uri='dummy:a')])]
|
||||||
|
|
||||||
self.sendRequest('listplaylist "name"')
|
self.sendRequest('listplaylist "name"')
|
||||||
self.assertInResponse('file: file:///dev/urandom')
|
self.assertInResponse('file: dummy:a')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_listplaylist_without_quotes(self):
|
def test_listplaylist_without_quotes(self):
|
||||||
self.backend.playlists.playlists = [
|
self.backend.playlists.playlists = [
|
||||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
Playlist(name='name', tracks=[Track(uri='dummy:a')])]
|
||||||
|
|
||||||
self.sendRequest('listplaylist name')
|
self.sendRequest('listplaylist name')
|
||||||
self.assertInResponse('file: file:///dev/urandom')
|
self.assertInResponse('file: dummy:a')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_listplaylist_fails_if_no_playlist_is_found(self):
|
def test_listplaylist_fails_if_no_playlist_is_found(self):
|
||||||
@ -30,20 +30,20 @@ class PlaylistsHandlerTest(protocol.BaseTestCase):
|
|||||||
|
|
||||||
def test_listplaylistinfo(self):
|
def test_listplaylistinfo(self):
|
||||||
self.backend.playlists.playlists = [
|
self.backend.playlists.playlists = [
|
||||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
Playlist(name='name', tracks=[Track(uri='dummy:a')])]
|
||||||
|
|
||||||
self.sendRequest('listplaylistinfo "name"')
|
self.sendRequest('listplaylistinfo "name"')
|
||||||
self.assertInResponse('file: file:///dev/urandom')
|
self.assertInResponse('file: dummy:a')
|
||||||
self.assertInResponse('Track: 0')
|
self.assertInResponse('Track: 0')
|
||||||
self.assertNotInResponse('Pos: 0')
|
self.assertNotInResponse('Pos: 0')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_listplaylistinfo_without_quotes(self):
|
def test_listplaylistinfo_without_quotes(self):
|
||||||
self.backend.playlists.playlists = [
|
self.backend.playlists.playlists = [
|
||||||
Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])]
|
Playlist(name='name', tracks=[Track(uri='dummy:a')])]
|
||||||
|
|
||||||
self.sendRequest('listplaylistinfo name')
|
self.sendRequest('listplaylistinfo name')
|
||||||
self.assertInResponse('file: file:///dev/urandom')
|
self.assertInResponse('file: dummy:a')
|
||||||
self.assertInResponse('Track: 0')
|
self.assertInResponse('Track: 0')
|
||||||
self.assertNotInResponse('Pos: 0')
|
self.assertNotInResponse('Pos: 0')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
@ -64,8 +64,17 @@ class PlaylistsHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('Last-Modified: 2001-03-17T13:41:17Z')
|
self.assertInResponse('Last-Modified: 2001-03-17T13:41:17Z')
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_listplaylists_ignores_playlists_without_name(self):
|
||||||
|
last_modified = datetime.datetime(2001, 3, 17, 13, 41, 17, 12345)
|
||||||
|
self.backend.playlists.playlists = [
|
||||||
|
Playlist(name='', last_modified=last_modified)]
|
||||||
|
|
||||||
|
self.sendRequest('listplaylists')
|
||||||
|
self.assertNotInResponse('playlist: ')
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_load_known_playlist_appends_to_tracklist(self):
|
def test_load_known_playlist_appends_to_tracklist(self):
|
||||||
self.core.tracklist.append([Track(uri='a'), Track(uri='b')])
|
self.core.tracklist.add([Track(uri='a'), Track(uri='b')])
|
||||||
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
self.assertEqual(len(self.core.tracklist.tracks.get()), 2)
|
||||||
self.backend.playlists.playlists = [
|
self.backend.playlists.playlists = [
|
||||||
Playlist(name='A-list', tracks=[
|
Playlist(name='A-list', tracks=[
|
||||||
@ -87,7 +96,7 @@ class PlaylistsHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertEqualResponse('ACK [50@0] {load} No such playlist')
|
self.assertEqualResponse('ACK [50@0] {load} No such playlist')
|
||||||
|
|
||||||
def test_playlistadd(self):
|
def test_playlistadd(self):
|
||||||
self.sendRequest('playlistadd "name" "file:///dev/urandom"')
|
self.sendRequest('playlistadd "name" "dummy:a"')
|
||||||
self.assertEqualResponse('ACK [0@0] {} Not implemented')
|
self.assertEqualResponse('ACK [0@0] {} Not implemented')
|
||||||
|
|
||||||
def test_playlistclear(self):
|
def test_playlistclear(self):
|
||||||
|
|||||||
@ -131,21 +131,21 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['state'], 'pause')
|
self.assertEqual(result['state'], 'pause')
|
||||||
|
|
||||||
def test_status_method_when_playlist_loaded_contains_song(self):
|
def test_status_method_when_playlist_loaded_contains_song(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
self.assertIn('song', result)
|
self.assertIn('song', result)
|
||||||
self.assertGreaterEqual(int(result['song']), 0)
|
self.assertGreaterEqual(int(result['song']), 0)
|
||||||
|
|
||||||
def test_status_method_when_playlist_loaded_contains_tlid_as_songid(self):
|
def test_status_method_when_playlist_loaded_contains_tlid_as_songid(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
self.assertIn('songid', result)
|
self.assertIn('songid', result)
|
||||||
self.assertEqual(int(result['songid']), 0)
|
self.assertEqual(int(result['songid']), 0)
|
||||||
|
|
||||||
def test_status_method_when_playing_contains_time_with_no_length(self):
|
def test_status_method_when_playing_contains_time_with_no_length(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=None)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=None)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
self.assertIn('time', result)
|
self.assertIn('time', result)
|
||||||
@ -155,7 +155,7 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assertLessEqual(position, total)
|
self.assertLessEqual(position, total)
|
||||||
|
|
||||||
def test_status_method_when_playing_contains_time_with_length(self):
|
def test_status_method_when_playing_contains_time_with_length(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=10000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=10000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
self.assertIn('time', result)
|
self.assertIn('time', result)
|
||||||
@ -165,7 +165,7 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assertLessEqual(position, total)
|
self.assertLessEqual(position, total)
|
||||||
|
|
||||||
def test_status_method_when_playing_contains_elapsed(self):
|
def test_status_method_when_playing_contains_elapsed(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=60000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=60000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
self.core.playback.seek(59123)
|
self.core.playback.seek(59123)
|
||||||
@ -174,7 +174,7 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['elapsed'], '59.123')
|
self.assertEqual(result['elapsed'], '59.123')
|
||||||
|
|
||||||
def test_status_method_when_starting_playing_contains_elapsed_zero(self):
|
def test_status_method_when_starting_playing_contains_elapsed_zero(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=10000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=10000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
@ -182,7 +182,7 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['elapsed'], '0.000')
|
self.assertEqual(result['elapsed'], '0.000')
|
||||||
|
|
||||||
def test_status_method_when_playing_contains_bitrate(self):
|
def test_status_method_when_playing_contains_bitrate(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', bitrate=320)])
|
self.core.tracklist.add([Track(uri='dummy:a', bitrate=320)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = dict(status.status(self.context))
|
result = dict(status.status(self.context))
|
||||||
self.assertIn('bitrate', result)
|
self.assertIn('bitrate', result)
|
||||||
|
|||||||
@ -101,16 +101,14 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_set_rate_is_ignored_if_can_control_is_false(self):
|
def test_set_rate_is_ignored_if_can_control_is_false(self):
|
||||||
self.mpris.get_CanControl = lambda *_: False
|
self.mpris.get_CanControl = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0)
|
self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0)
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_set_rate_to_zero_pauses_playback(self):
|
def test_set_rate_to_zero_pauses_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0)
|
self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0)
|
||||||
@ -150,7 +148,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['mpris:trackid'], '')
|
self.assertEqual(result['mpris:trackid'], '')
|
||||||
|
|
||||||
def test_get_metadata_has_trackid_based_on_tlid(self):
|
def test_get_metadata_has_trackid_based_on_tlid(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
(tlid, track) = self.core.playback.current_tl_track.get()
|
(tlid, track) = self.core.playback.current_tl_track.get()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
@ -159,28 +157,28 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
result['mpris:trackid'], '/com/mopidy/track/%d' % tlid)
|
result['mpris:trackid'], '/com/mopidy/track/%d' % tlid)
|
||||||
|
|
||||||
def test_get_metadata_has_track_length(self):
|
def test_get_metadata_has_track_length(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
self.assertIn('mpris:length', result.keys())
|
self.assertIn('mpris:length', result.keys())
|
||||||
self.assertEqual(result['mpris:length'], 40000000)
|
self.assertEqual(result['mpris:length'], 40000000)
|
||||||
|
|
||||||
def test_get_metadata_has_track_uri(self):
|
def test_get_metadata_has_track_uri(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
self.assertIn('xesam:url', result.keys())
|
self.assertIn('xesam:url', result.keys())
|
||||||
self.assertEqual(result['xesam:url'], 'dummy:a')
|
self.assertEqual(result['xesam:url'], 'dummy:a')
|
||||||
|
|
||||||
def test_get_metadata_has_track_title(self):
|
def test_get_metadata_has_track_title(self):
|
||||||
self.core.tracklist.append([Track(name='a')])
|
self.core.tracklist.add([Track(name='a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
self.assertIn('xesam:title', result.keys())
|
self.assertIn('xesam:title', result.keys())
|
||||||
self.assertEqual(result['xesam:title'], 'a')
|
self.assertEqual(result['xesam:title'], 'a')
|
||||||
|
|
||||||
def test_get_metadata_has_track_artists(self):
|
def test_get_metadata_has_track_artists(self):
|
||||||
self.core.tracklist.append([Track(artists=[
|
self.core.tracklist.add([Track(artists=[
|
||||||
Artist(name='a'), Artist(name='b'), Artist(name=None)])])
|
Artist(name='a'), Artist(name='b'), Artist(name=None)])])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
@ -188,14 +186,14 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['xesam:artist'], ['a', 'b'])
|
self.assertEqual(result['xesam:artist'], ['a', 'b'])
|
||||||
|
|
||||||
def test_get_metadata_has_track_album(self):
|
def test_get_metadata_has_track_album(self):
|
||||||
self.core.tracklist.append([Track(album=Album(name='a'))])
|
self.core.tracklist.add([Track(album=Album(name='a'))])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
self.assertIn('xesam:album', result.keys())
|
self.assertIn('xesam:album', result.keys())
|
||||||
self.assertEqual(result['xesam:album'], 'a')
|
self.assertEqual(result['xesam:album'], 'a')
|
||||||
|
|
||||||
def test_get_metadata_has_track_album_artists(self):
|
def test_get_metadata_has_track_album_artists(self):
|
||||||
self.core.tracklist.append([Track(album=Album(artists=[
|
self.core.tracklist.add([Track(album=Album(artists=[
|
||||||
Artist(name='a'), Artist(name='b'), Artist(name=None)]))])
|
Artist(name='a'), Artist(name='b'), Artist(name=None)]))])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
@ -203,7 +201,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(result['xesam:albumArtist'], ['a', 'b'])
|
self.assertEqual(result['xesam:albumArtist'], ['a', 'b'])
|
||||||
|
|
||||||
def test_get_metadata_has_track_number_in_album(self):
|
def test_get_metadata_has_track_number_in_album(self):
|
||||||
self.core.tracklist.append([Track(track_no=7)])
|
self.core.tracklist.add([Track(track_no=7)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata')
|
||||||
self.assertIn('xesam:trackNumber', result.keys())
|
self.assertIn('xesam:trackNumber', result.keys())
|
||||||
@ -246,7 +244,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.volume.get(), 10)
|
self.assertEqual(self.core.playback.volume.get(), 10)
|
||||||
|
|
||||||
def test_get_position_returns_time_position_in_microseconds(self):
|
def test_get_position_returns_time_position_in_microseconds(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(10000)
|
self.core.playback.seek(10000)
|
||||||
result_in_microseconds = self.mpris.Get(
|
result_in_microseconds = self.mpris.Get(
|
||||||
@ -270,15 +268,14 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_can_go_next_is_true_if_can_control_and_other_next_track(self):
|
def test_can_go_next_is_true_if_can_control_and_other_next_track(self):
|
||||||
self.mpris.get_CanControl = lambda *_: True
|
self.mpris.get_CanControl = lambda *_: True
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
def test_can_go_next_is_false_if_next_track_is_the_same(self):
|
def test_can_go_next_is_false_if_next_track_is_the_same(self):
|
||||||
self.mpris.get_CanControl = lambda *_: True
|
self.mpris.get_CanControl = lambda *_: True
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.repeat = True
|
self.core.playback.repeat = True
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
||||||
@ -286,16 +283,14 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_can_go_next_is_false_if_can_control_is_false(self):
|
def test_can_go_next_is_false_if_can_control_is_false(self):
|
||||||
self.mpris.get_CanControl = lambda *_: False
|
self.mpris.get_CanControl = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext')
|
||||||
self.assertFalse(result)
|
self.assertFalse(result)
|
||||||
|
|
||||||
def test_can_go_previous_is_true_if_can_control_and_previous_track(self):
|
def test_can_go_previous_is_true_if_can_control_and_previous_track(self):
|
||||||
self.mpris.get_CanControl = lambda *_: True
|
self.mpris.get_CanControl = lambda *_: True
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
||||||
@ -303,7 +298,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_can_go_previous_is_false_if_previous_track_is_the_same(self):
|
def test_can_go_previous_is_false_if_previous_track_is_the_same(self):
|
||||||
self.mpris.get_CanControl = lambda *_: True
|
self.mpris.get_CanControl = lambda *_: True
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.repeat = True
|
self.core.playback.repeat = True
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
||||||
@ -311,8 +306,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_can_go_previous_is_false_if_can_control_is_false(self):
|
def test_can_go_previous_is_false_if_can_control_is_false(self):
|
||||||
self.mpris.get_CanControl = lambda *_: False
|
self.mpris.get_CanControl = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious')
|
||||||
@ -320,7 +314,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_can_play_is_true_if_can_control_and_current_track(self):
|
def test_can_play_is_true_if_can_control_and_current_track(self):
|
||||||
self.mpris.get_CanControl = lambda *_: True
|
self.mpris.get_CanControl = lambda *_: True
|
||||||
self.core.tracklist.append([Track(uri='dummy:a')])
|
self.core.tracklist.add([Track(uri='dummy:a')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertTrue(self.core.playback.current_track.get())
|
self.assertTrue(self.core.playback.current_track.get())
|
||||||
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanPlay')
|
result = self.mpris.Get(objects.PLAYER_IFACE, 'CanPlay')
|
||||||
@ -363,16 +357,14 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_next_is_ignored_if_can_go_next_is_false(self):
|
def test_next_is_ignored_if_can_go_next_is_false(self):
|
||||||
self.mpris.get_CanGoNext = lambda *_: False
|
self.mpris.get_CanGoNext = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
self.mpris.Next()
|
self.mpris.Next()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
|
|
||||||
def test_next_when_playing_skips_to_next_track_and_keep_playing(self):
|
def test_next_when_playing_skips_to_next_track_and_keep_playing(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
@ -381,8 +373,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_next_when_at_end_of_list_should_stop_playback(self):
|
def test_next_when_at_end_of_list_should_stop_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
||||||
@ -391,8 +382,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
|
|
||||||
def test_next_when_paused_should_skip_to_next_track_and_stay_paused(self):
|
def test_next_when_paused_should_skip_to_next_track_and_stay_paused(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
@ -402,8 +392,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
|
|
||||||
def test_next_when_stopped_skips_to_next_track_and_stay_stopped(self):
|
def test_next_when_stopped_skips_to_next_track_and_stay_stopped(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.stop()
|
self.core.playback.stop()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
@ -414,8 +403,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_previous_is_ignored_if_can_go_previous_is_false(self):
|
def test_previous_is_ignored_if_can_go_previous_is_false(self):
|
||||||
self.mpris.get_CanGoPrevious = lambda *_: False
|
self.mpris.get_CanGoPrevious = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
||||||
@ -423,8 +411,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
||||||
|
|
||||||
def test_previous_when_playing_skips_to_prev_track_and_keep_playing(self):
|
def test_previous_when_playing_skips_to_prev_track_and_keep_playing(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:b')
|
||||||
@ -434,8 +421,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_previous_when_at_start_of_list_should_stop_playback(self):
|
def test_previous_when_at_start_of_list_should_stop_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
@ -443,8 +429,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
|
|
||||||
def test_previous_when_paused_skips_to_previous_track_and_pause(self):
|
def test_previous_when_paused_skips_to_previous_track_and_pause(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
@ -455,8 +440,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
|
|
||||||
def test_previous_when_stopped_skips_to_previous_track_and_stops(self):
|
def test_previous_when_stopped_skips_to_previous_track_and_stops(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.next()
|
self.core.playback.next()
|
||||||
self.core.playback.stop()
|
self.core.playback.stop()
|
||||||
@ -468,24 +452,21 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_pause_is_ignored_if_can_pause_is_false(self):
|
def test_pause_is_ignored_if_can_pause_is_false(self):
|
||||||
self.mpris.get_CanPause = lambda *_: False
|
self.mpris.get_CanPause = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Pause()
|
self.mpris.Pause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_pause_when_playing_should_pause_playback(self):
|
def test_pause_when_playing_should_pause_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Pause()
|
self.mpris.Pause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
|
|
||||||
def test_pause_when_paused_has_no_effect(self):
|
def test_pause_when_paused_has_no_effect(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
@ -494,24 +475,21 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_playpause_is_ignored_if_can_pause_is_false(self):
|
def test_playpause_is_ignored_if_can_pause_is_false(self):
|
||||||
self.mpris.get_CanPause = lambda *_: False
|
self.mpris.get_CanPause = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.PlayPause()
|
self.mpris.PlayPause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_playpause_when_playing_should_pause_playback(self):
|
def test_playpause_when_playing_should_pause_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.PlayPause()
|
self.mpris.PlayPause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
|
|
||||||
def test_playpause_when_paused_should_resume_playback(self):
|
def test_playpause_when_paused_should_resume_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
|
|
||||||
@ -526,32 +504,28 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(after_pause, at_pause)
|
self.assertGreaterEqual(after_pause, at_pause)
|
||||||
|
|
||||||
def test_playpause_when_stopped_should_start_playback(self):
|
def test_playpause_when_stopped_should_start_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
self.mpris.PlayPause()
|
self.mpris.PlayPause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_stop_is_ignored_if_can_control_is_false(self):
|
def test_stop_is_ignored_if_can_control_is_false(self):
|
||||||
self.mpris.get_CanControl = lambda *_: False
|
self.mpris.get_CanControl = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Stop()
|
self.mpris.Stop()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_stop_when_playing_should_stop_playback(self):
|
def test_stop_when_playing_should_stop_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.mpris.Stop()
|
self.mpris.Stop()
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
|
|
||||||
def test_stop_when_paused_should_stop_playback(self):
|
def test_stop_when_paused_should_stop_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
@ -560,21 +534,19 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_play_is_ignored_if_can_play_is_false(self):
|
def test_play_is_ignored_if_can_play_is_false(self):
|
||||||
self.mpris.get_CanPlay = lambda *_: False
|
self.mpris.get_CanPlay = lambda *_: False
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
self.mpris.Play()
|
self.mpris.Play()
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
|
|
||||||
def test_play_when_stopped_starts_playback(self):
|
def test_play_when_stopped_starts_playback(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
self.mpris.Play()
|
self.mpris.Play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
|
|
||||||
def test_play_after_pause_resumes_from_same_position(self):
|
def test_play_after_pause_resumes_from_same_position(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
|
|
||||||
before_pause = self.core.playback.time_position.get()
|
before_pause = self.core.playback.time_position.get()
|
||||||
@ -598,7 +570,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_seek_is_ignored_if_can_seek_is_false(self):
|
def test_seek_is_ignored_if_can_seek_is_false(self):
|
||||||
self.mpris.get_CanSeek = lambda *_: False
|
self.mpris.get_CanSeek = lambda *_: False
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
|
|
||||||
before_seek = self.core.playback.time_position.get()
|
before_seek = self.core.playback.time_position.get()
|
||||||
@ -614,7 +586,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertLess(after_seek, before_seek + milliseconds_to_seek)
|
self.assertLess(after_seek, before_seek + milliseconds_to_seek)
|
||||||
|
|
||||||
def test_seek_seeks_given_microseconds_forward_in_the_current_track(self):
|
def test_seek_seeks_given_microseconds_forward_in_the_current_track(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
|
|
||||||
before_seek = self.core.playback.time_position.get()
|
before_seek = self.core.playback.time_position.get()
|
||||||
@ -631,7 +603,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(after_seek, before_seek + milliseconds_to_seek)
|
self.assertGreaterEqual(after_seek, before_seek + milliseconds_to_seek)
|
||||||
|
|
||||||
def test_seek_seeks_given_microseconds_backward_if_negative(self):
|
def test_seek_seeks_given_microseconds_backward_if_negative(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(20000)
|
self.core.playback.seek(20000)
|
||||||
|
|
||||||
@ -650,7 +622,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertLess(after_seek, before_seek)
|
self.assertLess(after_seek, before_seek)
|
||||||
|
|
||||||
def test_seek_seeks_to_start_of_track_if_new_position_is_negative(self):
|
def test_seek_seeks_to_start_of_track_if_new_position_is_negative(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(20000)
|
self.core.playback.seek(20000)
|
||||||
|
|
||||||
@ -670,7 +642,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(after_seek, 0)
|
self.assertGreaterEqual(after_seek, 0)
|
||||||
|
|
||||||
def test_seek_skips_to_next_track_if_new_position_gt_track_length(self):
|
def test_seek_skips_to_next_track_if_new_position_gt_track_length(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:a', length=40000),
|
Track(uri='dummy:a', length=40000),
|
||||||
Track(uri='dummy:b')])
|
Track(uri='dummy:b')])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
@ -695,7 +667,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_set_position_is_ignored_if_can_seek_is_false(self):
|
def test_set_position_is_ignored_if_can_seek_is_false(self):
|
||||||
self.mpris.get_CanSeek = lambda *_: False
|
self.mpris.get_CanSeek = lambda *_: False
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
|
|
||||||
before_set_position = self.core.playback.time_position.get()
|
before_set_position = self.core.playback.time_position.get()
|
||||||
@ -713,7 +685,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertLess(after_set_position, position_to_set_in_millisec)
|
self.assertLess(after_set_position, position_to_set_in_millisec)
|
||||||
|
|
||||||
def test_set_position_sets_the_current_track_position_in_microsecs(self):
|
def test_set_position_sets_the_current_track_position_in_microsecs(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
|
|
||||||
before_set_position = self.core.playback.time_position.get()
|
before_set_position = self.core.playback.time_position.get()
|
||||||
@ -734,7 +706,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
after_set_position, position_to_set_in_millisec)
|
after_set_position, position_to_set_in_millisec)
|
||||||
|
|
||||||
def test_set_position_does_nothing_if_the_position_is_negative(self):
|
def test_set_position_does_nothing_if_the_position_is_negative(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(20000)
|
self.core.playback.seek(20000)
|
||||||
|
|
||||||
@ -757,7 +729,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
|
|
||||||
def test_set_position_does_nothing_if_position_is_gt_track_length(self):
|
def test_set_position_does_nothing_if_position_is_gt_track_length(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(20000)
|
self.core.playback.seek(20000)
|
||||||
|
|
||||||
@ -780,7 +752,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
|
|
||||||
def test_set_position_is_noop_if_track_id_isnt_current_track(self):
|
def test_set_position_is_noop_if_track_id_isnt_current_track(self):
|
||||||
self.core.tracklist.append([Track(uri='dummy:a', length=40000)])
|
self.core.tracklist.add([Track(uri='dummy:a', length=40000)])
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.seek(20000)
|
self.core.playback.seek(20000)
|
||||||
|
|
||||||
@ -826,8 +798,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
def test_open_uri_starts_playback_of_new_track_if_stopped(self):
|
def test_open_uri_starts_playback_of_new_track_if_stopped(self):
|
||||||
self.mpris.get_CanPlay = lambda *_: True
|
self.mpris.get_CanPlay = lambda *_: True
|
||||||
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
self.assertEqual(self.core.playback.state.get(), STOPPED)
|
||||||
|
|
||||||
self.mpris.OpenUri('dummy:/test/uri')
|
self.mpris.OpenUri('dummy:/test/uri')
|
||||||
@ -839,8 +810,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
def test_open_uri_starts_playback_of_new_track_if_paused(self):
|
def test_open_uri_starts_playback_of_new_track_if_paused(self):
|
||||||
self.mpris.get_CanPlay = lambda *_: True
|
self.mpris.get_CanPlay = lambda *_: True
|
||||||
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.core.playback.pause()
|
self.core.playback.pause()
|
||||||
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
self.assertEqual(self.core.playback.state.get(), PAUSED)
|
||||||
@ -855,8 +825,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
def test_open_uri_starts_playback_of_new_track_if_playing(self):
|
def test_open_uri_starts_playback_of_new_track_if_playing(self):
|
||||||
self.mpris.get_CanPlay = lambda *_: True
|
self.mpris.get_CanPlay = lambda *_: True
|
||||||
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
self.backend.library.dummy_library = [Track(uri='dummy:/test/uri')]
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([Track(uri='dummy:a'), Track(uri='dummy:b')])
|
||||||
Track(uri='dummy:a'), Track(uri='dummy:b')])
|
|
||||||
self.core.playback.play()
|
self.core.playback.play()
|
||||||
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
self.assertEqual(self.core.playback.state.get(), PLAYING)
|
||||||
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
self.assertEqual(self.core.playback.current_track.get().uri, 'dummy:a')
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class PlayerInterfaceTest(unittest.TestCase):
|
|||||||
pykka.ActorRegistry.stop_all()
|
pykka.ActorRegistry.stop_all()
|
||||||
|
|
||||||
def test_activate_playlist_appends_tracks_to_tracklist(self):
|
def test_activate_playlist_appends_tracks_to_tracklist(self):
|
||||||
self.core.tracklist.append([
|
self.core.tracklist.add([
|
||||||
Track(uri='dummy:old-a'),
|
Track(uri='dummy:old-a'),
|
||||||
Track(uri='dummy:old-b'),
|
Track(uri='dummy:old-b'),
|
||||||
])
|
])
|
||||||
|
|||||||
@ -30,5 +30,6 @@ class VersionTest(unittest.TestCase):
|
|||||||
self.assertLess(SV('0.7.1'), SV('0.7.2'))
|
self.assertLess(SV('0.7.1'), SV('0.7.2'))
|
||||||
self.assertLess(SV('0.7.2'), SV('0.7.3'))
|
self.assertLess(SV('0.7.2'), SV('0.7.3'))
|
||||||
self.assertLess(SV('0.7.3'), SV('0.8.0'))
|
self.assertLess(SV('0.7.3'), SV('0.8.0'))
|
||||||
self.assertLess(SV('0.8.0'), SV(__version__))
|
self.assertLess(SV('0.8.0'), SV('0.8.1'))
|
||||||
self.assertLess(SV(__version__), SV('0.8.2'))
|
self.assertLess(SV('0.8.1'), SV(__version__))
|
||||||
|
self.assertLess(SV(__version__), SV('0.9.1'))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user