From 2fdeec9f5af23315a9695568abce6ec24756c09c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 26 Sep 2012 14:54:44 +0200 Subject: [PATCH 01/15] Move controllers to a new core actor The frontends use the new core actor, while the core actor uses the backend. This is a step towards supporting multiple backends, where the core actor will coordinate the backends. --- mopidy/__main__.py | 15 +- mopidy/audio/__init__.py | 19 +- mopidy/backends/base/__init__.py | 18 +- mopidy/backends/dummy/__init__.py | 19 +- mopidy/backends/local/__init__.py | 20 +- mopidy/backends/spotify/__init__.py | 19 +- mopidy/backends/spotify/library.py | 2 +- mopidy/backends/spotify/session_manager.py | 2 +- mopidy/core/__init__.py | 1 + mopidy/core/actor.py | 42 ++ mopidy/core/current_playlist.py | 6 +- mopidy/core/library.py | 12 +- mopidy/core/playback.py | 43 +- mopidy/core/stored_playlists.py | 20 +- mopidy/frontends/mpd/dispatcher.py | 20 +- mopidy/frontends/mpris/objects.py | 18 +- tests/backends/base/__init__.py | 2 +- tests/backends/base/current_playlist.py | 16 +- tests/backends/base/library.py | 13 +- tests/backends/base/playback.py | 55 +- tests/backends/base/stored_playlists.py | 10 +- tests/backends/events_test.py | 37 +- tests/backends/local/playback_test.py | 7 +- tests/backends/local/stored_playlists_test.py | 3 +- tests/frontends/mpd/dispatcher_test.py | 10 +- tests/frontends/mpd/protocol/__init__.py | 11 +- .../mpd/protocol/current_playlist_test.py | 166 ++--- tests/frontends/mpd/protocol/playback_test.py | 230 +++---- .../frontends/mpd/protocol/regression_test.py | 28 +- tests/frontends/mpd/protocol/status_test.py | 4 +- .../mpd/protocol/stored_playlists_test.py | 16 +- tests/frontends/mpd/status_test.py | 58 +- .../frontends/mpris/player_interface_test.py | 621 +++++++++--------- tests/frontends/mpris/root_interface_test.py | 11 +- 34 files changed, 815 insertions(+), 759 deletions(-) create mode 100644 mopidy/core/actor.py diff --git a/mopidy/__main__.py b/mopidy/__main__.py index c82510d9..ee2e21b6 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -31,6 +31,7 @@ sys.path.insert(0, from mopidy import (get_version, settings, OptionalDependencyError, SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) from mopidy.audio import Audio +from mopidy.core import Core from mopidy.utils import get_class from mopidy.utils.deps import list_deps_optparse_callback from mopidy.utils.log import setup_logging @@ -52,7 +53,8 @@ def main(): check_old_folders() setup_settings(options.interactive) audio = setup_audio() - setup_backend(audio) + backend = setup_backend(audio) + setup_core(audio, backend) setup_frontends() loop.run() except SettingsError as e: @@ -64,6 +66,7 @@ def main(): finally: loop.quit() stop_frontends() + stop_core() stop_backend() stop_audio() stop_remaining_actors() @@ -126,13 +129,21 @@ def stop_audio(): def setup_backend(audio): - get_class(settings.BACKENDS[0]).start(audio=audio) + return get_class(settings.BACKENDS[0]).start(audio=audio).proxy() def stop_backend(): stop_actors_by_class(get_class(settings.BACKENDS[0])) +def setup_core(audio, backend): + return Core.start(audio, backend).proxy() + + +def stop_core(): + stop_actors_by_class(Core) + + def setup_frontends(): for frontend_class_name in settings.FRONTENDS: try: diff --git a/mopidy/audio/__init__.py b/mopidy/audio/__init__.py index df5efb92..3ce459dd 100644 --- a/mopidy/audio/__init__.py +++ b/mopidy/audio/__init__.py @@ -8,8 +8,7 @@ import logging from pykka.actor import ThreadingActor from pykka.registry import ActorRegistry -from mopidy import settings, utils -from mopidy.backends.base import Backend +from mopidy import core, settings, utils from mopidy.utils import process # Trigger install of gst mixer plugins @@ -150,7 +149,7 @@ class Audio(ThreadingActor): def _on_message(self, bus, message): if message.type == gst.MESSAGE_EOS: - self._notify_backend_of_eos() + self._notify_core_of_eos() elif message.type == gst.MESSAGE_ERROR: error, debug = message.parse_error() logger.error(u'%s %s', error, debug) @@ -159,14 +158,14 @@ class Audio(ThreadingActor): error, debug = message.parse_warning() logger.warning(u'%s %s', error, debug) - def _notify_backend_of_eos(self): - backend_refs = ActorRegistry.get_by_class(Backend) - assert len(backend_refs) <= 1, 'Expected at most one running backend.' - if backend_refs: - logger.debug(u'Notifying backend of end-of-stream.') - backend_refs[0].proxy().playback.on_end_of_track() + def _notify_core_of_eos(self): + core_refs = ActorRegistry.get_by_class(core.Core) + assert len(core_refs) <= 1, 'Expected at most one running core instance' + if core_refs: + logger.debug(u'Notifying core of end-of-stream') + core_refs[0].proxy().playback.on_end_of_track() else: - logger.debug(u'No backend to notify of end-of-stream found.') + logger.debug(u'No core instance to notify of end-of-stream found') def set_uri(self, uri): """ diff --git a/mopidy/backends/base/__init__.py b/mopidy/backends/base/__init__.py index 67a3c5ba..4e0f0b08 100644 --- a/mopidy/backends/base/__init__.py +++ b/mopidy/backends/base/__init__.py @@ -10,24 +10,20 @@ class Backend(object): #: which will then set this field. audio = None - #: The current playlist controller. An instance of - #: :class:`mopidy.backends.base.CurrentPlaylistController`. - current_playlist = None - - #: The library controller. An instance of - # :class:`mopidy.backends.base.LibraryController`. + #: The library provider. An instance of + # :class:`mopidy.backends.base.BaseLibraryProvider`. library = None - #: The playback controller. An instance of - #: :class:`mopidy.backends.base.PlaybackController`. + #: The playback provider. An instance of + #: :class:`mopidy.backends.base.BasePlaybackProvider`. playback = None - #: The stored playlists controller. An instance of - #: :class:`mopidy.backends.base.StoredPlaylistsController`. + #: The stored playlists provider. An instance of + #: :class:`mopidy.backends.base.BaseStoredPlaylistsProvider`. stored_playlists = None #: List of URI schemes this backend can handle. uri_schemes = [] - def __init__(self, audio=None): + def __init__(self, audio): self.audio = audio diff --git a/mopidy/backends/dummy/__init__.py b/mopidy/backends/dummy/__init__.py index 9c4a0e69..1d69ed7c 100644 --- a/mopidy/backends/dummy/__init__.py +++ b/mopidy/backends/dummy/__init__.py @@ -1,6 +1,5 @@ from pykka.actor import ThreadingActor -from mopidy import core from mopidy.backends import base from mopidy.models import Playlist @@ -14,21 +13,11 @@ class DummyBackend(ThreadingActor, base.Backend): """ def __init__(self, *args, **kwargs): - super(DummyBackend, self).__init__(*args, **kwargs) + base.Backend.__init__(self, *args, **kwargs) - self.current_playlist = core.CurrentPlaylistController(backend=self) - - library_provider = DummyLibraryProvider(backend=self) - self.library = core.LibraryController(backend=self, - provider=library_provider) - - playback_provider = DummyPlaybackProvider(backend=self) - self.playback = core.PlaybackController(backend=self, - provider=playback_provider) - - stored_playlists_provider = DummyStoredPlaylistsProvider(backend=self) - self.stored_playlists = core.StoredPlaylistsController(backend=self, - provider=stored_playlists_provider) + self.library = DummyLibraryProvider(backend=self) + self.playback = DummyPlaybackProvider(backend=self) + self.stored_playlists = DummyStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'dummy'] diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index 73e10918..f3e86679 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -6,7 +6,7 @@ import shutil from pykka.actor import ThreadingActor -from mopidy import audio, core, settings +from mopidy import settings from mopidy.backends import base from mopidy.models import Playlist, Track, Album @@ -33,19 +33,9 @@ class LocalBackend(ThreadingActor, base.Backend): def __init__(self, *args, **kwargs): base.Backend.__init__(self, *args, **kwargs) - self.current_playlist = core.CurrentPlaylistController(backend=self) - - self.library_provider = LocalLibraryProvider(backend=self) - self.library = core.LibraryController(backend=self, - provider=self.library_provider) - - playback_provider = base.BasePlaybackProvider(backend=self) - self.playback = core.PlaybackController(backend=self, - provider=playback_provider) - - stored_playlists_provider = LocalStoredPlaylistsProvider(backend=self) - self.stored_playlists = core.StoredPlaylistsController(backend=self, - provider=stored_playlists_provider) + self.library = LocalLibraryProvider(backend=self) + self.playback = base.BasePlaybackProvider(backend=self) + self.stored_playlists = LocalStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'file'] @@ -69,7 +59,7 @@ class LocalStoredPlaylistsProvider(base.BaseStoredPlaylistsProvider): tracks = [] for uri in parse_m3u(m3u, settings.LOCAL_MUSIC_PATH): try: - tracks.append(self.backend.library_provider.lookup(uri)) + tracks.append(self.backend.library.lookup(uri)) except LookupError, e: logger.error('Playlist item could not be added: %s', e) playlist = Playlist(tracks=tracks, name=name) diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py index 4320d723..a79168f5 100644 --- a/mopidy/backends/spotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -2,7 +2,7 @@ import logging from pykka.actor import ThreadingActor -from mopidy import audio, core, settings +from mopidy import settings from mopidy.backends import base logger = logging.getLogger('mopidy.backends.spotify') @@ -48,20 +48,9 @@ class SpotifyBackend(ThreadingActor, base.Backend): base.Backend.__init__(self, *args, **kwargs) - self.current_playlist = core.CurrentPlaylistController(backend=self) - - library_provider = SpotifyLibraryProvider(backend=self) - self.library = core.LibraryController(backend=self, - provider=library_provider) - - playback_provider = SpotifyPlaybackProvider(backend=self) - self.playback = core.PlaybackController(backend=self, - provider=playback_provider) - - self.stored_playlists_provider = SpotifyStoredPlaylistsProvider( - backend=self) - self.stored_playlists = core.StoredPlaylistsController(backend=self, - provider=self.stored_playlists_provider) + self.library = SpotifyLibraryProvider(backend=self) + self.playback = SpotifyPlaybackProvider(backend=self) + self.stored_playlists = SpotifyStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'spotify'] diff --git a/mopidy/backends/spotify/library.py b/mopidy/backends/spotify/library.py index 3931aece..18276ecd 100644 --- a/mopidy/backends/spotify/library.py +++ b/mopidy/backends/spotify/library.py @@ -66,7 +66,7 @@ class SpotifyLibraryProvider(BaseLibraryProvider): # Since we can't search for the entire Spotify library, we return # all tracks in the stored playlists when the query is empty. tracks = [] - for playlist in self.backend.stored_playlists_provider.playlists: + for playlist in self.backend.stored_playlists.playlists: tracks += playlist.tracks return Playlist(tracks=tracks) spotify_query = [] diff --git a/mopidy/backends/spotify/session_manager.py b/mopidy/backends/spotify/session_manager.py index a6389048..52769d84 100644 --- a/mopidy/backends/spotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -138,7 +138,7 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): playlists = map(SpotifyTranslator.to_mopidy_playlist, self.session.playlist_container()) playlists = filter(None, playlists) - self.backend.stored_playlists_provider.playlists = playlists + self.backend.stored_playlists.playlists = playlists logger.info(u'Loaded %d Spotify playlist(s)', len(playlists)) def search(self, query, queue): diff --git a/mopidy/core/__init__.py b/mopidy/core/__init__.py index 87df96c9..6070dcc8 100644 --- a/mopidy/core/__init__.py +++ b/mopidy/core/__init__.py @@ -1,3 +1,4 @@ +from .actor import Core from .current_playlist import CurrentPlaylistController from .library import LibraryController from .playback import PlaybackController, PlaybackState diff --git a/mopidy/core/actor.py b/mopidy/core/actor.py new file mode 100644 index 00000000..4ff378c4 --- /dev/null +++ b/mopidy/core/actor.py @@ -0,0 +1,42 @@ +from pykka.actor import ThreadingActor + +from .current_playlist import CurrentPlaylistController +from .library import LibraryController +from .playback import PlaybackController +from .stored_playlists import StoredPlaylistsController + + +class Core(ThreadingActor): + #: The current playlist controller. An instance of + #: :class:`mopidy.core.CurrentPlaylistController`. + current_playlist = None + + #: The library controller. An instance of + # :class:`mopidy.core.LibraryController`. + library = None + + #: The playback controller. An instance of + #: :class:`mopidy.core.PlaybackController`. + playback = None + + #: The stored playlists controller. An instance of + #: :class:`mopidy.core.StoredPlaylistsController`. + stored_playlists = None + + def __init__(self, audio=None, backend=None): + self._backend = backend + + self.current_playlist = CurrentPlaylistController(core=self) + + self.library = LibraryController(backend=backend, core=self) + + self.playback = PlaybackController( + audio=audio, backend=backend, core=self) + + self.stored_playlists = StoredPlaylistsController( + backend=backend, core=self) + + @property + def uri_schemes(self): + """List of URI schemes we can handle""" + return self._backend.uri_schemes.get() diff --git a/mopidy/core/current_playlist.py b/mopidy/core/current_playlist.py index af06e05e..a39b4c39 100644 --- a/mopidy/core/current_playlist.py +++ b/mopidy/core/current_playlist.py @@ -17,8 +17,8 @@ class CurrentPlaylistController(object): pykka_traversable = True - def __init__(self, backend): - self.backend = backend + def __init__(self, core): + self.core = core self.cp_id = 0 self._cp_tracks = [] self._version = 0 @@ -59,7 +59,7 @@ class CurrentPlaylistController(object): @version.setter def version(self, version): self._version = version - self.backend.playback.on_current_playlist_change() + self.core.playback.on_current_playlist_change() self._trigger_playlist_changed() def add(self, track, at_position=None, increase_version=True): diff --git a/mopidy/core/library.py b/mopidy/core/library.py index fc55aaeb..52f85b55 100644 --- a/mopidy/core/library.py +++ b/mopidy/core/library.py @@ -8,9 +8,9 @@ class LibraryController(object): pykka_traversable = True - def __init__(self, backend, provider): + def __init__(self, backend, core): self.backend = backend - self.provider = provider + self.core = core def find_exact(self, **query): """ @@ -29,7 +29,7 @@ class LibraryController(object): :type query: dict :rtype: :class:`mopidy.models.Playlist` """ - return self.provider.find_exact(**query) + return self.backend.library.find_exact(**query).get() def lookup(self, uri): """ @@ -39,7 +39,7 @@ class LibraryController(object): :type uri: string :rtype: :class:`mopidy.models.Track` or :class:`None` """ - return self.provider.lookup(uri) + return self.backend.library.lookup(uri).get() def refresh(self, uri=None): """ @@ -48,7 +48,7 @@ class LibraryController(object): :param uri: directory or track URI :type uri: string """ - return self.provider.refresh(uri) + return self.backend.library.refresh(uri).get() def search(self, **query): """ @@ -67,4 +67,4 @@ class LibraryController(object): :type query: dict :rtype: :class:`mopidy.models.Playlist` """ - return self.provider.search(**query) + return self.backend.library.search(**query).get() diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index 82a11064..efba03dd 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -79,9 +79,10 @@ class PlaybackController(object): #: Playback continues after current song. single = option_wrapper('_single', False) - def __init__(self, backend, provider): + def __init__(self, audio, backend, core): + self.audio = audio self.backend = backend - self.provider = provider + self.core = core self._state = PlaybackState.STOPPED self._shuffled = [] self._first_shuffle = True @@ -125,7 +126,7 @@ class PlaybackController(object): if self.current_cp_track is None: return None try: - return self.backend.current_playlist.cp_tracks.index( + return self.core.current_playlist.cp_tracks.index( self.current_cp_track) except ValueError: return None @@ -152,7 +153,7 @@ class PlaybackController(object): # pylint: disable = R0911 # Too many return statements - cp_tracks = self.backend.current_playlist.cp_tracks + cp_tracks = self.core.current_playlist.cp_tracks if not cp_tracks: return None @@ -204,7 +205,7 @@ class PlaybackController(object): enabled this should be a random track, all tracks should be played once before the list repeats. """ - cp_tracks = self.backend.current_playlist.cp_tracks + cp_tracks = self.core.current_playlist.cp_tracks if not cp_tracks: return None @@ -258,7 +259,7 @@ class PlaybackController(object): if self.current_playlist_position in (None, 0): return None - return self.backend.current_playlist.cp_tracks[ + return self.core.current_playlist.cp_tracks[ self.current_playlist_position - 1] @property @@ -291,15 +292,16 @@ class PlaybackController(object): @property def time_position(self): """Time position in milliseconds.""" - return self.provider.get_time_position() + return self.backend.playback.get_time_position().get() @property def volume(self): - return self.provider.get_volume() + """Volume as int in range [0..100].""" + return self.backend.playback.get_volume().get() @volume.setter def volume(self, volume): - self.provider.set_volume(volume) + self.backend.playback.set_volume(volume).get() def change_track(self, cp_track, on_error_step=1): """ @@ -337,20 +339,20 @@ class PlaybackController(object): self.stop(clear_current_track=True) if self.consume: - self.backend.current_playlist.remove(cpid=original_cp_track.cpid) + self.core.current_playlist.remove(cpid=original_cp_track.cpid) def on_current_playlist_change(self): """ Tell the playback controller that the current playlist has changed. - Used by :class:`mopidy.backends.base.CurrentPlaylistController`. + Used by :class:`mopidy.core.CurrentPlaylistController`. """ self._first_shuffle = True self._shuffled = [] - if (not self.backend.current_playlist.cp_tracks or + if (not self.core.current_playlist.cp_tracks or self.current_cp_track not in - self.backend.current_playlist.cp_tracks): + self.core.current_playlist.cp_tracks): self.stop(clear_current_track=True) def next(self): @@ -368,7 +370,7 @@ class PlaybackController(object): def pause(self): """Pause playback.""" - if self.provider.pause(): + if self.backend.playback.pause().get(): self.state = PlaybackState.PAUSED self._trigger_track_playback_paused() @@ -386,7 +388,7 @@ class PlaybackController(object): """ if cp_track is not None: - assert cp_track in self.backend.current_playlist.cp_tracks + assert cp_track in self.core.current_playlist.cp_tracks elif cp_track is None: if self.state == PlaybackState.PAUSED: return self.resume() @@ -400,7 +402,7 @@ class PlaybackController(object): if cp_track is not None: self.current_cp_track = cp_track self.state = PlaybackState.PLAYING - if not self.provider.play(cp_track.track): + if not self.backend.playback.play(cp_track.track).get(): # Track is not playable if self.random and self._shuffled: self._shuffled.remove(cp_track) @@ -426,7 +428,8 @@ class PlaybackController(object): def resume(self): """If paused, resume playing the current track.""" - if self.state == PlaybackState.PAUSED and self.provider.resume(): + if (self.state == PlaybackState.PAUSED and + self.backend.playback.resume().get()): self.state = PlaybackState.PLAYING self._trigger_track_playback_resumed() @@ -438,7 +441,7 @@ class PlaybackController(object): :type time_position: int :rtype: :class:`True` if successful, else :class:`False` """ - if not self.backend.current_playlist.tracks: + if not self.core.current_playlist.tracks: return False if self.state == PlaybackState.STOPPED: @@ -452,7 +455,7 @@ class PlaybackController(object): self.next() return True - success = self.provider.seek(time_position) + success = self.backend.playback.seek(time_position).get() if success: self._trigger_seeked(time_position) return success @@ -466,7 +469,7 @@ class PlaybackController(object): :type clear_current_track: boolean """ if self.state != PlaybackState.STOPPED: - if self.provider.stop(): + if self.backend.playback.stop().get(): self._trigger_track_playback_ended() self.state = PlaybackState.STOPPED if clear_current_track: diff --git a/mopidy/core/stored_playlists.py b/mopidy/core/stored_playlists.py index a29e34fc..6ea9b1d3 100644 --- a/mopidy/core/stored_playlists.py +++ b/mopidy/core/stored_playlists.py @@ -8,9 +8,9 @@ class StoredPlaylistsController(object): pykka_traversable = True - def __init__(self, backend, provider): + def __init__(self, backend, core): self.backend = backend - self.provider = provider + self.core = core @property def playlists(self): @@ -19,11 +19,11 @@ class StoredPlaylistsController(object): Read/write. List of :class:`mopidy.models.Playlist`. """ - return self.provider.playlists + return self.backend.stored_playlists.playlists.get() @playlists.setter def playlists(self, playlists): - self.provider.playlists = playlists + self.backend.stored_playlists.playlists = playlists def create(self, name): """ @@ -33,7 +33,7 @@ class StoredPlaylistsController(object): :type name: string :rtype: :class:`mopidy.models.Playlist` """ - return self.provider.create(name) + return self.backend.stored_playlists.create(name).get() def delete(self, playlist): """ @@ -42,7 +42,7 @@ class StoredPlaylistsController(object): :param playlist: the playlist to delete :type playlist: :class:`mopidy.models.Playlist` """ - return self.provider.delete(playlist) + return self.backend.stored_playlists.delete(playlist).get() def get(self, **criteria): """ @@ -83,14 +83,14 @@ class StoredPlaylistsController(object): :type uri: string :rtype: :class:`mopidy.models.Playlist` """ - return self.provider.lookup(uri) + return self.backend.stored_playlists.lookup(uri).get() def refresh(self): """ Refresh the stored playlists in :attr:`mopidy.backends.base.StoredPlaylistsController.playlists`. """ - return self.provider.refresh() + return self.backend.stored_playlists.refresh().get() def rename(self, playlist, new_name): """ @@ -101,7 +101,7 @@ class StoredPlaylistsController(object): :param new_name: the new name :type new_name: string """ - return self.provider.rename(playlist, new_name) + return self.backend.stored_playlists.rename(playlist, new_name).get() def save(self, playlist): """ @@ -110,4 +110,4 @@ class StoredPlaylistsController(object): :param playlist: the playlist :type playlist: :class:`mopidy.models.Playlist` """ - return self.provider.save(playlist) + return self.backend.stored_playlists.save(playlist).get() diff --git a/mopidy/frontends/mpd/dispatcher.py b/mopidy/frontends/mpd/dispatcher.py index 94ac6bf9..c9dee576 100644 --- a/mopidy/frontends/mpd/dispatcher.py +++ b/mopidy/frontends/mpd/dispatcher.py @@ -4,8 +4,7 @@ import re from pykka import ActorDeadError from pykka.registry import ActorRegistry -from mopidy import settings -from mopidy.backends.base import Backend +from mopidy import core, settings from mopidy.frontends.mpd import exceptions from mopidy.frontends.mpd.protocol import mpd_commands, request_handlers # Do not remove the following import. The protocol modules must be imported to @@ -233,16 +232,17 @@ class MpdContext(object): self.session = session self.events = set() self.subscriptions = set() - self._backend = None + self._core = None @property def backend(self): """ - The backend. An instance of :class:`mopidy.backends.base.Backend`. + The Mopidy core. An instance of :class:`mopidy.core.Core`. """ - if self._backend is None: - backend_refs = ActorRegistry.get_by_class(Backend) - assert len(backend_refs) == 1, \ - 'Expected exactly one running backend.' - self._backend = backend_refs[0].proxy() - return self._backend + # TODO: Rename property to 'core' + if self._core is None: + core_refs = ActorRegistry.get_by_class(core.Core) + assert len(core_refs) == 1, \ + 'Expected exactly one running core instance.' + self._core = core_refs[0].proxy() + return self._core diff --git a/mopidy/frontends/mpris/objects.py b/mopidy/frontends/mpris/objects.py index 93669977..c2c9f527 100644 --- a/mopidy/frontends/mpris/objects.py +++ b/mopidy/frontends/mpris/objects.py @@ -14,8 +14,7 @@ except ImportError as import_error: from pykka.registry import ActorRegistry -from mopidy import settings -from mopidy.backends.base import Backend +from mopidy import core, settings from mopidy.core import PlaybackState from mopidy.utils.process import exit_process @@ -35,7 +34,7 @@ class MprisObject(dbus.service.Object): properties = None def __init__(self): - self._backend = None + self._core = None self.properties = { ROOT_IFACE: self._get_root_iface_properties(), PLAYER_IFACE: self._get_player_iface_properties(), @@ -86,12 +85,13 @@ class MprisObject(dbus.service.Object): @property def backend(self): - if self._backend is None: - backend_refs = ActorRegistry.get_by_class(Backend) - assert len(backend_refs) == 1, \ - 'Expected exactly one running backend.' - self._backend = backend_refs[0].proxy() - return self._backend + # TODO: Rename property to 'core' + if self._core is None: + core_refs = ActorRegistry.get_by_class(core.Core) + assert len(core_refs) == 1, \ + 'Expected exactly one running core instance.' + self._core = core_refs[0].proxy() + return self._core def _get_track_id(self, cp_track): return '/com/mopidy/track/%d' % cp_track.cpid diff --git a/tests/backends/base/__init__.py b/tests/backends/base/__init__.py index 29f010e1..84eee193 100644 --- a/tests/backends/base/__init__.py +++ b/tests/backends/base/__init__.py @@ -1,7 +1,7 @@ def populate_playlist(func): def wrapper(self): for track in self.tracks: - self.backend.current_playlist.add(track) + self.core.current_playlist.add(track) return func(self) wrapper.__name__ = func.__name__ diff --git a/tests/backends/base/current_playlist.py b/tests/backends/base/current_playlist.py index a42e7eac..db4473bb 100644 --- a/tests/backends/base/current_playlist.py +++ b/tests/backends/base/current_playlist.py @@ -1,7 +1,9 @@ import mock import random -from mopidy import audio +from pykka.registry import ActorRegistry + +from mopidy import audio, core from mopidy.core import PlaybackState from mopidy.models import CpTrack, Playlist, Track @@ -12,13 +14,17 @@ class CurrentPlaylistControllerTest(object): tracks = [] def setUp(self): - self.backend = self.backend_class() - self.backend.audio = mock.Mock(spec=audio.Audio) - self.controller = self.backend.current_playlist - self.playback = self.backend.playback + self.audio = mock.Mock(spec=audio.Audio) + self.backend = self.backend_class.start(audio=self.audio).proxy() + self.core = core.Core(audio=audio, backend=self.backend) + self.controller = self.core.current_playlist + self.playback = self.core.playback assert len(self.tracks) == 3, 'Need three tracks to run tests.' + def tearDown(self): + ActorRegistry.stop_all() + def test_length(self): self.assertEqual(0, len(self.controller.cp_tracks)) self.assertEqual(0, self.controller.length) diff --git a/tests/backends/base/library.py b/tests/backends/base/library.py index f76d9d75..99dce78e 100644 --- a/tests/backends/base/library.py +++ b/tests/backends/base/library.py @@ -1,3 +1,8 @@ +import mock + +from pykka.registry import ActorRegistry + +from mopidy import core from mopidy.models import Playlist, Track, Album, Artist from tests import unittest, path_to_data_dir @@ -15,8 +20,12 @@ class LibraryControllerTest(object): Track()] def setUp(self): - self.backend = self.backend_class() - self.library = self.backend.library + self.backend = self.backend_class.start(audio=None).proxy() + self.core = core.Core(backend=self.backend) + self.library = self.core.library + + def tearDown(self): + ActorRegistry.stop_all() def test_refresh(self): self.library.refresh() diff --git a/tests/backends/base/playback.py b/tests/backends/base/playback.py index e052a907..46863f03 100644 --- a/tests/backends/base/playback.py +++ b/tests/backends/base/playback.py @@ -2,7 +2,7 @@ import mock import random import time -from mopidy import audio +from mopidy import audio, core from mopidy.core import PlaybackState from mopidy.models import Track @@ -16,10 +16,11 @@ class PlaybackControllerTest(object): tracks = [] def setUp(self): - self.backend = self.backend_class() - self.backend.audio = mock.Mock(spec=audio.Audio) - self.playback = self.backend.playback - self.current_playlist = self.backend.current_playlist + self.audio = mock.Mock(spec=audio.Audio) + self.backend = self.backend_class.start(audio=self.audio).proxy() + self.core = core.Core(backend=self.backend) + self.playback = self.core.playback + self.current_playlist = self.core.current_playlist assert len(self.tracks) >= 3, \ 'Need at least three tracks to run tests.' @@ -97,8 +98,8 @@ class PlaybackControllerTest(object): @populate_playlist def test_play_skips_to_next_track_on_failure(self): - # If provider.play() returns False, it is a failure. - self.playback.provider.play = lambda track: track != self.tracks[0] + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[0] self.playback.play() self.assertNotEqual(self.playback.current_track, self.tracks[0]) self.assertEqual(self.playback.current_track, self.tracks[1]) @@ -157,8 +158,8 @@ class PlaybackControllerTest(object): @populate_playlist def test_previous_skips_to_previous_track_on_failure(self): - # If provider.play() returns False, it is a failure. - self.playback.provider.play = lambda track: track != self.tracks[1] + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] self.playback.play(self.current_playlist.cp_tracks[2]) self.assertEqual(self.playback.current_track, self.tracks[2]) self.playback.previous() @@ -221,8 +222,8 @@ class PlaybackControllerTest(object): @populate_playlist def test_next_skips_to_next_track_on_failure(self): - # If provider.play() returns False, it is a failure. - self.playback.provider.play = lambda track: track != self.tracks[1] + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] self.playback.play() self.assertEqual(self.playback.current_track, self.tracks[0]) self.playback.next() @@ -274,7 +275,7 @@ class PlaybackControllerTest(object): self.playback.consume = True self.playback.play() self.playback.next() - self.assertIn(self.tracks[0], self.backend.current_playlist.tracks) + self.assertIn(self.tracks[0], self.current_playlist.tracks) @populate_playlist def test_next_with_single_and_repeat(self): @@ -298,7 +299,7 @@ class PlaybackControllerTest(object): random.seed(1) self.playback.random = True self.assertEqual(self.playback.track_at_next, self.tracks[2]) - self.backend.current_playlist.append(self.tracks[:1]) + self.current_playlist.append(self.tracks[:1]) self.assertEqual(self.playback.track_at_next, self.tracks[1]) @populate_playlist @@ -357,8 +358,8 @@ class PlaybackControllerTest(object): @populate_playlist def test_end_of_track_skips_to_next_track_on_failure(self): - # If provider.play() returns False, it is a failure. - self.playback.provider.play = lambda track: track != self.tracks[1] + # If backend's play() returns False, it is a failure. + self.backend.playback.play = lambda track: track != self.tracks[1] self.playback.play() self.assertEqual(self.playback.current_track, self.tracks[0]) self.playback.on_end_of_track() @@ -411,7 +412,7 @@ class PlaybackControllerTest(object): self.playback.consume = True self.playback.play() self.playback.on_end_of_track() - self.assertNotIn(self.tracks[0], self.backend.current_playlist.tracks) + self.assertNotIn(self.tracks[0], self.current_playlist.tracks) @populate_playlist def test_end_of_track_with_random(self): @@ -427,7 +428,7 @@ class PlaybackControllerTest(object): random.seed(1) self.playback.random = True self.assertEqual(self.playback.track_at_next, self.tracks[2]) - self.backend.current_playlist.append(self.tracks[:1]) + self.current_playlist.append(self.tracks[:1]) self.assertEqual(self.playback.track_at_next, self.tracks[1]) @populate_playlist @@ -517,7 +518,7 @@ class PlaybackControllerTest(object): wrapper.called = False self.playback.on_current_playlist_change = wrapper - self.backend.current_playlist.append([Track()]) + self.current_playlist.append([Track()]) self.assert_(wrapper.called) @@ -534,13 +535,13 @@ class PlaybackControllerTest(object): def test_on_current_playlist_change_when_playing(self): self.playback.play() current_track = self.playback.current_track - self.backend.current_playlist.append([self.tracks[2]]) + self.current_playlist.append([self.tracks[2]]) self.assertEqual(self.playback.state, PlaybackState.PLAYING) self.assertEqual(self.playback.current_track, current_track) @populate_playlist def test_on_current_playlist_change_when_stopped(self): - self.backend.current_playlist.append([self.tracks[2]]) + self.current_playlist.append([self.tracks[2]]) self.assertEqual(self.playback.state, PlaybackState.STOPPED) self.assertEqual(self.playback.current_track, None) @@ -549,7 +550,7 @@ class PlaybackControllerTest(object): self.playback.play() self.playback.pause() current_track = self.playback.current_track - self.backend.current_playlist.append([self.tracks[2]]) + self.current_playlist.append([self.tracks[2]]) self.assertEqual(self.playback.state, PlaybackState.PAUSED) self.assertEqual(self.playback.current_track, current_track) @@ -640,7 +641,7 @@ class PlaybackControllerTest(object): @populate_playlist def test_seek_when_playing_updates_position(self): - length = self.backend.current_playlist.tracks[0].length + length = self.current_playlist.tracks[0].length self.playback.play() self.playback.seek(length - 1000) position = self.playback.time_position @@ -655,7 +656,7 @@ class PlaybackControllerTest(object): @populate_playlist def test_seek_when_paused_updates_position(self): - length = self.backend.current_playlist.tracks[0].length + length = self.current_playlist.tracks[0].length self.playback.play() self.playback.pause() self.playback.seek(length - 1000) @@ -730,7 +731,7 @@ class PlaybackControllerTest(object): def test_time_position_when_stopped(self): future = mock.Mock() future.get = mock.Mock(return_value=0) - self.backend.audio.get_position = mock.Mock(return_value=future) + self.audio.get_position = mock.Mock(return_value=future) self.assertEqual(self.playback.time_position, 0) @@ -738,7 +739,7 @@ class PlaybackControllerTest(object): def test_time_position_when_stopped_with_playlist(self): future = mock.Mock() future.get = mock.Mock(return_value=0) - self.backend.audio.get_position = mock.Mock(return_value=future) + self.audio.get_position = mock.Mock(return_value=future) self.assertEqual(self.playback.time_position, 0) @@ -772,9 +773,9 @@ class PlaybackControllerTest(object): def test_playlist_is_empty_after_all_tracks_are_played_with_consume(self): self.playback.consume = True self.playback.play() - for _ in range(len(self.backend.current_playlist.tracks)): + for _ in range(len(self.current_playlist.tracks)): self.playback.on_end_of_track() - self.assertEqual(len(self.backend.current_playlist.tracks), 0) + self.assertEqual(len(self.current_playlist.tracks), 0) @populate_playlist def test_play_with_random(self): diff --git a/tests/backends/base/stored_playlists.py b/tests/backends/base/stored_playlists.py index 1e575b9e..4e65c034 100644 --- a/tests/backends/base/stored_playlists.py +++ b/tests/backends/base/stored_playlists.py @@ -2,7 +2,9 @@ import os import shutil import tempfile -from mopidy import settings +import mock + +from mopidy import audio, core, settings from mopidy.models import Playlist from tests import unittest, path_to_data_dir @@ -14,8 +16,10 @@ class StoredPlaylistsControllerTest(object): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('library_tag_cache') settings.LOCAL_MUSIC_PATH = path_to_data_dir('') - self.backend = self.backend_class() - self.stored = self.backend.stored_playlists + self.audio = mock.Mock(spec=audio.Audio) + self.backend = self.backend_class.start(audio=self.audio).proxy() + self.core = core.Core(backend=self.backend) + self.stored = self.core.stored_playlists def tearDown(self): if os.path.exists(settings.LOCAL_PLAYLIST_PATH): diff --git a/tests/backends/events_test.py b/tests/backends/events_test.py index d761676d..5408d71f 100644 --- a/tests/backends/events_test.py +++ b/tests/backends/events_test.py @@ -2,7 +2,8 @@ import mock from pykka.registry import ActorRegistry -from mopidy.backends.dummy import DummyBackend +from mopidy import audio, core +from mopidy.backends import dummy from mopidy.listeners import BackendListener from mopidy.models import Track @@ -12,42 +13,44 @@ from tests import unittest @mock.patch.object(BackendListener, 'send') class BackendEventsTest(unittest.TestCase): def setUp(self): - self.backend = DummyBackend.start().proxy() + self.audio = mock.Mock(spec=audio.Audio) + self.backend = dummy.DummyBackend.start(audio=audio).proxy() + self.core = core.Core.start(backend=self.backend).proxy() def tearDown(self): ActorRegistry.stop_all() def test_pause_sends_track_playback_paused_event(self, send): - self.backend.current_playlist.add(Track(uri='a')) - self.backend.playback.play().get() + self.core.current_playlist.add(Track(uri='a')) + self.core.playback.play().get() send.reset_mock() - self.backend.playback.pause().get() + self.core.playback.pause().get() self.assertEqual(send.call_args[0][0], 'track_playback_paused') def test_resume_sends_track_playback_resumed(self, send): - self.backend.current_playlist.add(Track(uri='a')) - self.backend.playback.play() - self.backend.playback.pause().get() + self.core.current_playlist.add(Track(uri='a')) + self.core.playback.play() + self.core.playback.pause().get() send.reset_mock() - self.backend.playback.resume().get() + self.core.playback.resume().get() self.assertEqual(send.call_args[0][0], 'track_playback_resumed') def test_play_sends_track_playback_started_event(self, send): - self.backend.current_playlist.add(Track(uri='a')) + self.core.current_playlist.add(Track(uri='a')) send.reset_mock() - self.backend.playback.play().get() + self.core.playback.play().get() self.assertEqual(send.call_args[0][0], 'track_playback_started') def test_stop_sends_track_playback_ended_event(self, send): - self.backend.current_playlist.add(Track(uri='a')) - self.backend.playback.play().get() + self.core.current_playlist.add(Track(uri='a')) + self.core.playback.play().get() send.reset_mock() - self.backend.playback.stop().get() + self.core.playback.stop().get() self.assertEqual(send.call_args_list[0][0][0], 'track_playback_ended') def test_seek_sends_seeked_event(self, send): - self.backend.current_playlist.add(Track(uri='a', length=40000)) - self.backend.playback.play().get() + self.core.current_playlist.add(Track(uri='a', length=40000)) + self.core.playback.play().get() send.reset_mock() - self.backend.playback.seek(1000).get() + self.core.playback.seek(1000).get() self.assertEqual(send.call_args[0][0], 'seeked') diff --git a/tests/backends/local/playback_test.py b/tests/backends/local/playback_test.py index c167fbcc..fe5fee32 100644 --- a/tests/backends/local/playback_test.py +++ b/tests/backends/local/playback_test.py @@ -20,10 +20,7 @@ class LocalPlaybackControllerTest(PlaybackControllerTest, unittest.TestCase): def setUp(self): settings.BACKENDS = ('mopidy.backends.local.LocalBackend',) - super(LocalPlaybackControllerTest, self).setUp() - # Two tests does not work at all when using the fake sink - #self.backend.playback.use_fake_sink() def tearDown(self): super(LocalPlaybackControllerTest, self).tearDown() @@ -32,10 +29,10 @@ class LocalPlaybackControllerTest(PlaybackControllerTest, unittest.TestCase): def add_track(self, path): uri = path_to_uri(path_to_data_dir(path)) track = Track(uri=uri, length=4464) - self.backend.current_playlist.add(track) + self.current_playlist.add(track) def test_uri_scheme(self): - self.assertIn('file', self.backend.uri_schemes) + self.assertIn('file', self.core.uri_schemes) def test_play_mp3(self): self.add_track('blank.mp3') diff --git a/tests/backends/local/stored_playlists_test.py b/tests/backends/local/stored_playlists_test.py index 56be92c4..3f3d9c58 100644 --- a/tests/backends/local/stored_playlists_test.py +++ b/tests/backends/local/stored_playlists_test.py @@ -65,8 +65,7 @@ class LocalStoredPlaylistsControllerTest(StoredPlaylistsControllerTest, self.stored.save(playlist) - self.backend = self.backend_class() - self.stored = self.backend.stored_playlists + self.backend = self.backend_class.start(audio=self.audio).proxy() self.assert_(self.stored.playlists) self.assertEqual('test', self.stored.playlists[0].name) diff --git a/tests/frontends/mpd/dispatcher_test.py b/tests/frontends/mpd/dispatcher_test.py index 9f05d7dd..0bff04e7 100644 --- a/tests/frontends/mpd/dispatcher_test.py +++ b/tests/frontends/mpd/dispatcher_test.py @@ -1,4 +1,7 @@ -from mopidy.backends.dummy import DummyBackend +from pykka.registry import ActorRegistry + +from mopidy import core +from mopidy.backends import dummy from mopidy.frontends.mpd.dispatcher import MpdDispatcher from mopidy.frontends.mpd.exceptions import MpdAckError from mopidy.frontends.mpd.protocol import request_handlers, handle_request @@ -8,11 +11,12 @@ from tests import unittest class MpdDispatcherTest(unittest.TestCase): def setUp(self): - self.backend = DummyBackend.start().proxy() + self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.core = core.Core.start(backend=self.backend).proxy() self.dispatcher = MpdDispatcher() def tearDown(self): - self.backend.stop().get() + ActorRegistry.stop_all() def test_register_same_pattern_twice_fails(self): func = lambda: None diff --git a/tests/frontends/mpd/protocol/__init__.py b/tests/frontends/mpd/protocol/__init__.py index 3b8fbe33..a2dafb9b 100644 --- a/tests/frontends/mpd/protocol/__init__.py +++ b/tests/frontends/mpd/protocol/__init__.py @@ -1,7 +1,9 @@ import mock -from mopidy import settings -from mopidy.backends import dummy as backend +from pykka.registry import ActorRegistry + +from mopidy import core, settings +from mopidy.backends import dummy from mopidy.frontends import mpd from tests import unittest @@ -21,7 +23,8 @@ class MockConnection(mock.Mock): class BaseTestCase(unittest.TestCase): def setUp(self): - self.backend = backend.DummyBackend.start().proxy() + self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.core = core.Core.start(backend=self.backend).proxy() self.connection = MockConnection() self.session = mpd.MpdSession(self.connection) @@ -29,7 +32,7 @@ class BaseTestCase(unittest.TestCase): self.context = self.dispatcher.context def tearDown(self): - self.backend.stop().get() + ActorRegistry.stop_all() settings.runtime.clear() def sendRequest(self, request): diff --git a/tests/frontends/mpd/protocol/current_playlist_test.py b/tests/frontends/mpd/protocol/current_playlist_test.py index 4aed5de1..63c4a42b 100644 --- a/tests/frontends/mpd/protocol/current_playlist_test.py +++ b/tests/frontends/mpd/protocol/current_playlist_test.py @@ -6,15 +6,15 @@ from tests.frontends.mpd import protocol class CurrentPlaylistHandlerTest(protocol.BaseTestCase): def test_add(self): needle = Track(uri='dummy://foo') - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(), Track(), needle, Track()] - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'add "dummy://foo"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 6) - self.assertEqual(self.backend.current_playlist.tracks.get()[5], needle) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 6) + self.assertEqual(self.core.current_playlist.tracks.get()[5], needle) self.assertEqualResponse(u'OK') def test_add_with_uri_not_found_in_library_should_ack(self): @@ -29,17 +29,17 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): def test_addid_without_songpos(self): needle = Track(uri='dummy://foo') - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(), Track(), needle, Track()] - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'addid "dummy://foo"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 6) - self.assertEqual(self.backend.current_playlist.tracks.get()[5], needle) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 6) + self.assertEqual(self.core.current_playlist.tracks.get()[5], needle) self.assertInResponse(u'Id: %d' % - self.backend.current_playlist.cp_tracks.get()[5][0]) + self.core.current_playlist.cp_tracks.get()[5][0]) self.assertInResponse(u'OK') def test_addid_with_empty_uri_acks(self): @@ -48,26 +48,26 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): def test_addid_with_songpos(self): needle = Track(uri='dummy://foo') - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(), Track(), needle, Track()] - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'addid "dummy://foo" "3"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 6) - self.assertEqual(self.backend.current_playlist.tracks.get()[3], needle) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 6) + self.assertEqual(self.core.current_playlist.tracks.get()[3], needle) self.assertInResponse(u'Id: %d' % - self.backend.current_playlist.cp_tracks.get()[3][0]) + self.core.current_playlist.cp_tracks.get()[3][0]) self.assertInResponse(u'OK') def test_addid_with_songpos_out_of_bounds_should_ack(self): needle = Track(uri='dummy://foo') - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(), Track(), needle, Track()] - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'addid "dummy://foo" "6"') self.assertEqualResponse(u'ACK [2@0] {addid} Bad song index') @@ -77,85 +77,85 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertEqualResponse(u'ACK [50@0] {addid} No such song') def test_clear(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'clear') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 0) - self.assertEqual(self.backend.playback.current_track.get(), None) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 0) + self.assertEqual(self.core.playback.current_track.get(), None) self.assertInResponse(u'OK') def test_delete_songpos(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'delete "%d"' % - self.backend.current_playlist.cp_tracks.get()[2][0]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 4) + self.core.current_playlist.cp_tracks.get()[2][0]) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 4) self.assertInResponse(u'OK') def test_delete_songpos_out_of_bounds(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'delete "5"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.assertEqualResponse(u'ACK [2@0] {delete} Bad song index') def test_delete_open_range(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'delete "1:"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 1) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 1) self.assertInResponse(u'OK') def test_delete_closed_range(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'delete "1:3"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 3) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 3) self.assertInResponse(u'OK') def test_delete_range_out_of_bounds(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(), Track(), Track(), Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.sendRequest(u'delete "5:7"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 5) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 5) self.assertEqualResponse(u'ACK [2@0] {delete} Bad song index') def test_deleteid(self): - self.backend.current_playlist.append([Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 2) + self.core.current_playlist.append([Track(), Track()]) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 2) self.sendRequest(u'deleteid "1"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 1) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 1) self.assertInResponse(u'OK') def test_deleteid_does_not_exist(self): - self.backend.current_playlist.append([Track(), Track()]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 2) + self.core.current_playlist.append([Track(), Track()]) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 2) self.sendRequest(u'deleteid "12345"') - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 2) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 2) self.assertEqualResponse(u'ACK [50@0] {deleteid} No such song') def test_move_songpos(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'move "1" "0"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'b') self.assertEqual(tracks[1].name, 'a') self.assertEqual(tracks[2].name, 'c') @@ -165,13 +165,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_move_open_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'move "2:" "0"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'c') self.assertEqual(tracks[1].name, 'd') self.assertEqual(tracks[2].name, 'e') @@ -181,13 +181,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_move_closed_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'move "1:3" "0"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'b') self.assertEqual(tracks[1].name, 'c') self.assertEqual(tracks[2].name, 'a') @@ -197,13 +197,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_moveid(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'moveid "4" "2"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'a') self.assertEqual(tracks[1].name, 'b') self.assertEqual(tracks[2].name, 'e') @@ -230,7 +230,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertEqualResponse(u'OK') def test_playlistfind_by_filename_in_current_playlist(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(uri='file:///exists')]) self.sendRequest( u'playlistfind filename "file:///exists"') @@ -240,7 +240,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_playlistid_without_songid(self): - self.backend.current_playlist.append([Track(name='a'), Track(name='b')]) + self.core.current_playlist.append([Track(name='a'), Track(name='b')]) self.sendRequest(u'playlistid') self.assertInResponse(u'Title: a') @@ -248,7 +248,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_playlistid_with_songid(self): - self.backend.current_playlist.append([Track(name='a'), Track(name='b')]) + self.core.current_playlist.append([Track(name='a'), Track(name='b')]) self.sendRequest(u'playlistid "1"') self.assertNotInResponse(u'Title: a') @@ -258,13 +258,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_playlistid_with_not_existing_songid_fails(self): - self.backend.current_playlist.append([Track(name='a'), Track(name='b')]) + self.core.current_playlist.append([Track(name='a'), Track(name='b')]) self.sendRequest(u'playlistid "25"') self.assertEqualResponse(u'ACK [50@0] {playlistid} No such song') def test_playlistinfo_without_songpos_or_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) @@ -286,8 +286,8 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): def test_playlistinfo_with_songpos(self): # Make the track's CPID not match the playlist position - self.backend.current_playlist.cp_id = 17 - self.backend.current_playlist.append([ + self.core.current_playlist.cp_id = 17 + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) @@ -313,7 +313,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertEqual(response1, response2) def test_playlistinfo_with_open_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) @@ -334,7 +334,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_playlistinfo_with_closed_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) @@ -365,7 +365,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertEqualResponse(u'ACK [0@0] {} Not implemented') def test_plchanges(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(name='a'), Track(name='b'), Track(name='c')]) self.sendRequest(u'plchanges "0"') @@ -375,7 +375,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_plchanges_with_minus_one_returns_entire_playlist(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(name='a'), Track(name='b'), Track(name='c')]) self.sendRequest(u'plchanges "-1"') @@ -385,7 +385,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_plchanges_without_quotes_works(self): - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(name='a'), Track(name='b'), Track(name='c')]) self.sendRequest(u'plchanges 0') @@ -395,10 +395,10 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_plchangesposid(self): - self.backend.current_playlist.append([Track(), Track(), Track()]) + self.core.current_playlist.append([Track(), Track(), Track()]) self.sendRequest(u'plchangesposid "0"') - cp_tracks = self.backend.current_playlist.cp_tracks.get() + cp_tracks = self.core.current_playlist.cp_tracks.get() self.assertInResponse(u'cpos: 0') self.assertInResponse(u'Id: %d' % cp_tracks[0][0]) self.assertInResponse(u'cpos: 2') @@ -408,26 +408,26 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_shuffle_without_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) - version = self.backend.current_playlist.version.get() + version = self.core.current_playlist.version.get() self.sendRequest(u'shuffle') - self.assertLess(version, self.backend.current_playlist.version.get()) + self.assertLess(version, self.core.current_playlist.version.get()) self.assertInResponse(u'OK') def test_shuffle_with_open_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) - version = self.backend.current_playlist.version.get() + version = self.core.current_playlist.version.get() self.sendRequest(u'shuffle "4:"') - self.assertLess(version, self.backend.current_playlist.version.get()) - tracks = self.backend.current_playlist.tracks.get() + self.assertLess(version, self.core.current_playlist.version.get()) + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'a') self.assertEqual(tracks[1].name, 'b') self.assertEqual(tracks[2].name, 'c') @@ -435,15 +435,15 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_shuffle_with_closed_range(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) - version = self.backend.current_playlist.version.get() + version = self.core.current_playlist.version.get() self.sendRequest(u'shuffle "1:3"') - self.assertLess(version, self.backend.current_playlist.version.get()) - tracks = self.backend.current_playlist.tracks.get() + self.assertLess(version, self.core.current_playlist.version.get()) + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'a') self.assertEqual(tracks[3].name, 'd') self.assertEqual(tracks[4].name, 'e') @@ -451,13 +451,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_swap(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'swap "1" "4"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'a') self.assertEqual(tracks[1].name, 'e') self.assertEqual(tracks[2].name, 'c') @@ -467,13 +467,13 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_swapid(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(name='a'), Track(name='b'), Track(name='c'), Track(name='d'), Track(name='e'), Track(name='f'), ]) self.sendRequest(u'swapid "1" "4"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(tracks[0].name, 'a') self.assertEqual(tracks[1].name, 'e') self.assertEqual(tracks[2].name, 'c') diff --git a/tests/frontends/mpd/protocol/playback_test.py b/tests/frontends/mpd/protocol/playback_test.py index 112a13ae..2380c7bc 100644 --- a/tests/frontends/mpd/protocol/playback_test.py +++ b/tests/frontends/mpd/protocol/playback_test.py @@ -13,22 +13,22 @@ STOPPED = PlaybackState.STOPPED class PlaybackOptionsHandlerTest(protocol.BaseTestCase): def test_consume_off(self): self.sendRequest(u'consume "0"') - self.assertFalse(self.backend.playback.consume.get()) + self.assertFalse(self.core.playback.consume.get()) self.assertInResponse(u'OK') def test_consume_off_without_quotes(self): self.sendRequest(u'consume 0') - self.assertFalse(self.backend.playback.consume.get()) + self.assertFalse(self.core.playback.consume.get()) self.assertInResponse(u'OK') def test_consume_on(self): self.sendRequest(u'consume "1"') - self.assertTrue(self.backend.playback.consume.get()) + self.assertTrue(self.core.playback.consume.get()) self.assertInResponse(u'OK') def test_consume_on_without_quotes(self): self.sendRequest(u'consume 1') - self.assertTrue(self.backend.playback.consume.get()) + self.assertTrue(self.core.playback.consume.get()) self.assertInResponse(u'OK') def test_crossfade(self): @@ -37,97 +37,97 @@ class PlaybackOptionsHandlerTest(protocol.BaseTestCase): def test_random_off(self): self.sendRequest(u'random "0"') - self.assertFalse(self.backend.playback.random.get()) + self.assertFalse(self.core.playback.random.get()) self.assertInResponse(u'OK') def test_random_off_without_quotes(self): self.sendRequest(u'random 0') - self.assertFalse(self.backend.playback.random.get()) + self.assertFalse(self.core.playback.random.get()) self.assertInResponse(u'OK') def test_random_on(self): self.sendRequest(u'random "1"') - self.assertTrue(self.backend.playback.random.get()) + self.assertTrue(self.core.playback.random.get()) self.assertInResponse(u'OK') def test_random_on_without_quotes(self): self.sendRequest(u'random 1') - self.assertTrue(self.backend.playback.random.get()) + self.assertTrue(self.core.playback.random.get()) self.assertInResponse(u'OK') def test_repeat_off(self): self.sendRequest(u'repeat "0"') - self.assertFalse(self.backend.playback.repeat.get()) + self.assertFalse(self.core.playback.repeat.get()) self.assertInResponse(u'OK') def test_repeat_off_without_quotes(self): self.sendRequest(u'repeat 0') - self.assertFalse(self.backend.playback.repeat.get()) + self.assertFalse(self.core.playback.repeat.get()) self.assertInResponse(u'OK') def test_repeat_on(self): self.sendRequest(u'repeat "1"') - self.assertTrue(self.backend.playback.repeat.get()) + self.assertTrue(self.core.playback.repeat.get()) self.assertInResponse(u'OK') def test_repeat_on_without_quotes(self): self.sendRequest(u'repeat 1') - self.assertTrue(self.backend.playback.repeat.get()) + self.assertTrue(self.core.playback.repeat.get()) self.assertInResponse(u'OK') def test_setvol_below_min(self): self.sendRequest(u'setvol "-10"') - self.assertEqual(0, self.backend.playback.volume.get()) + self.assertEqual(0, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_min(self): self.sendRequest(u'setvol "0"') - self.assertEqual(0, self.backend.playback.volume.get()) + self.assertEqual(0, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_middle(self): self.sendRequest(u'setvol "50"') - self.assertEqual(50, self.backend.playback.volume.get()) + self.assertEqual(50, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_max(self): self.sendRequest(u'setvol "100"') - self.assertEqual(100, self.backend.playback.volume.get()) + self.assertEqual(100, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_above_max(self): self.sendRequest(u'setvol "110"') - self.assertEqual(100, self.backend.playback.volume.get()) + self.assertEqual(100, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_plus_is_ignored(self): self.sendRequest(u'setvol "+10"') - self.assertEqual(10, self.backend.playback.volume.get()) + self.assertEqual(10, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_setvol_without_quotes(self): self.sendRequest(u'setvol 50') - self.assertEqual(50, self.backend.playback.volume.get()) + self.assertEqual(50, self.core.playback.volume.get()) self.assertInResponse(u'OK') def test_single_off(self): self.sendRequest(u'single "0"') - self.assertFalse(self.backend.playback.single.get()) + self.assertFalse(self.core.playback.single.get()) self.assertInResponse(u'OK') def test_single_off_without_quotes(self): self.sendRequest(u'single 0') - self.assertFalse(self.backend.playback.single.get()) + self.assertFalse(self.core.playback.single.get()) self.assertInResponse(u'OK') def test_single_on(self): self.sendRequest(u'single "1"') - self.assertTrue(self.backend.playback.single.get()) + self.assertTrue(self.core.playback.single.get()) self.assertInResponse(u'OK') def test_single_on_without_quotes(self): self.sendRequest(u'single 1') - self.assertTrue(self.backend.playback.single.get()) + self.assertTrue(self.core.playback.single.get()) self.assertInResponse(u'OK') def test_replay_gain_mode_off(self): @@ -166,198 +166,198 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_pause_off(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'play "0"') self.sendRequest(u'pause "1"') self.sendRequest(u'pause "0"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_pause_on(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'play "0"') self.sendRequest(u'pause "1"') - self.assertEqual(PAUSED, self.backend.playback.state.get()) + self.assertEqual(PAUSED, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_pause_toggle(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'play "0"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') self.sendRequest(u'pause') - self.assertEqual(PAUSED, self.backend.playback.state.get()) + self.assertEqual(PAUSED, self.core.playback.state.get()) self.assertInResponse(u'OK') self.sendRequest(u'pause') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_play_without_pos(self): - self.backend.current_playlist.append([Track()]) - self.backend.playback.state = PAUSED + self.core.current_playlist.append([Track()]) + self.core.playback.state = PAUSED self.sendRequest(u'play') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_play_with_pos(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'play "0"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_play_with_pos_without_quotes(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'play 0') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_play_with_pos_out_of_bounds(self): - self.backend.current_playlist.append([]) + self.core.current_playlist.append([]) self.sendRequest(u'play "0"') - self.assertEqual(STOPPED, self.backend.playback.state.get()) + self.assertEqual(STOPPED, self.core.playback.state.get()) self.assertInResponse(u'ACK [2@0] {play} Bad song index') def test_play_minus_one_plays_first_in_playlist_if_no_current_track(self): - self.assertEqual(self.backend.playback.current_track.get(), None) - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEqual(self.core.playback.current_track.get(), None) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) self.sendRequest(u'play "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertEqual('a', self.backend.playback.current_track.get().uri) + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertEqual('a', self.core.playback.current_track.get().uri) self.assertInResponse(u'OK') def test_play_minus_one_plays_current_track_if_current_track_is_set(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEqual(self.backend.playback.current_track.get(), None) - self.backend.playback.play() - self.backend.playback.next() - self.backend.playback.stop() - self.assertNotEqual(self.backend.playback.current_track.get(), None) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEqual(self.core.playback.current_track.get(), None) + self.core.playback.play() + self.core.playback.next() + self.core.playback.stop() + self.assertNotEqual(self.core.playback.current_track.get(), None) self.sendRequest(u'play "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertEqual('b', self.backend.playback.current_track.get().uri) + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertEqual('b', self.core.playback.current_track.get().uri) self.assertInResponse(u'OK') def test_play_minus_one_on_empty_playlist_does_not_ack(self): - self.backend.current_playlist.clear() + self.core.current_playlist.clear() self.sendRequest(u'play "-1"') - self.assertEqual(STOPPED, self.backend.playback.state.get()) - self.assertEqual(None, self.backend.playback.current_track.get()) + self.assertEqual(STOPPED, self.core.playback.state.get()) + self.assertEqual(None, self.core.playback.current_track.get()) self.assertInResponse(u'OK') def test_play_minus_is_ignored_if_playing(self): - self.backend.current_playlist.append([Track(length=40000)]) - self.backend.playback.seek(30000) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.core.current_playlist.append([Track(length=40000)]) + self.core.playback.seek(30000) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) - self.assertEquals(PLAYING, self.backend.playback.state.get()) + self.assertEquals(PLAYING, self.core.playback.state.get()) self.sendRequest(u'play "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_play_minus_one_resumes_if_paused(self): - self.backend.current_playlist.append([Track(length=40000)]) - self.backend.playback.seek(30000) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.core.current_playlist.append([Track(length=40000)]) + self.core.playback.seek(30000) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) - self.assertEquals(PLAYING, self.backend.playback.state.get()) - self.backend.playback.pause() - self.assertEquals(PAUSED, self.backend.playback.state.get()) + self.assertEquals(PLAYING, self.core.playback.state.get()) + self.core.playback.pause() + self.assertEquals(PAUSED, self.core.playback.state.get()) self.sendRequest(u'play "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_playid(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'playid "0"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_playid_without_quotes(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'playid 0') - self.assertEqual(PLAYING, self.backend.playback.state.get()) + self.assertEqual(PLAYING, self.core.playback.state.get()) self.assertInResponse(u'OK') def test_playid_minus_one_plays_first_in_playlist_if_no_current_track(self): - self.assertEqual(self.backend.playback.current_track.get(), None) - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEqual(self.core.playback.current_track.get(), None) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) self.sendRequest(u'playid "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertEqual('a', self.backend.playback.current_track.get().uri) + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertEqual('a', self.core.playback.current_track.get().uri) self.assertInResponse(u'OK') def test_playid_minus_one_plays_current_track_if_current_track_is_set(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEqual(self.backend.playback.current_track.get(), None) - self.backend.playback.play() - self.backend.playback.next() - self.backend.playback.stop() - self.assertNotEqual(None, self.backend.playback.current_track.get()) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEqual(self.core.playback.current_track.get(), None) + self.core.playback.play() + self.core.playback.next() + self.core.playback.stop() + self.assertNotEqual(None, self.core.playback.current_track.get()) self.sendRequest(u'playid "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertEqual('b', self.backend.playback.current_track.get().uri) + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertEqual('b', self.core.playback.current_track.get().uri) self.assertInResponse(u'OK') def test_playid_minus_one_on_empty_playlist_does_not_ack(self): - self.backend.current_playlist.clear() + self.core.current_playlist.clear() self.sendRequest(u'playid "-1"') - self.assertEqual(STOPPED, self.backend.playback.state.get()) - self.assertEqual(None, self.backend.playback.current_track.get()) + self.assertEqual(STOPPED, self.core.playback.state.get()) + self.assertEqual(None, self.core.playback.current_track.get()) self.assertInResponse(u'OK') def test_playid_minus_is_ignored_if_playing(self): - self.backend.current_playlist.append([Track(length=40000)]) - self.backend.playback.seek(30000) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.core.current_playlist.append([Track(length=40000)]) + self.core.playback.seek(30000) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) - self.assertEquals(PLAYING, self.backend.playback.state.get()) + self.assertEquals(PLAYING, self.core.playback.state.get()) self.sendRequest(u'playid "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_playid_minus_one_resumes_if_paused(self): - self.backend.current_playlist.append([Track(length=40000)]) - self.backend.playback.seek(30000) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.core.current_playlist.append([Track(length=40000)]) + self.core.playback.seek(30000) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) - self.assertEquals(PLAYING, self.backend.playback.state.get()) - self.backend.playback.pause() - self.assertEquals(PAUSED, self.backend.playback.state.get()) + self.assertEquals(PLAYING, self.core.playback.state.get()) + self.core.playback.pause() + self.assertEquals(PAUSED, self.core.playback.state.get()) self.sendRequest(u'playid "-1"') - self.assertEqual(PLAYING, self.backend.playback.state.get()) - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertEqual(PLAYING, self.core.playback.state.get()) + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_playid_which_does_not_exist(self): - self.backend.current_playlist.append([Track()]) + self.core.current_playlist.append([Track()]) self.sendRequest(u'playid "12345"') self.assertInResponse(u'ACK [50@0] {playid} No such song') @@ -367,49 +367,49 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_seek(self): - self.backend.current_playlist.append([Track(length=40000)]) + self.core.current_playlist.append([Track(length=40000)]) self.sendRequest(u'seek "0"') self.sendRequest(u'seek "0" "30"') - self.assertGreaterEqual(self.backend.playback.time_position, 30000) + self.assertGreaterEqual(self.core.playback.time_position, 30000) self.assertInResponse(u'OK') def test_seek_with_songpos(self): seek_track = Track(uri='2', length=40000) - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(uri='1', length=40000), seek_track]) self.sendRequest(u'seek "1" "30"') - self.assertEqual(self.backend.playback.current_track.get(), seek_track) + self.assertEqual(self.core.playback.current_track.get(), seek_track) self.assertInResponse(u'OK') def test_seek_without_quotes(self): - self.backend.current_playlist.append([Track(length=40000)]) + self.core.current_playlist.append([Track(length=40000)]) self.sendRequest(u'seek 0') self.sendRequest(u'seek 0 30') - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_seekid(self): - self.backend.current_playlist.append([Track(length=40000)]) + self.core.current_playlist.append([Track(length=40000)]) self.sendRequest(u'seekid "0" "30"') - self.assertGreaterEqual(self.backend.playback.time_position.get(), + self.assertGreaterEqual(self.core.playback.time_position.get(), 30000) self.assertInResponse(u'OK') def test_seekid_with_cpid(self): seek_track = Track(uri='2', length=40000) - self.backend.current_playlist.append( + self.core.current_playlist.append( [Track(length=40000), seek_track]) self.sendRequest(u'seekid "1" "30"') - self.assertEqual(1, self.backend.playback.current_cpid.get()) - self.assertEqual(seek_track, self.backend.playback.current_track.get()) + self.assertEqual(1, self.core.playback.current_cpid.get()) + self.assertEqual(seek_track, self.core.playback.current_track.get()) self.assertInResponse(u'OK') def test_stop(self): self.sendRequest(u'stop') - self.assertEqual(STOPPED, self.backend.playback.state.get()) + self.assertEqual(STOPPED, self.core.playback.state.get()) self.assertInResponse(u'OK') diff --git a/tests/frontends/mpd/protocol/regression_test.py b/tests/frontends/mpd/protocol/regression_test.py index 7f214efa..90bcaf60 100644 --- a/tests/frontends/mpd/protocol/regression_test.py +++ b/tests/frontends/mpd/protocol/regression_test.py @@ -16,23 +16,23 @@ class IssueGH17RegressionTest(protocol.BaseTestCase): - Press next until you get to the unplayable track """ def test(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(uri='a'), Track(uri='b'), None, Track(uri='d'), Track(uri='e'), Track(uri='f')]) random.seed(1) # Playlist order: abcfde self.sendRequest(u'play') - self.assertEquals('a', self.backend.playback.current_track.get().uri) + self.assertEquals('a', self.core.playback.current_track.get().uri) self.sendRequest(u'random "1"') self.sendRequest(u'next') - self.assertEquals('b', self.backend.playback.current_track.get().uri) + self.assertEquals('b', self.core.playback.current_track.get().uri) self.sendRequest(u'next') # Should now be at track 'c', but playback fails and it skips ahead - self.assertEquals('f', self.backend.playback.current_track.get().uri) + self.assertEquals('f', self.core.playback.current_track.get().uri) self.sendRequest(u'next') - self.assertEquals('d', self.backend.playback.current_track.get().uri) + self.assertEquals('d', self.core.playback.current_track.get().uri) self.sendRequest(u'next') - self.assertEquals('e', self.backend.playback.current_track.get().uri) + self.assertEquals('e', self.core.playback.current_track.get().uri) class IssueGH18RegressionTest(protocol.BaseTestCase): @@ -47,7 +47,7 @@ class IssueGH18RegressionTest(protocol.BaseTestCase): """ def test(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(uri='a'), Track(uri='b'), Track(uri='c'), Track(uri='d'), Track(uri='e'), Track(uri='f')]) random.seed(1) @@ -59,11 +59,11 @@ class IssueGH18RegressionTest(protocol.BaseTestCase): self.sendRequest(u'next') self.sendRequest(u'next') - cp_track_1 = self.backend.playback.current_cp_track.get() + cp_track_1 = self.core.playback.current_cp_track.get() self.sendRequest(u'next') - cp_track_2 = self.backend.playback.current_cp_track.get() + cp_track_2 = self.core.playback.current_cp_track.get() self.sendRequest(u'next') - cp_track_3 = self.backend.playback.current_cp_track.get() + cp_track_3 = self.core.playback.current_cp_track.get() self.assertNotEqual(cp_track_1, cp_track_2) self.assertNotEqual(cp_track_2, cp_track_3) @@ -83,7 +83,7 @@ class IssueGH22RegressionTest(protocol.BaseTestCase): """ def test(self): - self.backend.current_playlist.append([ + self.core.current_playlist.append([ Track(uri='a'), Track(uri='b'), Track(uri='c'), Track(uri='d'), Track(uri='e'), Track(uri='f')]) random.seed(1) @@ -111,8 +111,8 @@ class IssueGH69RegressionTest(protocol.BaseTestCase): """ def test(self): - self.backend.stored_playlists.create('foo') - self.backend.current_playlist.append([ + self.core.stored_playlists.create('foo') + self.core.current_playlist.append([ Track(uri='a'), Track(uri='b'), Track(uri='c'), Track(uri='d'), Track(uri='e'), Track(uri='f')]) @@ -136,7 +136,7 @@ class IssueGH113RegressionTest(protocol.BaseTestCase): """ def test(self): - self.backend.stored_playlists.create( + self.core.stored_playlists.create( u'all lart spotify:track:\w\{22\} pastes') self.sendRequest(u'lsinfo "/"') diff --git a/tests/frontends/mpd/protocol/status_test.py b/tests/frontends/mpd/protocol/status_test.py index e6572eab..e2f0df9c 100644 --- a/tests/frontends/mpd/protocol/status_test.py +++ b/tests/frontends/mpd/protocol/status_test.py @@ -10,8 +10,8 @@ class StatusHandlerTest(protocol.BaseTestCase): def test_currentsong(self): track = Track() - self.backend.current_playlist.append([track]) - self.backend.playback.play() + self.core.current_playlist.append([track]) + self.core.playback.play() self.sendRequest(u'currentsong') self.assertInResponse(u'file: ') self.assertInResponse(u'Time: 0') diff --git a/tests/frontends/mpd/protocol/stored_playlists_test.py b/tests/frontends/mpd/protocol/stored_playlists_test.py index 45d6a09a..0bf9756f 100644 --- a/tests/frontends/mpd/protocol/stored_playlists_test.py +++ b/tests/frontends/mpd/protocol/stored_playlists_test.py @@ -7,7 +7,7 @@ from tests.frontends.mpd import protocol class StoredPlaylistsHandlerTest(protocol.BaseTestCase): def test_listplaylist(self): - self.backend.stored_playlists.playlists = [ + self.core.stored_playlists.playlists = [ Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])] self.sendRequest(u'listplaylist "name"') @@ -19,7 +19,7 @@ class StoredPlaylistsHandlerTest(protocol.BaseTestCase): self.assertEqualResponse(u'ACK [50@0] {listplaylist} No such playlist') def test_listplaylistinfo(self): - self.backend.stored_playlists.playlists = [ + self.core.stored_playlists.playlists = [ Playlist(name='name', tracks=[Track(uri='file:///dev/urandom')])] self.sendRequest(u'listplaylistinfo "name"') @@ -35,7 +35,7 @@ class StoredPlaylistsHandlerTest(protocol.BaseTestCase): def test_listplaylists(self): last_modified = datetime.datetime(2001, 3, 17, 13, 41, 17, 12345) - self.backend.stored_playlists.playlists = [Playlist(name='a', + self.core.stored_playlists.playlists = [Playlist(name='a', last_modified=last_modified)] self.sendRequest(u'listplaylists') @@ -45,13 +45,13 @@ class StoredPlaylistsHandlerTest(protocol.BaseTestCase): self.assertInResponse(u'OK') def test_load_known_playlist_appends_to_current_playlist(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEqual(len(self.backend.current_playlist.tracks.get()), 2) - self.backend.stored_playlists.playlists = [Playlist(name='A-list', + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEqual(len(self.core.current_playlist.tracks.get()), 2) + self.core.stored_playlists.playlists = [Playlist(name='A-list', tracks=[Track(uri='c'), Track(uri='d'), Track(uri='e')])] self.sendRequest(u'load "A-list"') - tracks = self.backend.current_playlist.tracks.get() + tracks = self.core.current_playlist.tracks.get() self.assertEqual(5, len(tracks)) self.assertEqual('a', tracks[0].uri) self.assertEqual('b', tracks[1].uri) @@ -62,7 +62,7 @@ class StoredPlaylistsHandlerTest(protocol.BaseTestCase): def test_load_unknown_playlist_acks(self): self.sendRequest(u'load "unknown playlist"') - self.assertEqual(0, len(self.backend.current_playlist.tracks.get())) + self.assertEqual(0, len(self.core.current_playlist.tracks.get())) self.assertEqualResponse(u'ACK [50@0] {load} No such playlist') def test_playlistadd(self): diff --git a/tests/frontends/mpd/status_test.py b/tests/frontends/mpd/status_test.py index 2397b96f..3a5bdcbe 100644 --- a/tests/frontends/mpd/status_test.py +++ b/tests/frontends/mpd/status_test.py @@ -1,3 +1,6 @@ +from pykka.registry import ActorRegistry + +from mopidy import audio, core from mopidy.backends import dummy from mopidy.core import PlaybackState from mopidy.frontends.mpd import dispatcher @@ -17,12 +20,13 @@ STOPPED = PlaybackState.STOPPED class StatusHandlerTest(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start().proxy() + self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.core = core.Core.start(backend=self.backend).proxy() self.dispatcher = dispatcher.MpdDispatcher() self.context = self.dispatcher.context def tearDown(self): - self.backend.stop().get() + ActorRegistry.stop_all() def test_stats_method(self): result = status.stats(self.context) @@ -47,7 +51,7 @@ class StatusHandlerTest(unittest.TestCase): self.assertEqual(int(result['volume']), -1) def test_status_method_contains_volume(self): - self.backend.playback.volume = 17 + self.core.playback.volume = 17 result = dict(status.status(self.context)) self.assertIn('volume', result) self.assertEqual(int(result['volume']), 17) @@ -58,7 +62,7 @@ class StatusHandlerTest(unittest.TestCase): self.assertEqual(int(result['repeat']), 0) def test_status_method_contains_repeat_is_1(self): - self.backend.playback.repeat = 1 + self.core.playback.repeat = 1 result = dict(status.status(self.context)) self.assertIn('repeat', result) self.assertEqual(int(result['repeat']), 1) @@ -69,7 +73,7 @@ class StatusHandlerTest(unittest.TestCase): self.assertEqual(int(result['random']), 0) def test_status_method_contains_random_is_1(self): - self.backend.playback.random = 1 + self.core.playback.random = 1 result = dict(status.status(self.context)) self.assertIn('random', result) self.assertEqual(int(result['random']), 1) @@ -85,7 +89,7 @@ class StatusHandlerTest(unittest.TestCase): self.assertEqual(int(result['consume']), 0) def test_status_method_contains_consume_is_1(self): - self.backend.playback.consume = 1 + self.core.playback.consume = 1 result = dict(status.status(self.context)) self.assertIn('consume', result) self.assertEqual(int(result['consume']), 1) @@ -106,41 +110,41 @@ class StatusHandlerTest(unittest.TestCase): self.assertGreaterEqual(int(result['xfade']), 0) def test_status_method_contains_state_is_play(self): - self.backend.playback.state = PLAYING + self.core.playback.state = PLAYING result = dict(status.status(self.context)) self.assertIn('state', result) self.assertEqual(result['state'], 'play') def test_status_method_contains_state_is_stop(self): - self.backend.playback.state = STOPPED + self.core.playback.state = STOPPED result = dict(status.status(self.context)) self.assertIn('state', result) self.assertEqual(result['state'], 'stop') def test_status_method_contains_state_is_pause(self): - self.backend.playback.state = PLAYING - self.backend.playback.state = PAUSED + self.core.playback.state = PLAYING + self.core.playback.state = PAUSED result = dict(status.status(self.context)) self.assertIn('state', result) self.assertEqual(result['state'], 'pause') def test_status_method_when_playlist_loaded_contains_song(self): - self.backend.current_playlist.append([Track()]) - self.backend.playback.play() + self.core.current_playlist.append([Track()]) + self.core.playback.play() result = dict(status.status(self.context)) self.assertIn('song', result) self.assertGreaterEqual(int(result['song']), 0) def test_status_method_when_playlist_loaded_contains_cpid_as_songid(self): - self.backend.current_playlist.append([Track()]) - self.backend.playback.play() + self.core.current_playlist.append([Track()]) + self.core.playback.play() result = dict(status.status(self.context)) self.assertIn('songid', result) self.assertEqual(int(result['songid']), 0) def test_status_method_when_playing_contains_time_with_no_length(self): - self.backend.current_playlist.append([Track(length=None)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(length=None)]) + self.core.playback.play() result = dict(status.status(self.context)) self.assertIn('time', result) (position, total) = result['time'].split(':') @@ -149,8 +153,8 @@ class StatusHandlerTest(unittest.TestCase): self.assertLessEqual(position, total) def test_status_method_when_playing_contains_time_with_length(self): - self.backend.current_playlist.append([Track(length=10000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(length=10000)]) + self.core.playback.play() result = dict(status.status(self.context)) self.assertIn('time', result) (position, total) = result['time'].split(':') @@ -159,25 +163,25 @@ class StatusHandlerTest(unittest.TestCase): self.assertLessEqual(position, total) def test_status_method_when_playing_contains_elapsed(self): - self.backend.current_playlist.append([Track(length=60000)]) - self.backend.playback.play() - self.backend.playback.pause() - self.backend.playback.seek(59123) + self.core.current_playlist.append([Track(length=60000)]) + self.core.playback.play() + self.core.playback.pause() + self.core.playback.seek(59123) result = dict(status.status(self.context)) self.assertIn('elapsed', result) self.assertEqual(result['elapsed'], '59.123') def test_status_method_when_starting_playing_contains_elapsed_zero(self): - self.backend.current_playlist.append([Track(length=10000)]) - self.backend.playback.play() - self.backend.playback.pause() + self.core.current_playlist.append([Track(length=10000)]) + self.core.playback.play() + self.core.playback.pause() result = dict(status.status(self.context)) self.assertIn('elapsed', result) self.assertEqual(result['elapsed'], '0.000') def test_status_method_when_playing_contains_bitrate(self): - self.backend.current_playlist.append([Track(bitrate=320)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(bitrate=320)]) + self.core.playback.play() result = dict(status.status(self.context)) self.assertIn('bitrate', result) self.assertEqual(int(result['bitrate']), 320) diff --git a/tests/frontends/mpris/player_interface_test.py b/tests/frontends/mpris/player_interface_test.py index 89f7f1d4..236ec645 100644 --- a/tests/frontends/mpris/player_interface_test.py +++ b/tests/frontends/mpris/player_interface_test.py @@ -2,8 +2,10 @@ import sys import mock -from mopidy import OptionalDependencyError -from mopidy.backends.dummy import DummyBackend +from pykka.registry import ActorRegistry + +from mopidy import core, OptionalDependencyError +from mopidy.backends import dummy from mopidy.core import PlaybackState from mopidy.models import Album, Artist, Track @@ -23,68 +25,69 @@ STOPPED = PlaybackState.STOPPED class PlayerInterfaceTest(unittest.TestCase): def setUp(self): objects.MprisObject._connect_to_dbus = mock.Mock() - self.backend = DummyBackend.start().proxy() + self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.core = core.Core.start(backend=self.backend).proxy() self.mpris = objects.MprisObject() - self.mpris._backend = self.backend + self.mpris._core = self.core def tearDown(self): - self.backend.stop() + ActorRegistry.stop_all() def test_get_playback_status_is_playing_when_playing(self): - self.backend.playback.state = PLAYING + self.core.playback.state = PLAYING result = self.mpris.Get(objects.PLAYER_IFACE, 'PlaybackStatus') self.assertEqual('Playing', result) def test_get_playback_status_is_paused_when_paused(self): - self.backend.playback.state = PAUSED + self.core.playback.state = PAUSED result = self.mpris.Get(objects.PLAYER_IFACE, 'PlaybackStatus') self.assertEqual('Paused', result) def test_get_playback_status_is_stopped_when_stopped(self): - self.backend.playback.state = STOPPED + self.core.playback.state = STOPPED result = self.mpris.Get(objects.PLAYER_IFACE, 'PlaybackStatus') self.assertEqual('Stopped', result) def test_get_loop_status_is_none_when_not_looping(self): - self.backend.playback.repeat = False - self.backend.playback.single = False + self.core.playback.repeat = False + self.core.playback.single = False result = self.mpris.Get(objects.PLAYER_IFACE, 'LoopStatus') self.assertEqual('None', result) def test_get_loop_status_is_track_when_looping_a_single_track(self): - self.backend.playback.repeat = True - self.backend.playback.single = True + self.core.playback.repeat = True + self.core.playback.single = True result = self.mpris.Get(objects.PLAYER_IFACE, 'LoopStatus') self.assertEqual('Track', result) def test_get_loop_status_is_playlist_when_looping_the_current_playlist(self): - self.backend.playback.repeat = True - self.backend.playback.single = False + self.core.playback.repeat = True + self.core.playback.single = False result = self.mpris.Get(objects.PLAYER_IFACE, 'LoopStatus') self.assertEqual('Playlist', result) def test_set_loop_status_is_ignored_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.playback.repeat = True - self.backend.playback.single = True + self.core.playback.repeat = True + self.core.playback.single = True self.mpris.Set(objects.PLAYER_IFACE, 'LoopStatus', 'None') - self.assertEquals(self.backend.playback.repeat.get(), True) - self.assertEquals(self.backend.playback.single.get(), True) + self.assertEquals(self.core.playback.repeat.get(), True) + self.assertEquals(self.core.playback.single.get(), True) def test_set_loop_status_to_none_unsets_repeat_and_single(self): self.mpris.Set(objects.PLAYER_IFACE, 'LoopStatus', 'None') - self.assertEquals(self.backend.playback.repeat.get(), False) - self.assertEquals(self.backend.playback.single.get(), False) + self.assertEquals(self.core.playback.repeat.get(), False) + self.assertEquals(self.core.playback.single.get(), False) def test_set_loop_status_to_track_sets_repeat_and_single(self): self.mpris.Set(objects.PLAYER_IFACE, 'LoopStatus', 'Track') - self.assertEquals(self.backend.playback.repeat.get(), True) - self.assertEquals(self.backend.playback.single.get(), True) + self.assertEquals(self.core.playback.repeat.get(), True) + self.assertEquals(self.core.playback.single.get(), True) def test_set_loop_status_to_playlists_sets_repeat_and_not_single(self): self.mpris.Set(objects.PLAYER_IFACE, 'LoopStatus', 'Playlist') - self.assertEquals(self.backend.playback.repeat.get(), True) - self.assertEquals(self.backend.playback.single.get(), False) + self.assertEquals(self.core.playback.repeat.get(), True) + self.assertEquals(self.core.playback.single.get(), False) def test_get_rate_is_greater_or_equal_than_minimum_rate(self): rate = self.mpris.Get(objects.PLAYER_IFACE, 'Rate') @@ -98,46 +101,46 @@ class PlayerInterfaceTest(unittest.TestCase): def test_set_rate_is_ignored_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_set_rate_to_zero_pauses_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Set(objects.PLAYER_IFACE, 'Rate', 0) - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_get_shuffle_returns_true_if_random_is_active(self): - self.backend.playback.random = True + self.core.playback.random = True result = self.mpris.Get(objects.PLAYER_IFACE, 'Shuffle') self.assertTrue(result) def test_get_shuffle_returns_false_if_random_is_inactive(self): - self.backend.playback.random = False + self.core.playback.random = False result = self.mpris.Get(objects.PLAYER_IFACE, 'Shuffle') self.assertFalse(result) def test_set_shuffle_is_ignored_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.playback.random = False + self.core.playback.random = False result = self.mpris.Set(objects.PLAYER_IFACE, 'Shuffle', True) - self.assertFalse(self.backend.playback.random.get()) + self.assertFalse(self.core.playback.random.get()) def test_set_shuffle_to_true_activates_random_mode(self): - self.backend.playback.random = False - self.assertFalse(self.backend.playback.random.get()) + self.core.playback.random = False + self.assertFalse(self.core.playback.random.get()) result = self.mpris.Set(objects.PLAYER_IFACE, 'Shuffle', True) - self.assertTrue(self.backend.playback.random.get()) + self.assertTrue(self.core.playback.random.get()) def test_set_shuffle_to_false_deactivates_random_mode(self): - self.backend.playback.random = True - self.assertTrue(self.backend.playback.random.get()) + self.core.playback.random = True + self.assertTrue(self.core.playback.random.get()) result = self.mpris.Set(objects.PLAYER_IFACE, 'Shuffle', False) - self.assertFalse(self.backend.playback.random.get()) + self.assertFalse(self.core.playback.random.get()) def test_get_metadata_has_trackid_even_when_no_current_track(self): result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') @@ -145,105 +148,105 @@ class PlayerInterfaceTest(unittest.TestCase): self.assertEquals(result['mpris:trackid'], '') def test_get_metadata_has_trackid_based_on_cpid(self): - self.backend.current_playlist.append([Track(uri='a')]) - self.backend.playback.play() - (cpid, track) = self.backend.playback.current_cp_track.get() + self.core.current_playlist.append([Track(uri='a')]) + self.core.playback.play() + (cpid, track) = self.core.playback.current_cp_track.get() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('mpris:trackid', result.keys()) self.assertEquals(result['mpris:trackid'], '/com/mopidy/track/%d' % cpid) def test_get_metadata_has_track_length(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('mpris:length', result.keys()) self.assertEquals(result['mpris:length'], 40000000) def test_get_metadata_has_track_uri(self): - self.backend.current_playlist.append([Track(uri='a')]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a')]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:url', result.keys()) self.assertEquals(result['xesam:url'], 'a') def test_get_metadata_has_track_title(self): - self.backend.current_playlist.append([Track(name='a')]) - self.backend.playback.play() + self.core.current_playlist.append([Track(name='a')]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:title', result.keys()) self.assertEquals(result['xesam:title'], 'a') def test_get_metadata_has_track_artists(self): - self.backend.current_playlist.append([Track(artists=[ + self.core.current_playlist.append([Track(artists=[ Artist(name='a'), Artist(name='b'), Artist(name=None)])]) - self.backend.playback.play() + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:artist', result.keys()) self.assertEquals(result['xesam:artist'], ['a', 'b']) def test_get_metadata_has_track_album(self): - self.backend.current_playlist.append([Track(album=Album(name='a'))]) - self.backend.playback.play() + self.core.current_playlist.append([Track(album=Album(name='a'))]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:album', result.keys()) self.assertEquals(result['xesam:album'], 'a') def test_get_metadata_has_track_album_artists(self): - self.backend.current_playlist.append([Track(album=Album(artists=[ + self.core.current_playlist.append([Track(album=Album(artists=[ Artist(name='a'), Artist(name='b'), Artist(name=None)]))]) - self.backend.playback.play() + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:albumArtist', result.keys()) self.assertEquals(result['xesam:albumArtist'], ['a', 'b']) def test_get_metadata_has_track_number_in_album(self): - self.backend.current_playlist.append([Track(track_no=7)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(track_no=7)]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:trackNumber', result.keys()) self.assertEquals(result['xesam:trackNumber'], 7) def test_get_volume_should_return_volume_between_zero_and_one(self): - self.backend.playback.volume = None + self.core.playback.volume = None result = self.mpris.Get(objects.PLAYER_IFACE, 'Volume') self.assertEquals(result, 0) - self.backend.playback.volume = 0 + self.core.playback.volume = 0 result = self.mpris.Get(objects.PLAYER_IFACE, 'Volume') self.assertEquals(result, 0) - self.backend.playback.volume = 50 + self.core.playback.volume = 50 result = self.mpris.Get(objects.PLAYER_IFACE, 'Volume') self.assertEquals(result, 0.5) - self.backend.playback.volume = 100 + self.core.playback.volume = 100 result = self.mpris.Get(objects.PLAYER_IFACE, 'Volume') self.assertEquals(result, 1) def test_set_volume_is_ignored_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.playback.volume = 0 + self.core.playback.volume = 0 self.mpris.Set(objects.PLAYER_IFACE, 'Volume', 1.0) - self.assertEquals(self.backend.playback.volume.get(), 0) + self.assertEquals(self.core.playback.volume.get(), 0) def test_set_volume_to_one_should_set_mixer_volume_to_100(self): self.mpris.Set(objects.PLAYER_IFACE, 'Volume', 1.0) - self.assertEquals(self.backend.playback.volume.get(), 100) + self.assertEquals(self.core.playback.volume.get(), 100) def test_set_volume_to_anything_above_one_should_set_mixer_volume_to_100(self): self.mpris.Set(objects.PLAYER_IFACE, 'Volume', 2.0) - self.assertEquals(self.backend.playback.volume.get(), 100) + self.assertEquals(self.core.playback.volume.get(), 100) def test_set_volume_to_anything_not_a_number_does_not_change_volume(self): - self.backend.playback.volume = 10 + self.core.playback.volume = 10 self.mpris.Set(objects.PLAYER_IFACE, 'Volume', None) - self.assertEquals(self.backend.playback.volume.get(), 10) + self.assertEquals(self.core.playback.volume.get(), 10) def test_get_position_returns_time_position_in_microseconds(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(10000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(10000) result_in_microseconds = self.mpris.Get(objects.PLAYER_IFACE, 'Position') result_in_milliseconds = result_in_microseconds // 1000 self.assertGreaterEqual(result_in_milliseconds, 10000) @@ -263,61 +266,61 @@ class PlayerInterfaceTest(unittest.TestCase): def test_can_go_next_is_true_if_can_control_and_other_next_track(self): self.mpris.get_CanControl = lambda *_: True - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext') self.assertTrue(result) def test_can_go_next_is_false_if_next_track_is_the_same(self): self.mpris.get_CanControl = lambda *_: True - self.backend.current_playlist.append([Track(uri='a')]) - self.backend.playback.repeat = True - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a')]) + self.core.playback.repeat = True + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext') self.assertFalse(result) def test_can_go_next_is_false_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoNext') self.assertFalse(result) def test_can_go_previous_is_true_if_can_control_and_other_previous_track(self): self.mpris.get_CanControl = lambda *_: True - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious') self.assertTrue(result) def test_can_go_previous_is_false_if_previous_track_is_the_same(self): self.mpris.get_CanControl = lambda *_: True - self.backend.current_playlist.append([Track(uri='a')]) - self.backend.playback.repeat = True - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a')]) + self.core.playback.repeat = True + self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious') self.assertFalse(result) def test_can_go_previous_is_false_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() result = self.mpris.Get(objects.PLAYER_IFACE, 'CanGoPrevious') self.assertFalse(result) def test_can_play_is_true_if_can_control_and_current_track(self): self.mpris.get_CanControl = lambda *_: True - self.backend.current_playlist.append([Track(uri='a')]) - self.backend.playback.play() - self.assertTrue(self.backend.playback.current_track.get()) + self.core.current_playlist.append([Track(uri='a')]) + self.core.playback.play() + self.assertTrue(self.core.playback.current_track.get()) result = self.mpris.Get(objects.PLAYER_IFACE, 'CanPlay') self.assertTrue(result) def test_can_play_is_false_if_no_current_track(self): self.mpris.get_CanControl = lambda *_: True - self.assertFalse(self.backend.playback.current_track.get()) + self.assertFalse(self.core.playback.current_track.get()) result = self.mpris.Get(objects.PLAYER_IFACE, 'CanPlay') self.assertFalse(result) @@ -352,223 +355,223 @@ class PlayerInterfaceTest(unittest.TestCase): def test_next_is_ignored_if_can_go_next_is_false(self): self.mpris.get_CanGoNext = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.current_track.get().uri, 'a') self.mpris.Next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.current_track.get().uri, 'a') def test_next_when_playing_should_skip_to_next_track_and_keep_playing(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_next_when_at_end_of_list_should_stop_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Next() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_next_when_paused_should_skip_to_next_track_and_stay_paused(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.pause() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.pause() + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PAUSED) self.mpris.Next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_next_when_stopped_should_skip_to_next_track_and_stay_stopped(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.stop() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.stop() + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.Next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_previous_is_ignored_if_can_go_previous_is_false(self): self.mpris.get_CanGoPrevious = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() + self.assertEquals(self.core.playback.current_track.get().uri, 'b') self.mpris.Previous() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.current_track.get().uri, 'b') def test_previous_when_playing_should_skip_to_prev_track_and_keep_playing(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Previous() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_previous_when_at_start_of_list_should_stop_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Previous() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_previous_when_paused_should_skip_to_previous_track_and_stay_paused(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() - self.backend.playback.pause() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() + self.core.playback.pause() + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PAUSED) self.mpris.Previous() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_previous_when_stopped_should_skip_to_previous_track_and_stay_stopped(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.next() - self.backend.playback.stop() - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.next() + self.core.playback.stop() + self.assertEquals(self.core.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.Previous() - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_pause_is_ignored_if_can_pause_is_false(self): self.mpris.get_CanPause = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Pause() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_pause_when_playing_should_pause_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_pause_when_paused_has_no_effect(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.pause() + self.assertEquals(self.core.playback.state.get(), PAUSED) self.mpris.Pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_playpause_is_ignored_if_can_pause_is_false(self): self.mpris.get_CanPause = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.PlayPause() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_playpause_when_playing_should_pause_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.PlayPause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.state.get(), PAUSED) def test_playpause_when_paused_should_resume_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.pause() + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) - at_pause = self.backend.playback.time_position.get() + self.assertEquals(self.core.playback.state.get(), PAUSED) + at_pause = self.core.playback.time_position.get() self.assertGreaterEqual(at_pause, 0) self.mpris.PlayPause() - self.assertEquals(self.backend.playback.state.get(), PLAYING) - after_pause = self.backend.playback.time_position.get() + self.assertEquals(self.core.playback.state.get(), PLAYING) + after_pause = self.core.playback.time_position.get() self.assertGreaterEqual(after_pause, at_pause) def test_playpause_when_stopped_should_start_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.PlayPause() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_stop_is_ignored_if_can_control_is_false(self): self.mpris.get_CanControl = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Stop() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_stop_when_playing_should_stop_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) self.mpris.Stop() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_stop_when_paused_should_stop_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.pause() + self.assertEquals(self.core.playback.state.get(), PAUSED) self.mpris.Stop() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_play_is_ignored_if_can_play_is_false(self): self.mpris.get_CanPlay = lambda *_: False - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.Play() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_play_when_stopped_starts_playback(self): - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.Play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) def test_play_after_pause_resumes_from_same_position(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() - before_pause = self.backend.playback.time_position.get() + before_pause = self.core.playback.time_position.get() self.assertGreaterEqual(before_pause, 0) self.mpris.Pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) - at_pause = self.backend.playback.time_position.get() + self.assertEquals(self.core.playback.state.get(), PAUSED) + at_pause = self.core.playback.time_position.get() self.assertGreaterEqual(at_pause, before_pause) self.mpris.Play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) - after_pause = self.backend.playback.time_position.get() + self.assertEquals(self.core.playback.state.get(), PLAYING) + after_pause = self.core.playback.time_position.get() self.assertGreaterEqual(after_pause, at_pause) def test_play_when_there_is_no_track_has_no_effect(self): - self.backend.current_playlist.clear() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.clear() + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.Play() - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.assertEquals(self.core.playback.state.get(), STOPPED) def test_seek_is_ignored_if_can_seek_is_false(self): self.mpris.get_CanSeek = lambda *_: False - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() - before_seek = self.backend.playback.time_position.get() + before_seek = self.core.playback.time_position.get() self.assertGreaterEqual(before_seek, 0) milliseconds_to_seek = 10000 @@ -576,15 +579,15 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.Seek(microseconds_to_seek) - after_seek = self.backend.playback.time_position.get() + after_seek = self.core.playback.time_position.get() self.assertLessEqual(before_seek, after_seek) self.assertLess(after_seek, before_seek + milliseconds_to_seek) def test_seek_seeks_given_microseconds_forward_in_the_current_track(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() - before_seek = self.backend.playback.time_position.get() + before_seek = self.core.playback.time_position.get() self.assertGreaterEqual(before_seek, 0) milliseconds_to_seek = 10000 @@ -592,17 +595,17 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.Seek(microseconds_to_seek) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) - after_seek = self.backend.playback.time_position.get() + after_seek = self.core.playback.time_position.get() self.assertGreaterEqual(after_seek, before_seek + milliseconds_to_seek) def test_seek_seeks_given_microseconds_backward_if_negative(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(20000) - before_seek = self.backend.playback.time_position.get() + before_seek = self.core.playback.time_position.get() self.assertGreaterEqual(before_seek, 20000) milliseconds_to_seek = -10000 @@ -610,18 +613,18 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.Seek(microseconds_to_seek) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) - after_seek = self.backend.playback.time_position.get() + after_seek = self.core.playback.time_position.get() self.assertGreaterEqual(after_seek, before_seek + milliseconds_to_seek) self.assertLess(after_seek, before_seek) def test_seek_seeks_to_start_of_track_if_new_position_is_negative(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(20000) - before_seek = self.backend.playback.time_position.get() + before_seek = self.core.playback.time_position.get() self.assertGreaterEqual(before_seek, 20000) milliseconds_to_seek = -30000 @@ -629,42 +632,42 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.Seek(microseconds_to_seek) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) - after_seek = self.backend.playback.time_position.get() + after_seek = self.core.playback.time_position.get() self.assertGreaterEqual(after_seek, before_seek + milliseconds_to_seek) self.assertLess(after_seek, before_seek) self.assertGreaterEqual(after_seek, 0) def test_seek_skips_to_next_track_if_new_position_larger_than_track_length(self): - self.backend.current_playlist.append([Track(uri='a', length=40000), + self.core.current_playlist.append([Track(uri='a', length=40000), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.playback.play() + self.core.playback.seek(20000) - before_seek = self.backend.playback.time_position.get() + before_seek = self.core.playback.time_position.get() self.assertGreaterEqual(before_seek, 20000) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') milliseconds_to_seek = 50000 microseconds_to_seek = milliseconds_to_seek * 1000 self.mpris.Seek(microseconds_to_seek) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'b') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'b') - after_seek = self.backend.playback.time_position.get() + after_seek = self.core.playback.time_position.get() self.assertGreaterEqual(after_seek, 0) self.assertLess(after_seek, before_seek) def test_set_position_is_ignored_if_can_seek_is_false(self): self.mpris.get_CanSeek = lambda *_: False - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() - before_set_position = self.backend.playback.time_position.get() + before_set_position = self.core.playback.time_position.get() self.assertLessEqual(before_set_position, 5000) track_id = 'a' @@ -674,17 +677,17 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.SetPosition(track_id, position_to_set_in_microseconds) - after_set_position = self.backend.playback.time_position.get() + after_set_position = self.core.playback.time_position.get() self.assertLessEqual(before_set_position, after_set_position) self.assertLess(after_set_position, position_to_set_in_milliseconds) def test_set_position_sets_the_current_track_position_in_microsecs(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() - before_set_position = self.backend.playback.time_position.get() + before_set_position = self.core.playback.time_position.get() self.assertLessEqual(before_set_position, 5000) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) track_id = '/com/mopidy/track/0' @@ -693,21 +696,21 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.SetPosition(track_id, position_to_set_in_microseconds) - self.assertEquals(self.backend.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.state.get(), PLAYING) - after_set_position = self.backend.playback.time_position.get() + after_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(after_set_position, position_to_set_in_milliseconds) def test_set_position_does_nothing_if_the_position_is_negative(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(20000) - before_set_position = self.backend.playback.time_position.get() + before_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(before_set_position, 20000) self.assertLessEqual(before_set_position, 25000) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') track_id = '/com/mopidy/track/0' @@ -716,21 +719,21 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.SetPosition(track_id, position_to_set_in_microseconds) - after_set_position = self.backend.playback.time_position.get() + after_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(after_set_position, before_set_position) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') def test_set_position_does_nothing_if_position_is_larger_than_track_length(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(20000) - before_set_position = self.backend.playback.time_position.get() + before_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(before_set_position, 20000) self.assertLessEqual(before_set_position, 25000) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') track_id = 'a' @@ -739,21 +742,21 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.SetPosition(track_id, position_to_set_in_microseconds) - after_set_position = self.backend.playback.time_position.get() + after_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(after_set_position, before_set_position) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') def test_set_position_does_nothing_if_track_id_does_not_match_current_track(self): - self.backend.current_playlist.append([Track(uri='a', length=40000)]) - self.backend.playback.play() - self.backend.playback.seek(20000) + self.core.current_playlist.append([Track(uri='a', length=40000)]) + self.core.playback.play() + self.core.playback.seek(20000) - before_set_position = self.backend.playback.time_position.get() + before_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(before_set_position, 20000) self.assertLessEqual(before_set_position, 25000) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') track_id = 'b' @@ -762,74 +765,74 @@ class PlayerInterfaceTest(unittest.TestCase): self.mpris.SetPosition(track_id, position_to_set_in_microseconds) - after_set_position = self.backend.playback.time_position.get() + after_set_position = self.core.playback.time_position.get() self.assertGreaterEqual(after_set_position, before_set_position) - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') def test_open_uri_is_ignored_if_can_play_is_false(self): self.mpris.get_CanPlay = lambda *_: False - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='dummy:/test/uri')] self.mpris.OpenUri('dummy:/test/uri') - self.assertEquals(len(self.backend.current_playlist.tracks.get()), 0) + self.assertEquals(len(self.core.current_playlist.tracks.get()), 0) def test_open_uri_ignores_uris_with_unknown_uri_scheme(self): - self.assertListEqual(self.backend.uri_schemes.get(), ['dummy']) + self.assertListEqual(self.core.uri_schemes.get(), ['dummy']) self.mpris.get_CanPlay = lambda *_: True - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='notdummy:/test/uri')] self.mpris.OpenUri('notdummy:/test/uri') - self.assertEquals(len(self.backend.current_playlist.tracks.get()), 0) + self.assertEquals(len(self.core.current_playlist.tracks.get()), 0) def test_open_uri_adds_uri_to_current_playlist(self): self.mpris.get_CanPlay = lambda *_: True - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='dummy:/test/uri')] self.mpris.OpenUri('dummy:/test/uri') - self.assertEquals(self.backend.current_playlist.tracks.get()[0].uri, + self.assertEquals(self.core.current_playlist.tracks.get()[0].uri, 'dummy:/test/uri') def test_open_uri_starts_playback_of_new_track_if_stopped(self): self.mpris.get_CanPlay = lambda *_: True - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='dummy:/test/uri')] - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.assertEquals(self.backend.playback.state.get(), STOPPED) + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.assertEquals(self.core.playback.state.get(), STOPPED) self.mpris.OpenUri('dummy:/test/uri') - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'dummy:/test/uri') def test_open_uri_starts_playback_of_new_track_if_paused(self): self.mpris.get_CanPlay = lambda *_: True - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='dummy:/test/uri')] - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.backend.playback.pause() - self.assertEquals(self.backend.playback.state.get(), PAUSED) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.core.playback.pause() + self.assertEquals(self.core.playback.state.get(), PAUSED) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') self.mpris.OpenUri('dummy:/test/uri') - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'dummy:/test/uri') def test_open_uri_starts_playback_of_new_track_if_playing(self): self.mpris.get_CanPlay = lambda *_: True - self.backend.library.provider.dummy_library = [ + self.backend.library.dummy_library = [ Track(uri='dummy:/test/uri')] - self.backend.current_playlist.append([Track(uri='a'), Track(uri='b')]) - self.backend.playback.play() - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, 'a') + self.core.current_playlist.append([Track(uri='a'), Track(uri='b')]) + self.core.playback.play() + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'a') self.mpris.OpenUri('dummy:/test/uri') - self.assertEquals(self.backend.playback.state.get(), PLAYING) - self.assertEquals(self.backend.playback.current_track.get().uri, + self.assertEquals(self.core.playback.state.get(), PLAYING) + self.assertEquals(self.core.playback.current_track.get().uri, 'dummy:/test/uri') diff --git a/tests/frontends/mpris/root_interface_test.py b/tests/frontends/mpris/root_interface_test.py index 1e54fc15..b84b70c3 100644 --- a/tests/frontends/mpris/root_interface_test.py +++ b/tests/frontends/mpris/root_interface_test.py @@ -2,8 +2,10 @@ import sys import mock -from mopidy import OptionalDependencyError, settings -from mopidy.backends.dummy import DummyBackend +from pykka.registry import ActorRegistry + +from mopidy import core, settings, OptionalDependencyError +from mopidy.backends import dummy try: from mopidy.frontends.mpris import objects @@ -18,11 +20,12 @@ class RootInterfaceTest(unittest.TestCase): def setUp(self): objects.exit_process = mock.Mock() objects.MprisObject._connect_to_dbus = mock.Mock() - self.backend = DummyBackend.start().proxy() + self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.core = core.Core.start(backend=self.backend).proxy() self.mpris = objects.MprisObject() def tearDown(self): - self.backend.stop() + ActorRegistry.stop_all() def test_constructor_connects_to_dbus(self): self.assert_(self.mpris._connect_to_dbus.called) From 2fb878df2e346996b6b5a8cf7646245d4dd6f0c2 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Thu, 27 Sep 2012 20:18:22 +0200 Subject: [PATCH 02/15] MPD: Rename context.backend to context.core --- mopidy/frontends/mpd/dispatcher.py | 3 +- .../mpd/protocol/current_playlist.py | 84 +++++++++---------- mopidy/frontends/mpd/protocol/music_db.py | 10 +-- mopidy/frontends/mpd/protocol/playback.py | 72 ++++++++-------- mopidy/frontends/mpd/protocol/reflection.py | 2 +- mopidy/frontends/mpd/protocol/status.py | 26 +++--- .../mpd/protocol/stored_playlists.py | 10 +-- 7 files changed, 103 insertions(+), 104 deletions(-) diff --git a/mopidy/frontends/mpd/dispatcher.py b/mopidy/frontends/mpd/dispatcher.py index c9dee576..1f2af153 100644 --- a/mopidy/frontends/mpd/dispatcher.py +++ b/mopidy/frontends/mpd/dispatcher.py @@ -235,11 +235,10 @@ class MpdContext(object): self._core = None @property - def backend(self): + def core(self): """ The Mopidy core. An instance of :class:`mopidy.core.Core`. """ - # TODO: Rename property to 'core' if self._core is None: core_refs = ActorRegistry.get_by_class(core.Core) assert len(core_refs) == 1, \ diff --git a/mopidy/frontends/mpd/protocol/current_playlist.py b/mopidy/frontends/mpd/protocol/current_playlist.py index c60cbc4a..622f79c9 100644 --- a/mopidy/frontends/mpd/protocol/current_playlist.py +++ b/mopidy/frontends/mpd/protocol/current_playlist.py @@ -20,11 +20,11 @@ def add(context, uri): """ if not uri: return - for uri_scheme in context.backend.uri_schemes.get(): + for uri_scheme in context.core.uri_schemes.get(): if uri.startswith(uri_scheme): - track = context.backend.library.lookup(uri).get() + track = context.core.library.lookup(uri).get() if track is not None: - context.backend.current_playlist.add(track) + context.core.current_playlist.add(track) return raise MpdNoExistError( u'directory or file not found', command=u'add') @@ -52,12 +52,12 @@ def addid(context, uri, songpos=None): raise MpdNoExistError(u'No such song', command=u'addid') if songpos is not None: songpos = int(songpos) - track = context.backend.library.lookup(uri).get() + track = context.core.library.lookup(uri).get() if track is None: raise MpdNoExistError(u'No such song', command=u'addid') - if songpos and songpos > context.backend.current_playlist.length.get(): + if songpos and songpos > context.core.current_playlist.length.get(): raise MpdArgError(u'Bad song index', command=u'addid') - cp_track = context.backend.current_playlist.add(track, + cp_track = context.core.current_playlist.add(track, at_position=songpos).get() return ('Id', cp_track.cpid) @@ -74,21 +74,21 @@ def delete_range(context, start, end=None): if end is not None: end = int(end) else: - end = context.backend.current_playlist.length.get() - cp_tracks = context.backend.current_playlist.slice(start, end).get() + end = context.core.current_playlist.length.get() + cp_tracks = context.core.current_playlist.slice(start, end).get() if not cp_tracks: raise MpdArgError(u'Bad song index', command=u'delete') for (cpid, _) in cp_tracks: - context.backend.current_playlist.remove(cpid=cpid) + context.core.current_playlist.remove(cpid=cpid) @handle_request(r'^delete "(?P\d+)"$') def delete_songpos(context, songpos): """See :meth:`delete_range`""" try: songpos = int(songpos) - (cpid, _) = context.backend.current_playlist.slice( + (cpid, _) = context.core.current_playlist.slice( songpos, songpos + 1).get()[0] - context.backend.current_playlist.remove(cpid=cpid) + context.core.current_playlist.remove(cpid=cpid) except IndexError: raise MpdArgError(u'Bad song index', command=u'delete') @@ -103,9 +103,9 @@ def deleteid(context, cpid): """ try: cpid = int(cpid) - if context.backend.playback.current_cpid.get() == cpid: - context.backend.playback.next() - return context.backend.current_playlist.remove(cpid=cpid).get() + if context.core.playback.current_cpid.get() == cpid: + context.core.playback.next() + return context.core.current_playlist.remove(cpid=cpid).get() except LookupError: raise MpdNoExistError(u'No such song', command=u'deleteid') @@ -118,7 +118,7 @@ def clear(context): Clears the current playlist. """ - context.backend.current_playlist.clear() + context.core.current_playlist.clear() @handle_request(r'^move "(?P\d+):(?P\d+)*" "(?P\d+)"$') def move_range(context, start, to, end=None): @@ -131,18 +131,18 @@ def move_range(context, start, to, end=None): ``TO`` in the playlist. """ if end is None: - end = context.backend.current_playlist.length.get() + end = context.core.current_playlist.length.get() start = int(start) end = int(end) to = int(to) - context.backend.current_playlist.move(start, end, to) + context.core.current_playlist.move(start, end, to) @handle_request(r'^move "(?P\d+)" "(?P\d+)"$') def move_songpos(context, songpos, to): """See :meth:`move_range`.""" songpos = int(songpos) to = int(to) - context.backend.current_playlist.move(songpos, songpos + 1, to) + context.core.current_playlist.move(songpos, songpos + 1, to) @handle_request(r'^moveid "(?P\d+)" "(?P\d+)"$') def moveid(context, cpid, to): @@ -157,9 +157,9 @@ def moveid(context, cpid, to): """ cpid = int(cpid) to = int(to) - cp_track = context.backend.current_playlist.get(cpid=cpid).get() - position = context.backend.current_playlist.index(cp_track).get() - context.backend.current_playlist.move(position, position + 1, to) + cp_track = context.core.current_playlist.get(cpid=cpid).get() + position = context.core.current_playlist.index(cp_track).get() + context.core.current_playlist.move(position, position + 1, to) @handle_request(r'^playlist$') def playlist(context): @@ -192,8 +192,8 @@ def playlistfind(context, tag, needle): """ if tag == 'filename': try: - cp_track = context.backend.current_playlist.get(uri=needle).get() - position = context.backend.current_playlist.index(cp_track).get() + cp_track = context.core.current_playlist.get(uri=needle).get() + position = context.core.current_playlist.index(cp_track).get() return track_to_mpd_format(cp_track, position=position) except LookupError: return None @@ -212,14 +212,14 @@ def playlistid(context, cpid=None): if cpid is not None: try: cpid = int(cpid) - cp_track = context.backend.current_playlist.get(cpid=cpid).get() - position = context.backend.current_playlist.index(cp_track).get() + cp_track = context.core.current_playlist.get(cpid=cpid).get() + position = context.core.current_playlist.index(cp_track).get() return track_to_mpd_format(cp_track, position=position) except LookupError: raise MpdNoExistError(u'No such song', command=u'playlistid') else: return tracks_to_mpd_format( - context.backend.current_playlist.cp_tracks.get()) + context.core.current_playlist.cp_tracks.get()) @handle_request(r'^playlistinfo$') @handle_request(r'^playlistinfo "-1"$') @@ -243,19 +243,19 @@ def playlistinfo(context, songpos=None, """ if songpos is not None: songpos = int(songpos) - cp_track = context.backend.current_playlist.cp_tracks.get()[songpos] + cp_track = context.core.current_playlist.cp_tracks.get()[songpos] return track_to_mpd_format(cp_track, position=songpos) else: if start is None: start = 0 start = int(start) - if not (0 <= start <= context.backend.current_playlist.length.get()): + if not (0 <= start <= context.core.current_playlist.length.get()): raise MpdArgError(u'Bad song index', command=u'playlistinfo') if end is not None: end = int(end) - if end > context.backend.current_playlist.length.get(): + if end > context.core.current_playlist.length.get(): end = None - cp_tracks = context.backend.current_playlist.cp_tracks.get() + cp_tracks = context.core.current_playlist.cp_tracks.get() return tracks_to_mpd_format(cp_tracks, start, end) @handle_request(r'^playlistsearch "(?P[^"]+)" "(?P[^"]+)"$') @@ -294,9 +294,9 @@ def plchanges(context, version): - Calls ``plchanges "-1"`` two times per second to get the entire playlist. """ # XXX Naive implementation that returns all tracks as changed - if int(version) < context.backend.current_playlist.version: + if int(version) < context.core.current_playlist.version: return tracks_to_mpd_format( - context.backend.current_playlist.cp_tracks.get()) + context.core.current_playlist.cp_tracks.get()) @handle_request(r'^plchangesposid "(?P\d+)"$') def plchangesposid(context, version): @@ -313,10 +313,10 @@ def plchangesposid(context, version): ``playlistlength`` returned by status command. """ # XXX Naive implementation that returns all tracks as changed - if int(version) != context.backend.current_playlist.version.get(): + if int(version) != context.core.current_playlist.version.get(): result = [] for (position, (cpid, _)) in enumerate( - context.backend.current_playlist.cp_tracks.get()): + context.core.current_playlist.cp_tracks.get()): result.append((u'cpos', position)) result.append((u'Id', cpid)) return result @@ -336,7 +336,7 @@ def shuffle(context, start=None, end=None): start = int(start) if end is not None: end = int(end) - context.backend.current_playlist.shuffle(start, end) + context.core.current_playlist.shuffle(start, end) @handle_request(r'^swap "(?P\d+)" "(?P\d+)"$') def swap(context, songpos1, songpos2): @@ -349,15 +349,15 @@ def swap(context, songpos1, songpos2): """ songpos1 = int(songpos1) songpos2 = int(songpos2) - tracks = context.backend.current_playlist.tracks.get() + tracks = context.core.current_playlist.tracks.get() song1 = tracks[songpos1] song2 = tracks[songpos2] del tracks[songpos1] tracks.insert(songpos1, song2) del tracks[songpos2] tracks.insert(songpos2, song1) - context.backend.current_playlist.clear() - context.backend.current_playlist.append(tracks) + context.core.current_playlist.clear() + context.core.current_playlist.append(tracks) @handle_request(r'^swapid "(?P\d+)" "(?P\d+)"$') def swapid(context, cpid1, cpid2): @@ -370,8 +370,8 @@ def swapid(context, cpid1, cpid2): """ cpid1 = int(cpid1) cpid2 = int(cpid2) - cp_track1 = context.backend.current_playlist.get(cpid=cpid1).get() - cp_track2 = context.backend.current_playlist.get(cpid=cpid2).get() - position1 = context.backend.current_playlist.index(cp_track1).get() - position2 = context.backend.current_playlist.index(cp_track2).get() + cp_track1 = context.core.current_playlist.get(cpid=cpid1).get() + cp_track2 = context.core.current_playlist.get(cpid=cpid2).get() + position1 = context.core.current_playlist.index(cp_track1).get() + position2 = context.core.current_playlist.index(cp_track2).get() swap(context, position1, position2) diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index d0128a1e..2678714a 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -70,7 +70,7 @@ def find(context, mpd_query): """ query = _build_query(mpd_query) return playlist_to_mpd_format( - context.backend.library.find_exact(**query).get()) + context.core.library.find_exact(**query).get()) @handle_request(r'^findadd ' r'(?P("?([Aa]lbum|[Aa]rtist|[Ff]ilename|[Tt]itle|[Aa]ny)"? ' @@ -223,7 +223,7 @@ def _list_build_query(field, mpd_query): def _list_artist(context, query): artists = set() - playlist = context.backend.library.find_exact(**query).get() + playlist = context.core.library.find_exact(**query).get() for track in playlist.tracks: for artist in track.artists: artists.add((u'Artist', artist.name)) @@ -231,7 +231,7 @@ def _list_artist(context, query): def _list_album(context, query): albums = set() - playlist = context.backend.library.find_exact(**query).get() + playlist = context.core.library.find_exact(**query).get() for track in playlist.tracks: if track.album is not None: albums.add((u'Album', track.album.name)) @@ -239,7 +239,7 @@ def _list_album(context, query): def _list_date(context, query): dates = set() - playlist = context.backend.library.find_exact(**query).get() + playlist = context.core.library.find_exact(**query).get() for track in playlist.tracks: if track.date is not None: dates.add((u'Date', track.date)) @@ -333,7 +333,7 @@ def search(context, mpd_query): """ query = _build_query(mpd_query) return playlist_to_mpd_format( - context.backend.library.search(**query).get()) + context.core.library.search(**query).get()) @handle_request(r'^update( "(?P[^"]+)")*$') def update(context, uri=None, rescan_unmodified_files=False): diff --git a/mopidy/frontends/mpd/protocol/playback.py b/mopidy/frontends/mpd/protocol/playback.py index 4152f11e..76cefdc3 100644 --- a/mopidy/frontends/mpd/protocol/playback.py +++ b/mopidy/frontends/mpd/protocol/playback.py @@ -16,9 +16,9 @@ def consume(context, state): playlist. """ if int(state): - context.backend.playback.consume = True + context.core.playback.consume = True else: - context.backend.playback.consume = False + context.core.playback.consume = False @handle_request(r'^crossfade "(?P\d+)"$') def crossfade(context, seconds): @@ -87,7 +87,7 @@ def next_(context): order as the first time. """ - return context.backend.playback.next().get() + return context.core.playback.next().get() @handle_request(r'^pause$') @handle_request(r'^pause "(?P[01])"$') @@ -104,14 +104,14 @@ def pause(context, state=None): - Calls ``pause`` without any arguments to toogle pause. """ if state is None: - if (context.backend.playback.state.get() == PlaybackState.PLAYING): - context.backend.playback.pause() - elif (context.backend.playback.state.get() == PlaybackState.PAUSED): - context.backend.playback.resume() + if (context.core.playback.state.get() == PlaybackState.PLAYING): + context.core.playback.pause() + elif (context.core.playback.state.get() == PlaybackState.PAUSED): + context.core.playback.resume() elif int(state): - context.backend.playback.pause() + context.core.playback.pause() else: - context.backend.playback.resume() + context.core.playback.resume() @handle_request(r'^play$') def play(context): @@ -119,7 +119,7 @@ def play(context): The original MPD server resumes from the paused state on ``play`` without arguments. """ - return context.backend.playback.play().get() + return context.core.playback.play().get() @handle_request(r'^playid (?P-?\d+)$') @handle_request(r'^playid "(?P-?\d+)"$') @@ -144,8 +144,8 @@ def playid(context, cpid): if cpid == -1: return _play_minus_one(context) try: - cp_track = context.backend.current_playlist.get(cpid=cpid).get() - return context.backend.playback.play(cp_track).get() + cp_track = context.core.current_playlist.get(cpid=cpid).get() + return context.core.playback.play(cp_track).get() except LookupError: raise MpdNoExistError(u'No such song', command=u'playid') @@ -176,23 +176,23 @@ def playpos(context, songpos): if songpos == -1: return _play_minus_one(context) try: - cp_track = context.backend.current_playlist.slice( + cp_track = context.core.current_playlist.slice( songpos, songpos + 1).get()[0] - return context.backend.playback.play(cp_track).get() + return context.core.playback.play(cp_track).get() except IndexError: raise MpdArgError(u'Bad song index', command=u'play') def _play_minus_one(context): - if (context.backend.playback.state.get() == PlaybackState.PLAYING): + if (context.core.playback.state.get() == PlaybackState.PLAYING): return # Nothing to do - elif (context.backend.playback.state.get() == PlaybackState.PAUSED): - return context.backend.playback.resume().get() - elif context.backend.playback.current_cp_track.get() is not None: - cp_track = context.backend.playback.current_cp_track.get() - return context.backend.playback.play(cp_track).get() - elif context.backend.current_playlist.slice(0, 1).get(): - cp_track = context.backend.current_playlist.slice(0, 1).get()[0] - return context.backend.playback.play(cp_track).get() + elif (context.core.playback.state.get() == PlaybackState.PAUSED): + return context.core.playback.resume().get() + elif context.core.playback.current_cp_track.get() is not None: + cp_track = context.core.playback.current_cp_track.get() + return context.core.playback.play(cp_track).get() + elif context.core.current_playlist.slice(0, 1).get(): + cp_track = context.core.current_playlist.slice(0, 1).get()[0] + return context.core.playback.play(cp_track).get() else: return # Fail silently @@ -240,7 +240,7 @@ def previous(context): ``previous`` should do a seek to time position 0. """ - return context.backend.playback.previous().get() + return context.core.playback.previous().get() @handle_request(r'^random (?P[01])$') @handle_request(r'^random "(?P[01])"$') @@ -253,9 +253,9 @@ def random(context, state): Sets random state to ``STATE``, ``STATE`` should be 0 or 1. """ if int(state): - context.backend.playback.random = True + context.core.playback.random = True else: - context.backend.playback.random = False + context.core.playback.random = False @handle_request(r'^repeat (?P[01])$') @handle_request(r'^repeat "(?P[01])"$') @@ -268,9 +268,9 @@ def repeat(context, state): Sets repeat state to ``STATE``, ``STATE`` should be 0 or 1. """ if int(state): - context.backend.playback.repeat = True + context.core.playback.repeat = True else: - context.backend.playback.repeat = False + context.core.playback.repeat = False @handle_request(r'^replay_gain_mode "(?P(off|track|album))"$') def replay_gain_mode(context, mode): @@ -315,9 +315,9 @@ def seek(context, songpos, seconds): - issues ``seek 1 120`` without quotes around the arguments. """ - if context.backend.playback.current_playlist_position != songpos: + if context.core.playback.current_playlist_position != songpos: playpos(context, songpos) - context.backend.playback.seek(int(seconds) * 1000) + context.core.playback.seek(int(seconds) * 1000) @handle_request(r'^seekid "(?P\d+)" "(?P\d+)"$') def seekid(context, cpid, seconds): @@ -328,9 +328,9 @@ def seekid(context, cpid, seconds): Seeks to the position ``TIME`` (in seconds) of song ``SONGID``. """ - if context.backend.playback.current_cpid != cpid: + if context.core.playback.current_cpid != cpid: playid(context, cpid) - context.backend.playback.seek(int(seconds) * 1000) + context.core.playback.seek(int(seconds) * 1000) @handle_request(r'^setvol (?P[-+]*\d+)$') @handle_request(r'^setvol "(?P[-+]*\d+)"$') @@ -351,7 +351,7 @@ def setvol(context, volume): volume = 0 if volume > 100: volume = 100 - context.backend.playback.volume = volume + context.core.playback.volume = volume @handle_request(r'^single (?P[01])$') @handle_request(r'^single "(?P[01])"$') @@ -366,9 +366,9 @@ def single(context, state): song is repeated if the ``repeat`` mode is enabled. """ if int(state): - context.backend.playback.single = True + context.core.playback.single = True else: - context.backend.playback.single = False + context.core.playback.single = False @handle_request(r'^stop$') def stop(context): @@ -379,4 +379,4 @@ def stop(context): Stops playing. """ - context.backend.playback.stop() + context.core.playback.stop() diff --git a/mopidy/frontends/mpd/protocol/reflection.py b/mopidy/frontends/mpd/protocol/reflection.py index df13b4b4..8cd1337b 100644 --- a/mopidy/frontends/mpd/protocol/reflection.py +++ b/mopidy/frontends/mpd/protocol/reflection.py @@ -84,4 +84,4 @@ def urlhandlers(context): Gets a list of available URL handlers. """ return [(u'handler', uri_scheme) - for uri_scheme in context.backend.uri_schemes.get()] + for uri_scheme in context.core.uri_schemes.get()] diff --git a/mopidy/frontends/mpd/protocol/status.py b/mopidy/frontends/mpd/protocol/status.py index fc24e1e1..4f48265c 100644 --- a/mopidy/frontends/mpd/protocol/status.py +++ b/mopidy/frontends/mpd/protocol/status.py @@ -31,9 +31,9 @@ def currentsong(context): Displays the song info of the current song (same song that is identified in status). """ - current_cp_track = context.backend.playback.current_cp_track.get() + current_cp_track = context.core.playback.current_cp_track.get() if current_cp_track is not None: - position = context.backend.playback.current_playlist_position.get() + position = context.core.playback.current_playlist_position.get() return track_to_mpd_format(current_cp_track, position=position) @handle_request(r'^idle$') @@ -166,18 +166,18 @@ def status(context): decimal places for millisecond precision. """ futures = { - 'current_playlist.length': context.backend.current_playlist.length, - 'current_playlist.version': context.backend.current_playlist.version, - 'playback.volume': context.backend.playback.volume, - 'playback.consume': context.backend.playback.consume, - 'playback.random': context.backend.playback.random, - 'playback.repeat': context.backend.playback.repeat, - 'playback.single': context.backend.playback.single, - 'playback.state': context.backend.playback.state, - 'playback.current_cp_track': context.backend.playback.current_cp_track, + 'current_playlist.length': context.core.current_playlist.length, + 'current_playlist.version': context.core.current_playlist.version, + 'playback.volume': context.core.playback.volume, + 'playback.consume': context.core.playback.consume, + 'playback.random': context.core.playback.random, + 'playback.repeat': context.core.playback.repeat, + 'playback.single': context.core.playback.single, + 'playback.state': context.core.playback.state, + 'playback.current_cp_track': context.core.playback.current_cp_track, 'playback.current_playlist_position': - context.backend.playback.current_playlist_position, - 'playback.time_position': context.backend.playback.time_position, + context.core.playback.current_playlist_position, + 'playback.time_position': context.core.playback.time_position, } pykka.future.get_all(futures.values()) result = [ diff --git a/mopidy/frontends/mpd/protocol/stored_playlists.py b/mopidy/frontends/mpd/protocol/stored_playlists.py index bb39d328..c21f4714 100644 --- a/mopidy/frontends/mpd/protocol/stored_playlists.py +++ b/mopidy/frontends/mpd/protocol/stored_playlists.py @@ -20,7 +20,7 @@ def listplaylist(context, name): file: relative/path/to/file3.mp3 """ try: - playlist = context.backend.stored_playlists.get(name=name).get() + playlist = context.core.stored_playlists.get(name=name).get() return ['file: %s' % t.uri for t in playlist.tracks] except LookupError: raise MpdNoExistError(u'No such playlist', command=u'listplaylist') @@ -40,7 +40,7 @@ def listplaylistinfo(context, name): Album, Artist, Track """ try: - playlist = context.backend.stored_playlists.get(name=name).get() + playlist = context.core.stored_playlists.get(name=name).get() return playlist_to_mpd_format(playlist) except LookupError: raise MpdNoExistError( @@ -68,7 +68,7 @@ def listplaylists(context): Last-Modified: 2010-02-06T02:11:08Z """ result = [] - for playlist in context.backend.stored_playlists.playlists.get(): + for playlist in context.core.stored_playlists.playlists.get(): result.append((u'playlist', playlist.name)) last_modified = (playlist.last_modified or dt.datetime.now()).isoformat() @@ -94,8 +94,8 @@ def load(context, name): - ``load`` appends the given playlist to the current playlist. """ try: - playlist = context.backend.stored_playlists.get(name=name).get() - context.backend.current_playlist.append(playlist.tracks) + playlist = context.core.stored_playlists.get(name=name).get() + context.core.current_playlist.append(playlist.tracks) except LookupError: raise MpdNoExistError(u'No such playlist', command=u'load') From 5a628a4150cf43fe4bfab5a55f2c67b2ee25a7ce Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Thu, 27 Sep 2012 20:18:35 +0200 Subject: [PATCH 03/15] MPRIS: Rename self.backend to self.core --- mopidy/frontends/mpris/objects.py | 91 +++++++++++++++---------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/mopidy/frontends/mpris/objects.py b/mopidy/frontends/mpris/objects.py index c2c9f527..cb1e73eb 100644 --- a/mopidy/frontends/mpris/objects.py +++ b/mopidy/frontends/mpris/objects.py @@ -84,8 +84,7 @@ class MprisObject(dbus.service.Object): return bus_name @property - def backend(self): - # TODO: Rename property to 'core' + def core(self): if self._core is None: core_refs = ActorRegistry.get_by_class(core.Core) assert len(core_refs) == 1, \ @@ -162,7 +161,7 @@ class MprisObject(dbus.service.Object): return os.path.splitext(os.path.basename(settings.DESKTOP_FILE))[0] def get_SupportedUriSchemes(self): - return dbus.Array(self.backend.uri_schemes.get(), signature='s') + return dbus.Array(self.core.uri_schemes.get(), signature='s') ### Player interface methods @@ -173,7 +172,7 @@ class MprisObject(dbus.service.Object): if not self.get_CanGoNext(): logger.debug(u'%s.Next not allowed', PLAYER_IFACE) return - self.backend.playback.next().get() + self.core.playback.next().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def Previous(self): @@ -181,7 +180,7 @@ class MprisObject(dbus.service.Object): if not self.get_CanGoPrevious(): logger.debug(u'%s.Previous not allowed', PLAYER_IFACE) return - self.backend.playback.previous().get() + self.core.playback.previous().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def Pause(self): @@ -189,7 +188,7 @@ class MprisObject(dbus.service.Object): if not self.get_CanPause(): logger.debug(u'%s.Pause not allowed', PLAYER_IFACE) return - self.backend.playback.pause().get() + self.core.playback.pause().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def PlayPause(self): @@ -197,13 +196,13 @@ class MprisObject(dbus.service.Object): if not self.get_CanPause(): logger.debug(u'%s.PlayPause not allowed', PLAYER_IFACE) return - state = self.backend.playback.state.get() + state = self.core.playback.state.get() if state == PlaybackState.PLAYING: - self.backend.playback.pause().get() + self.core.playback.pause().get() elif state == PlaybackState.PAUSED: - self.backend.playback.resume().get() + self.core.playback.resume().get() elif state == PlaybackState.STOPPED: - self.backend.playback.play().get() + self.core.playback.play().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def Stop(self): @@ -211,7 +210,7 @@ class MprisObject(dbus.service.Object): if not self.get_CanControl(): logger.debug(u'%s.Stop not allowed', PLAYER_IFACE) return - self.backend.playback.stop().get() + self.core.playback.stop().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def Play(self): @@ -219,11 +218,11 @@ class MprisObject(dbus.service.Object): if not self.get_CanPlay(): logger.debug(u'%s.Play not allowed', PLAYER_IFACE) return - state = self.backend.playback.state.get() + state = self.core.playback.state.get() if state == PlaybackState.PAUSED: - self.backend.playback.resume().get() + self.core.playback.resume().get() else: - self.backend.playback.play().get() + self.core.playback.play().get() @dbus.service.method(dbus_interface=PLAYER_IFACE) def Seek(self, offset): @@ -232,9 +231,9 @@ class MprisObject(dbus.service.Object): logger.debug(u'%s.Seek not allowed', PLAYER_IFACE) return offset_in_milliseconds = offset // 1000 - current_position = self.backend.playback.time_position.get() + current_position = self.core.playback.time_position.get() new_position = current_position + offset_in_milliseconds - self.backend.playback.seek(new_position) + self.core.playback.seek(new_position) @dbus.service.method(dbus_interface=PLAYER_IFACE) def SetPosition(self, track_id, position): @@ -243,7 +242,7 @@ class MprisObject(dbus.service.Object): logger.debug(u'%s.SetPosition not allowed', PLAYER_IFACE) return position = position // 1000 - current_cp_track = self.backend.playback.current_cp_track.get() + current_cp_track = self.core.playback.current_cp_track.get() if current_cp_track is None: return if track_id != self._get_track_id(current_cp_track): @@ -252,7 +251,7 @@ class MprisObject(dbus.service.Object): return if current_cp_track.track.length < position: return - self.backend.playback.seek(position) + self.core.playback.seek(position) @dbus.service.method(dbus_interface=PLAYER_IFACE) def OpenUri(self, uri): @@ -264,13 +263,13 @@ class MprisObject(dbus.service.Object): return # NOTE Check if URI has MIME type known to the backend, if MIME support # is added to the backend. - uri_schemes = self.backend.uri_schemes.get() + uri_schemes = self.core.uri_schemes.get() if not any([uri.startswith(uri_scheme) for uri_scheme in uri_schemes]): return - track = self.backend.library.lookup(uri).get() + track = self.core.library.lookup(uri).get() if track is not None: - cp_track = self.backend.current_playlist.add(track).get() - self.backend.playback.play(cp_track) + cp_track = self.core.current_playlist.add(track).get() + self.core.playback.play(cp_track) else: logger.debug(u'Track with URI "%s" not found in library.', uri) @@ -286,7 +285,7 @@ class MprisObject(dbus.service.Object): ### Player interface properties def get_PlaybackStatus(self): - state = self.backend.playback.state.get() + state = self.core.playback.state.get() if state == PlaybackState.PLAYING: return 'Playing' elif state == PlaybackState.PAUSED: @@ -295,8 +294,8 @@ class MprisObject(dbus.service.Object): return 'Stopped' def get_LoopStatus(self): - repeat = self.backend.playback.repeat.get() - single = self.backend.playback.single.get() + repeat = self.core.playback.repeat.get() + single = self.core.playback.single.get() if not repeat: return 'None' else: @@ -310,14 +309,14 @@ class MprisObject(dbus.service.Object): logger.debug(u'Setting %s.LoopStatus not allowed', PLAYER_IFACE) return if value == 'None': - self.backend.playback.repeat = False - self.backend.playback.single = False + self.core.playback.repeat = False + self.core.playback.single = False elif value == 'Track': - self.backend.playback.repeat = True - self.backend.playback.single = True + self.core.playback.repeat = True + self.core.playback.single = True elif value == 'Playlist': - self.backend.playback.repeat = True - self.backend.playback.single = False + self.core.playback.repeat = True + self.core.playback.single = False def set_Rate(self, value): if not self.get_CanControl(): @@ -329,19 +328,19 @@ class MprisObject(dbus.service.Object): self.Pause() def get_Shuffle(self): - return self.backend.playback.random.get() + return self.core.playback.random.get() def set_Shuffle(self, value): if not self.get_CanControl(): logger.debug(u'Setting %s.Shuffle not allowed', PLAYER_IFACE) return if value: - self.backend.playback.random = True + self.core.playback.random = True else: - self.backend.playback.random = False + self.core.playback.random = False def get_Metadata(self): - current_cp_track = self.backend.playback.current_cp_track.get() + current_cp_track = self.core.playback.current_cp_track.get() if current_cp_track is None: return {'mpris:trackid': ''} else: @@ -370,7 +369,7 @@ class MprisObject(dbus.service.Object): return dbus.Dictionary(metadata, signature='sv') def get_Volume(self): - volume = self.backend.playback.volume.get() + volume = self.core.playback.volume.get() if volume is None: return 0 return volume / 100.0 @@ -382,32 +381,32 @@ class MprisObject(dbus.service.Object): if value is None: return elif value < 0: - self.backend.playback.volume = 0 + self.core.playback.volume = 0 elif value > 1: - self.backend.playback.volume = 100 + self.core.playback.volume = 100 elif 0 <= value <= 1: - self.backend.playback.volume = int(value * 100) + self.core.playback.volume = int(value * 100) def get_Position(self): - return self.backend.playback.time_position.get() * 1000 + return self.core.playback.time_position.get() * 1000 def get_CanGoNext(self): if not self.get_CanControl(): return False - return (self.backend.playback.cp_track_at_next.get() != - self.backend.playback.current_cp_track.get()) + return (self.core.playback.cp_track_at_next.get() != + self.core.playback.current_cp_track.get()) def get_CanGoPrevious(self): if not self.get_CanControl(): return False - return (self.backend.playback.cp_track_at_previous.get() != - self.backend.playback.current_cp_track.get()) + return (self.core.playback.cp_track_at_previous.get() != + self.core.playback.current_cp_track.get()) def get_CanPlay(self): if not self.get_CanControl(): return False - return (self.backend.playback.current_track.get() is not None - or self.backend.playback.track_at_next.get() is not None) + return (self.core.playback.current_track.get() is not None + or self.core.playback.track_at_next.get() is not None) def get_CanPause(self): if not self.get_CanControl(): From e7f08a7a20e3493e1c35561d293423659f0c3977 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Thu, 27 Sep 2012 20:31:41 +0200 Subject: [PATCH 04/15] Rename mopidy.{listeners.BackendListener => core.CoreListener} --- docs/api/core.rst | 7 +++++++ docs/api/index.rst | 1 - docs/api/listeners.rst | 7 ------- mopidy/core/__init__.py | 1 + mopidy/core/current_playlist.py | 5 +++-- mopidy/{listeners.py => core/listener.py} | 11 ++++++----- mopidy/core/playback.py | 16 ++++++++-------- mopidy/frontends/lastfm.py | 7 ++++--- mopidy/frontends/mpd/__init__.py | 6 ++++-- mopidy/frontends/mpris/__init__.py | 5 ++--- tests/backends/events_test.py | 3 +-- .../{listeners_test.py => core/listener_test.py} | 7 +++---- 12 files changed, 39 insertions(+), 37 deletions(-) delete mode 100644 docs/api/listeners.rst rename mopidy/{listeners.py => core/listener.py} (92%) rename tests/{listeners_test.py => core/listener_test.py} (87%) diff --git a/docs/api/core.rst b/docs/api/core.rst index e74d9f45..1563b61b 100644 --- a/docs/api/core.rst +++ b/docs/api/core.rst @@ -48,3 +48,10 @@ Manages the music library, e.g. searching for tracks to be added to a playlist. .. autoclass:: mopidy.core.LibraryController :members: + + +Core listener +============= + +.. autoclass:: mopidy.core.CoreListener + :members: diff --git a/docs/api/index.rst b/docs/api/index.rst index 618096ee..5a210812 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -11,4 +11,3 @@ API reference core audio frontends - listeners diff --git a/docs/api/listeners.rst b/docs/api/listeners.rst deleted file mode 100644 index 609dc3c7..00000000 --- a/docs/api/listeners.rst +++ /dev/null @@ -1,7 +0,0 @@ -************ -Listener API -************ - -.. automodule:: mopidy.listeners - :synopsis: Listener API - :members: diff --git a/mopidy/core/__init__.py b/mopidy/core/__init__.py index 6070dcc8..28274fe3 100644 --- a/mopidy/core/__init__.py +++ b/mopidy/core/__init__.py @@ -1,5 +1,6 @@ from .actor import Core from .current_playlist import CurrentPlaylistController from .library import LibraryController +from .listener import CoreListener from .playback import PlaybackController, PlaybackState from .stored_playlists import StoredPlaylistsController diff --git a/mopidy/core/current_playlist.py b/mopidy/core/current_playlist.py index a39b4c39..973fe71f 100644 --- a/mopidy/core/current_playlist.py +++ b/mopidy/core/current_playlist.py @@ -2,9 +2,10 @@ from copy import copy import logging import random -from mopidy.listeners import BackendListener from mopidy.models import CpTrack +from .listener import CoreListener + logger = logging.getLogger('mopidy.core') @@ -240,4 +241,4 @@ class CurrentPlaylistController(object): def _trigger_playlist_changed(self): logger.debug(u'Triggering playlist changed event') - BackendListener.send('playlist_changed') + CoreListener.send('playlist_changed') diff --git a/mopidy/listeners.py b/mopidy/core/listener.py similarity index 92% rename from mopidy/listeners.py rename to mopidy/core/listener.py index a8794232..a77b29a8 100644 --- a/mopidy/listeners.py +++ b/mopidy/core/listener.py @@ -1,11 +1,12 @@ from pykka import registry -class BackendListener(object): + +class CoreListener(object): """ - Marker interface for recipients of events sent by the backend. + Marker interface for recipients of events sent by the core actor. Any Pykka actor that mixes in this class will receive calls to the methods - defined here when the corresponding events happen in the backend. This + defined here when the corresponding events happen in the core actor. This interface is used both for looking up what actors to notify of the events, and for providing default implementations for those listeners that are not interested in all events. @@ -13,7 +14,7 @@ class BackendListener(object): @staticmethod def send(event, **kwargs): - """Helper to allow calling of backend listener events""" + """Helper to allow calling of core listener events""" # FIXME this should be updated once Pykka supports non-blocking calls # on proxies or some similar solution. registry.ActorRegistry.broadcast({ @@ -21,7 +22,7 @@ class BackendListener(object): 'attr_path': (event,), 'args': [], 'kwargs': kwargs, - }, target_class=BackendListener) + }, target_class=CoreListener) def track_playback_paused(self, track, time_position): """ diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index efba03dd..603b40a4 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -1,7 +1,7 @@ import logging import random -from mopidy.listeners import BackendListener +from .listener import CoreListener logger = logging.getLogger('mopidy.backends.base') @@ -479,7 +479,7 @@ class PlaybackController(object): logger.debug(u'Triggering track playback paused event') if self.current_track is None: return - BackendListener.send('track_playback_paused', + CoreListener.send('track_playback_paused', track=self.current_track, time_position=self.time_position) @@ -487,7 +487,7 @@ class PlaybackController(object): logger.debug(u'Triggering track playback resumed event') if self.current_track is None: return - BackendListener.send('track_playback_resumed', + CoreListener.send('track_playback_resumed', track=self.current_track, time_position=self.time_position) @@ -495,26 +495,26 @@ class PlaybackController(object): logger.debug(u'Triggering track playback started event') if self.current_track is None: return - BackendListener.send('track_playback_started', + CoreListener.send('track_playback_started', track=self.current_track) def _trigger_track_playback_ended(self): logger.debug(u'Triggering track playback ended event') if self.current_track is None: return - BackendListener.send('track_playback_ended', + CoreListener.send('track_playback_ended', track=self.current_track, time_position=self.time_position) def _trigger_playback_state_changed(self, old_state, new_state): logger.debug(u'Triggering playback state change event') - BackendListener.send('playback_state_changed', + CoreListener.send('playback_state_changed', old_state=old_state, new_state=new_state) def _trigger_options_changed(self): logger.debug(u'Triggering options changed event') - BackendListener.send('options_changed') + CoreListener.send('options_changed') def _trigger_seeked(self, time_position): logger.debug(u'Triggering seeked event') - BackendListener.send('seeked', time_position=time_position) + CoreListener.send('seeked', time_position=time_position) diff --git a/mopidy/frontends/lastfm.py b/mopidy/frontends/lastfm.py index 0e79024b..f2bc44d2 100644 --- a/mopidy/frontends/lastfm.py +++ b/mopidy/frontends/lastfm.py @@ -9,15 +9,16 @@ except ImportError as import_error: from pykka.actor import ThreadingActor -from mopidy import settings, SettingsError -from mopidy.listeners import BackendListener +from mopidy import core, settings, SettingsError + logger = logging.getLogger('mopidy.frontends.lastfm') API_KEY = '2236babefa8ebb3d93ea467560d00d04' API_SECRET = '94d9a09c0cd5be955c4afaeaffcaefcd' -class LastfmFrontend(ThreadingActor, BackendListener): + +class LastfmFrontend(ThreadingActor, core.CoreListener): """ Frontend which scrobbles the music you play to your `Last.fm `_ profile. diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py index 5d287d03..9dcf4c34 100644 --- a/mopidy/frontends/mpd/__init__.py +++ b/mopidy/frontends/mpd/__init__.py @@ -3,13 +3,15 @@ import sys from pykka import registry, actor -from mopidy import listeners, settings +from mopidy import core, settings from mopidy.frontends.mpd import dispatcher, protocol from mopidy.utils import locale_decode, log, network, process + logger = logging.getLogger('mopidy.frontends.mpd') -class MpdFrontend(actor.ThreadingActor, listeners.BackendListener): + +class MpdFrontend(actor.ThreadingActor, core.CoreListener): """ The MPD frontend. diff --git a/mopidy/frontends/mpris/__init__.py b/mopidy/frontends/mpris/__init__.py index 4d4d5edb..2815c551 100644 --- a/mopidy/frontends/mpris/__init__.py +++ b/mopidy/frontends/mpris/__init__.py @@ -10,12 +10,11 @@ except ImportError as import_error: from pykka.actor import ThreadingActor -from mopidy import settings +from mopidy import core, settings from mopidy.frontends.mpris import objects -from mopidy.listeners import BackendListener -class MprisFrontend(ThreadingActor, BackendListener): +class MprisFrontend(ThreadingActor, core.CoreListener): """ Frontend which lets you control Mopidy through the Media Player Remote Interfacing Specification (`MPRIS `_) D-Bus diff --git a/tests/backends/events_test.py b/tests/backends/events_test.py index 5408d71f..200e0ca2 100644 --- a/tests/backends/events_test.py +++ b/tests/backends/events_test.py @@ -4,13 +4,12 @@ from pykka.registry import ActorRegistry from mopidy import audio, core from mopidy.backends import dummy -from mopidy.listeners import BackendListener from mopidy.models import Track from tests import unittest -@mock.patch.object(BackendListener, 'send') +@mock.patch.object(core.CoreListener, 'send') class BackendEventsTest(unittest.TestCase): def setUp(self): self.audio = mock.Mock(spec=audio.Audio) diff --git a/tests/listeners_test.py b/tests/core/listener_test.py similarity index 87% rename from tests/listeners_test.py rename to tests/core/listener_test.py index 896fedf0..2abd9479 100644 --- a/tests/listeners_test.py +++ b/tests/core/listener_test.py @@ -1,13 +1,12 @@ -from mopidy.core import PlaybackState -from mopidy.listeners import BackendListener +from mopidy.core import CoreListener, PlaybackState from mopidy.models import Track from tests import unittest -class BackendListenerTest(unittest.TestCase): +class CoreListenerTest(unittest.TestCase): def setUp(self): - self.listener = BackendListener() + self.listener = CoreListener() def test_listener_has_default_impl_for_track_playback_paused(self): self.listener.track_playback_paused(Track(), 0) From 8c78d469e29b54d6ab5c085e6246348050f46009 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Thu, 27 Sep 2012 22:18:39 +0200 Subject: [PATCH 05/15] Use Pykka proxies to send events With Pykka >= 0.16, sending events can be done using proxies instead of manually crafting Pykka's internal function call messages. --- docs/changes.rst | 4 +++- docs/installation/index.rst | 2 +- mopidy/core/listener.py | 14 ++++---------- requirements/core.txt | 2 +- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index caec53ba..17d50072 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -8,7 +8,9 @@ This change log is used to track all major changes to Mopidy. v0.9.0 (in development) ======================= -- Nothing so far. +**Dependencies** + +- Pykka >= 0.16 is now required. v0.8.0 (2012-09-20) diff --git a/docs/installation/index.rst b/docs/installation/index.rst index 66b920f8..d5728c00 100644 --- a/docs/installation/index.rst +++ b/docs/installation/index.rst @@ -26,7 +26,7 @@ dependencies installed. - Python >= 2.6, < 3 - - Pykka >= 0.12.3:: + - Pykka >= 0.16:: sudo pip install -U pykka diff --git a/mopidy/core/listener.py b/mopidy/core/listener.py index a77b29a8..9476ac4f 100644 --- a/mopidy/core/listener.py +++ b/mopidy/core/listener.py @@ -1,4 +1,4 @@ -from pykka import registry +from pykka.registry import ActorRegistry class CoreListener(object): @@ -15,14 +15,9 @@ class CoreListener(object): @staticmethod def send(event, **kwargs): """Helper to allow calling of core listener events""" - # FIXME this should be updated once Pykka supports non-blocking calls - # on proxies or some similar solution. - registry.ActorRegistry.broadcast({ - 'command': 'pykka_call', - 'attr_path': (event,), - 'args': [], - 'kwargs': kwargs, - }, target_class=CoreListener) + listeners = ActorRegistry.get_by_class(CoreListener) + for listener in listeners: + getattr(listener.proxy(), event)(**kwargs) def track_playback_paused(self, track, time_position): """ @@ -50,7 +45,6 @@ class CoreListener(object): """ pass - def track_playback_started(self, track): """ Called whenever a new track starts playing. diff --git a/requirements/core.txt b/requirements/core.txt index 8f9da622..1c2371f3 100644 --- a/requirements/core.txt +++ b/requirements/core.txt @@ -1 +1 @@ -Pykka >= 0.12.3 +Pykka >= 0.16 From 4b13f46e2e9c1f8fd85a03cb23f27ddb4edc74ae Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Thu, 27 Sep 2012 23:17:57 +0200 Subject: [PATCH 06/15] Add AudioListener for events from the audio actor This is analogous to how the core actor sends events to the frontends. This removes the audio actor's direct dependency on the core actor, which conceptually is on a higher layer. --- docs/api/audio.rst | 13 ++++++++++--- mopidy/audio/__init__.py | 19 +++++++------------ mopidy/audio/listener.py | 28 ++++++++++++++++++++++++++++ mopidy/core/actor.py | 7 ++++++- 4 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 mopidy/audio/listener.py diff --git a/docs/api/audio.rst b/docs/api/audio.rst index d5fb5dd9..e00772fd 100644 --- a/docs/api/audio.rst +++ b/docs/api/audio.rst @@ -10,10 +10,17 @@ the URI of the resource they want to play, for these cases the default playback provider should be used. For more advanced cases such as when the raw audio data is delivered outside of -GStreamer or the backend needs to add metadata to the currently playing resource, -developers should sub-class the base playback provider and implement the extra -behaviour that is needed through the following API: +GStreamer or the backend needs to add metadata to the currently playing +resource, developers should sub-class the base playback provider and implement +the extra behaviour that is needed through the following API: .. autoclass:: mopidy.audio.Audio :members: + + +Audio listener +============== + +.. autoclass:: mopidy.audio.AudioListener + :members: diff --git a/mopidy/audio/__init__.py b/mopidy/audio/__init__.py index 3ce459dd..4abd5774 100644 --- a/mopidy/audio/__init__.py +++ b/mopidy/audio/__init__.py @@ -6,13 +6,13 @@ import gobject import logging from pykka.actor import ThreadingActor -from pykka.registry import ActorRegistry -from mopidy import core, settings, utils +from mopidy import settings, utils from mopidy.utils import process # Trigger install of gst mixer plugins -from mopidy.audio import mixers +from . import mixers +from .listener import AudioListener logger = logging.getLogger('mopidy.audio') @@ -149,7 +149,7 @@ class Audio(ThreadingActor): def _on_message(self, bus, message): if message.type == gst.MESSAGE_EOS: - self._notify_core_of_eos() + self._trigger_reached_end_of_stream_event() elif message.type == gst.MESSAGE_ERROR: error, debug = message.parse_error() logger.error(u'%s %s', error, debug) @@ -158,14 +158,9 @@ class Audio(ThreadingActor): error, debug = message.parse_warning() logger.warning(u'%s %s', error, debug) - def _notify_core_of_eos(self): - core_refs = ActorRegistry.get_by_class(core.Core) - assert len(core_refs) <= 1, 'Expected at most one running core instance' - if core_refs: - logger.debug(u'Notifying core of end-of-stream') - core_refs[0].proxy().playback.on_end_of_track() - else: - logger.debug(u'No core instance to notify of end-of-stream found') + def _trigger_reached_end_of_stream_event(self): + logger.debug(u'Triggering reached end of stream event') + AudioListener.send('reached_end_of_stream') def set_uri(self, uri): """ diff --git a/mopidy/audio/listener.py b/mopidy/audio/listener.py new file mode 100644 index 00000000..757cd5f4 --- /dev/null +++ b/mopidy/audio/listener.py @@ -0,0 +1,28 @@ +from pykka.registry import ActorRegistry + + +class AudioListener(object): + """ + Marker interface for recipients of events sent by the audio actor. + + Any Pykka actor that mixes in this class will receive calls to the methods + defined here when the corresponding events happen in the core actor. This + interface is used both for looking up what actors to notify of the events, + and for providing default implementations for those listeners that are not + interested in all events. + """ + + @staticmethod + def send(event, **kwargs): + """Helper to allow calling of audio listener events""" + listeners = ActorRegistry.get_by_class(AudioListener) + for listener in listeners: + getattr(listener.proxy(), event)(**kwargs) + + def reached_end_of_stream(self): + """ + Called whenever the end of the audio stream is reached. + + *MAY* be implemented by actor. + """ + pass diff --git a/mopidy/core/actor.py b/mopidy/core/actor.py index 4ff378c4..4ec86e8b 100644 --- a/mopidy/core/actor.py +++ b/mopidy/core/actor.py @@ -1,12 +1,14 @@ from pykka.actor import ThreadingActor +from mopidy import audio + from .current_playlist import CurrentPlaylistController from .library import LibraryController from .playback import PlaybackController from .stored_playlists import StoredPlaylistsController -class Core(ThreadingActor): +class Core(ThreadingActor, audio.AudioListener): #: The current playlist controller. An instance of #: :class:`mopidy.core.CurrentPlaylistController`. current_playlist = None @@ -40,3 +42,6 @@ class Core(ThreadingActor): def uri_schemes(self): """List of URI schemes we can handle""" return self._backend.uri_schemes.get() + + def reached_end_of_stream(self): + self.playback.on_end_of_track() From 9798c34e79eccf45c5ffbadc25fd631c30a7d7bc Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 00:14:40 +0200 Subject: [PATCH 07/15] Remove unused variable --- mopidy/audio/__init__.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mopidy/audio/__init__.py b/mopidy/audio/__init__.py index 4abd5774..10a74959 100644 --- a/mopidy/audio/__init__.py +++ b/mopidy/audio/__init__.py @@ -32,15 +32,6 @@ class Audio(ThreadingActor): def __init__(self): super(Audio, self).__init__() - self._default_caps = gst.Caps(""" - audio/x-raw-int, - endianness=(int)1234, - channels=(int)2, - width=(int)16, - depth=(int)16, - signed=(boolean)true, - rate=(int)44100""") - self._playbin = None self._mixer = None self._mixer_track = None From 63cd153b1b2b3a58a4b5741c935c86735928f56f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 00:45:09 +0200 Subject: [PATCH 08/15] Let NetworkServer pass protocol_kwargs on --- mopidy/utils/network.py | 19 +++++++++++++++---- tests/utils/network/connection_test.py | 13 ++++++++----- tests/utils/network/server_test.py | 3 ++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/mopidy/utils/network.py b/mopidy/utils/network.py index 9cb8d74c..d2e0690b 100644 --- a/mopidy/utils/network.py +++ b/mopidy/utils/network.py @@ -11,11 +11,14 @@ from pykka.registry import ActorRegistry from mopidy.utils import locale_decode + logger = logging.getLogger('mopidy.utils.server') + class ShouldRetrySocketCall(Exception): """Indicate that attempted socket call should be retried""" + def try_ipv6_socket(): """Determine if system really supports IPv6""" if not socket.has_ipv6: @@ -28,9 +31,11 @@ def try_ipv6_socket(): 'creation failed, disabling: %s', locale_decode(error)) return False + #: Boolean value that indicates if creating an IPv6 socket will succeed. has_ipv6 = try_ipv6_socket() + def create_socket(): """Create a TCP socket with or without IPv6 depending on system support""" if has_ipv6: @@ -42,17 +47,21 @@ def create_socket(): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) return sock + def format_hostname(hostname): """Format hostname for display.""" if (has_ipv6 and re.match('\d+.\d+.\d+.\d+', hostname) is not None): hostname = '::ffff:%s' % hostname return hostname + class Server(object): """Setup listener and register it with gobject's event loop.""" - def __init__(self, host, port, protocol, max_connections=5, timeout=30): + def __init__(self, host, port, protocol, protocol_kwargs=None, + max_connections=5, timeout=30): self.protocol = protocol + self.protocol_kwargs = protocol_kwargs or {} self.max_connections = max_connections self.timeout = timeout self.server_socket = self.create_server_socket(host, port) @@ -105,7 +114,8 @@ class Server(object): pass def init_connection(self, sock, addr): - Connection(self.protocol, sock, addr, self.timeout) + Connection(self.protocol, self.protocol_kwargs, + sock, addr, self.timeout) class Connection(object): @@ -117,13 +127,14 @@ class Connection(object): # false return value would only tell us that what we thought was registered # is already gone, there is really nothing more we can do. - def __init__(self, protocol, sock, addr, timeout): + def __init__(self, protocol, protocol_kwargs, sock, addr, timeout): sock.setblocking(False) self.host, self.port = addr[:2] # IPv6 has larger addr self.sock = sock self.protocol = protocol + self.protocol_kwargs = protocol_kwargs self.timeout = timeout self.send_lock = threading.Lock() @@ -135,7 +146,7 @@ class Connection(object): self.send_id = None self.timeout_id = None - self.actor_ref = self.protocol.start(self) + self.actor_ref = self.protocol.start(self, **self.protocol_kwargs) self.enable_recv() self.enable_timeout() diff --git a/tests/utils/network/connection_test.py b/tests/utils/network/connection_test.py index 96ddb833..25ae1940 100644 --- a/tests/utils/network/connection_test.py +++ b/tests/utils/network/connection_test.py @@ -17,19 +17,19 @@ class ConnectionTest(unittest.TestCase): def test_init_ensure_nonblocking_io(self): sock = Mock(spec=socket.SocketType) - network.Connection.__init__(self.mock, Mock(), sock, + network.Connection.__init__(self.mock, Mock(), {}, sock, (sentinel.host, sentinel.port), sentinel.timeout) sock.setblocking.assert_called_once_with(False) def test_init_starts_actor(self): protocol = Mock(spec=network.LineProtocol) - network.Connection.__init__(self.mock, protocol, Mock(), + network.Connection.__init__(self.mock, protocol, {}, Mock(), (sentinel.host, sentinel.port), sentinel.timeout) protocol.start.assert_called_once_with(self.mock) def test_init_enables_recv_and_timeout(self): - network.Connection.__init__(self.mock, Mock(), Mock(), + network.Connection.__init__(self.mock, Mock(), {}, Mock(), (sentinel.host, sentinel.port), sentinel.timeout) self.mock.enable_recv.assert_called_once_with() self.mock.enable_timeout.assert_called_once_with() @@ -37,12 +37,14 @@ class ConnectionTest(unittest.TestCase): def test_init_stores_values_in_attributes(self): addr = (sentinel.host, sentinel.port) protocol = Mock(spec=network.LineProtocol) + protocol_kwargs = {} sock = Mock(spec=socket.SocketType) network.Connection.__init__( - self.mock, protocol, sock, addr, sentinel.timeout) + self.mock, protocol, protocol_kwargs, sock, addr, sentinel.timeout) self.assertEqual(sock, self.mock.sock) self.assertEqual(protocol, self.mock.protocol) + self.assertEqual(protocol_kwargs, self.mock.protocol_kwargs) self.assertEqual(sentinel.timeout, self.mock.timeout) self.assertEqual(sentinel.host, self.mock.host) self.assertEqual(sentinel.port, self.mock.port) @@ -51,10 +53,11 @@ class ConnectionTest(unittest.TestCase): addr = (sentinel.host, sentinel.port, sentinel.flowinfo, sentinel.scopeid) protocol = Mock(spec=network.LineProtocol) + protocol_kwargs = {} sock = Mock(spec=socket.SocketType) network.Connection.__init__( - self.mock, protocol, sock, addr, sentinel.timeout) + self.mock, protocol, protocol_kwargs, sock, addr, sentinel.timeout) self.assertEqual(sentinel.host, self.mock.host) self.assertEqual(sentinel.port, self.mock.port) diff --git a/tests/utils/network/server_test.py b/tests/utils/network/server_test.py index e0399525..268b5dbd 100644 --- a/tests/utils/network/server_test.py +++ b/tests/utils/network/server_test.py @@ -164,10 +164,11 @@ class ServerTest(unittest.TestCase): @patch.object(network, 'Connection', new=Mock()) def test_init_connection(self): self.mock.protocol = sentinel.protocol + self.mock.protocol_kwargs = {} self.mock.timeout = sentinel.timeout network.Server.init_connection(self.mock, sentinel.sock, sentinel.addr) - network.Connection.assert_called_once_with(sentinel.protocol, + network.Connection.assert_called_once_with(sentinel.protocol, {}, sentinel.sock, sentinel.addr, sentinel.timeout) def test_reject_connection(self): From 706b6c6d3f9f89a92e435ac3b7751b38fb58cc63 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 00:14:21 +0200 Subject: [PATCH 09/15] Pass core actor to frontends --- docs/api/frontends.rst | 18 ++++++++++++++++-- mopidy/__main__.py | 10 +++++----- mopidy/frontends/lastfm.py | 2 +- mopidy/frontends/mpd/__init__.py | 2 +- mopidy/frontends/mpris/__init__.py | 2 +- tests/frontends/mpris/events_test.py | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/api/frontends.rst b/docs/api/frontends.rst index af0cc991..36626fa0 100644 --- a/docs/api/frontends.rst +++ b/docs/api/frontends.rst @@ -6,22 +6,36 @@ The following requirements applies to any frontend implementation: - A frontend MAY do mostly whatever it wants to, including creating threads, opening TCP ports and exposing Mopidy for a group of clients. + - A frontend MUST implement at least one `Pykka `_ actor, called the "main actor" from here on. + +- The main actor MUST accept a constructor argument ``core``, which will be an + :class:`ActorProxy ` for the core actor. This object + gives access to the full :ref:`core-api`. + - It MAY use additional actors to implement whatever it does, and using actors in frontend implementations is encouraged. + - The frontend is activated by including its main actor in the :attr:`mopidy.settings.FRONTENDS` setting. + - The main actor MUST be able to start and stop the frontend when the main actor is started and stopped. + - The frontend MAY require additional settings to be set for it to work. + - Such settings MUST be documented. + - The main actor MUST stop itself if the defined settings are not adequate for the frontend to work properly. -- Any actor which is part of the frontend MAY implement any listener interface - from :mod:`mopidy.listeners` to receive notification of the specified events. + +- Any actor which is part of the frontend MAY implement the + :class:`mopidy.core.CoreListener` interface to receive notification of the + specified events. + Frontend implementations ======================== diff --git a/mopidy/__main__.py b/mopidy/__main__.py index ee2e21b6..dbdb193b 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -54,8 +54,8 @@ def main(): setup_settings(options.interactive) audio = setup_audio() backend = setup_backend(audio) - setup_core(audio, backend) - setup_frontends() + core = setup_core(audio, backend) + setup_frontends(core) loop.run() except SettingsError as e: logger.error(e.message) @@ -137,17 +137,17 @@ def stop_backend(): def setup_core(audio, backend): - return Core.start(audio, backend).proxy() + return Core.start(audio=audio, backend=backend).proxy() def stop_core(): stop_actors_by_class(Core) -def setup_frontends(): +def setup_frontends(core): for frontend_class_name in settings.FRONTENDS: try: - get_class(frontend_class_name).start() + get_class(frontend_class_name).start(core=core) except OptionalDependencyError as e: logger.info(u'Disabled: %s (%s)', frontend_class_name, e) diff --git a/mopidy/frontends/lastfm.py b/mopidy/frontends/lastfm.py index f2bc44d2..37fbafe2 100644 --- a/mopidy/frontends/lastfm.py +++ b/mopidy/frontends/lastfm.py @@ -37,7 +37,7 @@ class LastfmFrontend(ThreadingActor, core.CoreListener): - :attr:`mopidy.settings.LASTFM_PASSWORD` """ - def __init__(self): + def __init__(self, core): super(LastfmFrontend, self).__init__() self.lastfm = None self.last_start_time = None diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py index 9dcf4c34..f8c7a9ef 100644 --- a/mopidy/frontends/mpd/__init__.py +++ b/mopidy/frontends/mpd/__init__.py @@ -26,7 +26,7 @@ class MpdFrontend(actor.ThreadingActor, core.CoreListener): - :attr:`mopidy.settings.MPD_SERVER_PASSWORD` """ - def __init__(self): + def __init__(self, core): super(MpdFrontend, self).__init__() hostname = network.format_hostname(settings.MPD_SERVER_HOSTNAME) port = settings.MPD_SERVER_PORT diff --git a/mopidy/frontends/mpris/__init__.py b/mopidy/frontends/mpris/__init__.py index 2815c551..769f2e84 100644 --- a/mopidy/frontends/mpris/__init__.py +++ b/mopidy/frontends/mpris/__init__.py @@ -55,7 +55,7 @@ class MprisFrontend(ThreadingActor, core.CoreListener): player.Quit(dbus_interface='org.mpris.MediaPlayer2') """ - def __init__(self): + def __init__(self, core): super(MprisFrontend, self).__init__() self.indicate_server = None self.mpris_object = None diff --git a/tests/frontends/mpris/events_test.py b/tests/frontends/mpris/events_test.py index 3db03ccf..f466e207 100644 --- a/tests/frontends/mpris/events_test.py +++ b/tests/frontends/mpris/events_test.py @@ -16,7 +16,7 @@ from tests import unittest @unittest.skipUnless(sys.platform.startswith('linux'), 'requires Linux') class BackendEventsTest(unittest.TestCase): def setUp(self): - self.mpris_frontend = MprisFrontend() # As a plain class, not an actor + self.mpris_frontend = MprisFrontend(core=None) # As a plain class, not an actor self.mpris_object = mock.Mock(spec=objects.MprisObject) self.mpris_frontend.mpris_object = self.mpris_object From 9fd3e93cb6fa8438cc54c0115bd8c393e8c353b0 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 00:15:47 +0200 Subject: [PATCH 10/15] MPRIS: Use core actor passed to frontend --- mopidy/frontends/mpris/__init__.py | 3 ++- mopidy/frontends/mpris/objects.py | 22 +++++-------------- .../frontends/mpris/player_interface_test.py | 3 +-- tests/frontends/mpris/root_interface_test.py | 2 +- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/mopidy/frontends/mpris/__init__.py b/mopidy/frontends/mpris/__init__.py index 769f2e84..1a8797f2 100644 --- a/mopidy/frontends/mpris/__init__.py +++ b/mopidy/frontends/mpris/__init__.py @@ -57,12 +57,13 @@ class MprisFrontend(ThreadingActor, core.CoreListener): def __init__(self, core): super(MprisFrontend, self).__init__() + self.core = core self.indicate_server = None self.mpris_object = None def on_start(self): try: - self.mpris_object = objects.MprisObject() + self.mpris_object = objects.MprisObject(self.core) self._send_startup_notification() except Exception as e: logger.error(u'MPRIS frontend setup failed (%s)', e) diff --git a/mopidy/frontends/mpris/objects.py b/mopidy/frontends/mpris/objects.py index cb1e73eb..7c8b6f5a 100644 --- a/mopidy/frontends/mpris/objects.py +++ b/mopidy/frontends/mpris/objects.py @@ -1,8 +1,6 @@ import logging import os -logger = logging.getLogger('mopidy.frontends.mpris') - try: import dbus import dbus.mainloop.glib @@ -12,12 +10,13 @@ except ImportError as import_error: from mopidy import OptionalDependencyError raise OptionalDependencyError(import_error) -from pykka.registry import ActorRegistry - -from mopidy import core, settings +from mopidy import settings from mopidy.core import PlaybackState from mopidy.utils.process import exit_process + +logger = logging.getLogger('mopidy.frontends.mpris') + # Must be done before dbus.SessionBus() is called gobject.threads_init() dbus.mainloop.glib.threads_init() @@ -33,8 +32,8 @@ class MprisObject(dbus.service.Object): properties = None - def __init__(self): - self._core = None + def __init__(self, core): + self.core = core self.properties = { ROOT_IFACE: self._get_root_iface_properties(), PLAYER_IFACE: self._get_player_iface_properties(), @@ -83,15 +82,6 @@ class MprisObject(dbus.service.Object): logger.info(u'Connected to D-Bus') return bus_name - @property - def core(self): - if self._core is None: - core_refs = ActorRegistry.get_by_class(core.Core) - assert len(core_refs) == 1, \ - 'Expected exactly one running core instance.' - self._core = core_refs[0].proxy() - return self._core - def _get_track_id(self, cp_track): return '/com/mopidy/track/%d' % cp_track.cpid diff --git a/tests/frontends/mpris/player_interface_test.py b/tests/frontends/mpris/player_interface_test.py index 236ec645..403d05c7 100644 --- a/tests/frontends/mpris/player_interface_test.py +++ b/tests/frontends/mpris/player_interface_test.py @@ -27,8 +27,7 @@ class PlayerInterfaceTest(unittest.TestCase): objects.MprisObject._connect_to_dbus = mock.Mock() self.backend = dummy.DummyBackend.start(audio=None).proxy() self.core = core.Core.start(backend=self.backend).proxy() - self.mpris = objects.MprisObject() - self.mpris._core = self.core + self.mpris = objects.MprisObject(core=self.core) def tearDown(self): ActorRegistry.stop_all() diff --git a/tests/frontends/mpris/root_interface_test.py b/tests/frontends/mpris/root_interface_test.py index b84b70c3..847ed2de 100644 --- a/tests/frontends/mpris/root_interface_test.py +++ b/tests/frontends/mpris/root_interface_test.py @@ -22,7 +22,7 @@ class RootInterfaceTest(unittest.TestCase): objects.MprisObject._connect_to_dbus = mock.Mock() self.backend = dummy.DummyBackend.start(audio=None).proxy() self.core = core.Core.start(backend=self.backend).proxy() - self.mpris = objects.MprisObject() + self.mpris = objects.MprisObject(core=self.core) def tearDown(self): ActorRegistry.stop_all() From c115cf123f8be2725885ec885417c076f990aaeb Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 00:46:44 +0200 Subject: [PATCH 11/15] MPD: Use core actor passed to frontend --- mopidy/frontends/mpd/__init__.py | 7 ++++--- mopidy/frontends/mpd/dispatcher.py | 23 +++++++---------------- tests/frontends/mpd/protocol/__init__.py | 2 +- tests/frontends/mpd/status_test.py | 2 +- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py index f8c7a9ef..d7eeaaa3 100644 --- a/mopidy/frontends/mpd/__init__.py +++ b/mopidy/frontends/mpd/__init__.py @@ -32,7 +32,8 @@ class MpdFrontend(actor.ThreadingActor, core.CoreListener): port = settings.MPD_SERVER_PORT try: - network.Server(hostname, port, protocol=MpdSession, + network.Server(hostname, port, + protocol=MpdSession, protocol_kwargs={'core': core}, max_connections=settings.MPD_SERVER_MAX_CONNECTIONS) except IOError as error: logger.error(u'MPD server startup failed: %s', locale_decode(error)) @@ -76,9 +77,9 @@ class MpdSession(network.LineProtocol): encoding = protocol.ENCODING delimiter = r'\r?\n' - def __init__(self, connection): + def __init__(self, connection, core=None): super(MpdSession, self).__init__(connection) - self.dispatcher = dispatcher.MpdDispatcher(self) + self.dispatcher = dispatcher.MpdDispatcher(session=self, core=core) def on_start(self): logger.info(u'New MPD connection from [%s]:%s', self.host, self.port) diff --git a/mopidy/frontends/mpd/dispatcher.py b/mopidy/frontends/mpd/dispatcher.py index 1f2af153..c29cdf4d 100644 --- a/mopidy/frontends/mpd/dispatcher.py +++ b/mopidy/frontends/mpd/dispatcher.py @@ -27,12 +27,12 @@ class MpdDispatcher(object): _noidle = re.compile(r'^noidle$') - def __init__(self, session=None): + def __init__(self, session=None, core=None): self.authenticated = False self.command_list = False self.command_list_ok = False self.command_list_index = None - self.context = MpdContext(self, session=session) + self.context = MpdContext(self, session=session, core=core) def handle_request(self, request, current_command_list_index=None): """Dispatch incoming requests to the correct handler.""" @@ -221,27 +221,18 @@ class MpdContext(object): #: The current :class:`mopidy.frontends.mpd.MpdSession`. session = None + #: The Mopidy core API. An instance of :class:`mopidy.core.Core`. + core = None + #: The active subsystems that have pending events. events = None #: The subsytems that we want to be notified about in idle mode. subscriptions = None - def __init__(self, dispatcher, session=None): + def __init__(self, dispatcher, session=None, core=None): self.dispatcher = dispatcher self.session = session + self.core = core self.events = set() self.subscriptions = set() - self._core = None - - @property - def core(self): - """ - The Mopidy core. An instance of :class:`mopidy.core.Core`. - """ - if self._core is None: - core_refs = ActorRegistry.get_by_class(core.Core) - assert len(core_refs) == 1, \ - 'Expected exactly one running core instance.' - self._core = core_refs[0].proxy() - return self._core diff --git a/tests/frontends/mpd/protocol/__init__.py b/tests/frontends/mpd/protocol/__init__.py index a2dafb9b..041b6532 100644 --- a/tests/frontends/mpd/protocol/__init__.py +++ b/tests/frontends/mpd/protocol/__init__.py @@ -27,7 +27,7 @@ class BaseTestCase(unittest.TestCase): self.core = core.Core.start(backend=self.backend).proxy() self.connection = MockConnection() - self.session = mpd.MpdSession(self.connection) + self.session = mpd.MpdSession(self.connection, core=self.core) self.dispatcher = self.session.dispatcher self.context = self.dispatcher.context diff --git a/tests/frontends/mpd/status_test.py b/tests/frontends/mpd/status_test.py index 3a5bdcbe..6322ec36 100644 --- a/tests/frontends/mpd/status_test.py +++ b/tests/frontends/mpd/status_test.py @@ -22,7 +22,7 @@ class StatusHandlerTest(unittest.TestCase): def setUp(self): self.backend = dummy.DummyBackend.start(audio=None).proxy() self.core = core.Core.start(backend=self.backend).proxy() - self.dispatcher = dispatcher.MpdDispatcher() + self.dispatcher = dispatcher.MpdDispatcher(core=self.core) self.context = self.dispatcher.context def tearDown(self): From 609bd6a5b5d12215d7ffb3385d177381966d5993 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 01:38:39 +0200 Subject: [PATCH 12/15] Limit audio access to the playback provider --- mopidy/backends/base/__init__.py | 3 --- mopidy/backends/base/playback.py | 23 +++++++++--------- mopidy/backends/dummy/__init__.py | 6 ++--- mopidy/backends/local/__init__.py | 6 ++--- mopidy/backends/spotify/__init__.py | 28 ++++++++-------------- mopidy/backends/spotify/playback.py | 12 +++++----- mopidy/backends/spotify/session_manager.py | 5 ++-- 7 files changed, 35 insertions(+), 48 deletions(-) diff --git a/mopidy/backends/base/__init__.py b/mopidy/backends/base/__init__.py index 4e0f0b08..c27acae2 100644 --- a/mopidy/backends/base/__init__.py +++ b/mopidy/backends/base/__init__.py @@ -24,6 +24,3 @@ class Backend(object): #: List of URI schemes this backend can handle. uri_schemes = [] - - def __init__(self, audio): - self.audio = audio diff --git a/mopidy/backends/base/playback.py b/mopidy/backends/base/playback.py index 197ba90e..635146ff 100644 --- a/mopidy/backends/base/playback.py +++ b/mopidy/backends/base/playback.py @@ -6,7 +6,8 @@ class BasePlaybackProvider(object): pykka_traversable = True - def __init__(self, backend): + def __init__(self, audio, backend): + self.audio = audio self.backend = backend def pause(self): @@ -17,7 +18,7 @@ class BasePlaybackProvider(object): :rtype: :class:`True` if successful, else :class:`False` """ - return self.backend.audio.pause_playback().get() + return self.audio.pause_playback().get() def play(self, track): """ @@ -29,9 +30,9 @@ class BasePlaybackProvider(object): :type track: :class:`mopidy.models.Track` :rtype: :class:`True` if successful, else :class:`False` """ - self.backend.audio.prepare_change() - self.backend.audio.set_uri(track.uri).get() - return self.backend.audio.start_playback().get() + self.audio.prepare_change() + self.audio.set_uri(track.uri).get() + return self.audio.start_playback().get() def resume(self): """ @@ -41,7 +42,7 @@ class BasePlaybackProvider(object): :rtype: :class:`True` if successful, else :class:`False` """ - return self.backend.audio.start_playback().get() + return self.audio.start_playback().get() def seek(self, time_position): """ @@ -53,7 +54,7 @@ class BasePlaybackProvider(object): :type time_position: int :rtype: :class:`True` if successful, else :class:`False` """ - return self.backend.audio.set_position(time_position).get() + return self.audio.set_position(time_position).get() def stop(self): """ @@ -63,7 +64,7 @@ class BasePlaybackProvider(object): :rtype: :class:`True` if successful, else :class:`False` """ - return self.backend.audio.stop_playback().get() + return self.audio.stop_playback().get() def get_time_position(self): """ @@ -73,7 +74,7 @@ class BasePlaybackProvider(object): :rtype: int """ - return self.backend.audio.get_position().get() + return self.audio.get_position().get() def get_volume(self): """ @@ -83,7 +84,7 @@ class BasePlaybackProvider(object): :rtype: int [0..100] or :class:`None` """ - return self.backend.audio.get_volume().get() + return self.audio.get_volume().get() def set_volume(self, volume): """ @@ -94,4 +95,4 @@ class BasePlaybackProvider(object): :param: volume :type volume: int [0..100] """ - self.backend.audio.set_volume(volume) + self.audio.set_volume(volume) diff --git a/mopidy/backends/dummy/__init__.py b/mopidy/backends/dummy/__init__.py index 1d69ed7c..5e028ea3 100644 --- a/mopidy/backends/dummy/__init__.py +++ b/mopidy/backends/dummy/__init__.py @@ -12,11 +12,9 @@ class DummyBackend(ThreadingActor, base.Backend): Handles URIs starting with ``dummy:``. """ - def __init__(self, *args, **kwargs): - base.Backend.__init__(self, *args, **kwargs) - + def __init__(self, audio): self.library = DummyLibraryProvider(backend=self) - self.playback = DummyPlaybackProvider(backend=self) + self.playback = DummyPlaybackProvider(audio=audio, backend=self) self.stored_playlists = DummyStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'dummy'] diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index f3e86679..ee8448b3 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -30,11 +30,9 @@ class LocalBackend(ThreadingActor, base.Backend): - :attr:`mopidy.settings.LOCAL_TAG_CACHE_FILE` """ - def __init__(self, *args, **kwargs): - base.Backend.__init__(self, *args, **kwargs) - + def __init__(self, audio): self.library = LocalLibraryProvider(backend=self) - self.playback = base.BasePlaybackProvider(backend=self) + self.playback = base.BasePlaybackProvider(audio=audio, backend=self) self.stored_playlists = LocalStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'file'] diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py index a79168f5..0e2a2bfa 100644 --- a/mopidy/backends/spotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -41,37 +41,29 @@ class SpotifyBackend(ThreadingActor, base.Backend): # Imports inside methods are to prevent loading of __init__.py to fail on # missing spotify dependencies. - def __init__(self, *args, **kwargs): + def __init__(self, audio): from .library import SpotifyLibraryProvider from .playback import SpotifyPlaybackProvider + from .session_manager import SpotifySessionManager from .stored_playlists import SpotifyStoredPlaylistsProvider - base.Backend.__init__(self, *args, **kwargs) - self.library = SpotifyLibraryProvider(backend=self) - self.playback = SpotifyPlaybackProvider(backend=self) + self.playback = SpotifyPlaybackProvider(audio=audio, backend=self) self.stored_playlists = SpotifyStoredPlaylistsProvider(backend=self) self.uri_schemes = [u'spotify'] - self.spotify = None - # Fail early if settings are not present - self.username = settings.SPOTIFY_USERNAME - self.password = settings.SPOTIFY_PASSWORD + username = settings.SPOTIFY_USERNAME + password = settings.SPOTIFY_PASSWORD + + self.spotify = SpotifySessionManager(username, password, + audio=audio, backend_ref=self.actor_ref) def on_start(self): logger.info(u'Mopidy uses SPOTIFY(R) CORE') - self.spotify = self._connect() + logger.debug(u'Connecting to Spotify') + self.spotify.start() def on_stop(self): self.spotify.logout() - - def _connect(self): - from .session_manager import SpotifySessionManager - - logger.debug(u'Connecting to Spotify') - spotify = SpotifySessionManager(self.username, self.password, - audio=self.audio, backend=self.actor_ref.proxy()) - spotify.start() - return spotify diff --git a/mopidy/backends/spotify/playback.py b/mopidy/backends/spotify/playback.py index 94d57f56..d3d0cfa9 100644 --- a/mopidy/backends/spotify/playback.py +++ b/mopidy/backends/spotify/playback.py @@ -30,10 +30,10 @@ class SpotifyPlaybackProvider(BasePlaybackProvider): Link.from_string(track.uri).as_track()) self.backend.spotify.session.play(1) - self.backend.audio.prepare_change() - self.backend.audio.set_uri('appsrc://') - self.backend.audio.start_playback() - self.backend.audio.set_metadata(track) + self.audio.prepare_change() + self.audio.set_uri('appsrc://') + self.audio.start_playback() + self.audio.set_metadata(track) self._timer.play() @@ -50,9 +50,9 @@ class SpotifyPlaybackProvider(BasePlaybackProvider): return self.seek(time_position) def seek(self, time_position): - self.backend.audio.prepare_change() + self.audio.prepare_change() self.backend.spotify.session.seek(time_position) - self.backend.audio.start_playback() + self.audio.start_playback() self._timer.seek(time_position) diff --git a/mopidy/backends/spotify/session_manager.py b/mopidy/backends/spotify/session_manager.py index 52769d84..dab759c9 100644 --- a/mopidy/backends/spotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -24,13 +24,13 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key') user_agent = 'Mopidy %s' % get_version() - def __init__(self, username, password, audio, backend): + def __init__(self, username, password, audio, backend_ref): PyspotifySessionManager.__init__(self, username, password) BaseThread.__init__(self) self.name = 'SpotifyThread' self.audio = audio - self.backend = backend + self.backend_ref = backend_ref self.connected = threading.Event() self.session = None @@ -41,6 +41,7 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): self._initial_data_receive_completed = False def run_inside_try(self): + self.backend = self.backend_ref.proxy() self.connect() def logged_in(self, session, error): From c6b38820ce20026ed9a36ff28e303f39a0a41c2d Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 01:58:53 +0200 Subject: [PATCH 13/15] Remove volume handling from backends --- mopidy/backends/base/playback.py | 21 --------------------- mopidy/backends/dummy/__init__.py | 7 ------- mopidy/core/playback.py | 15 ++++++++++++--- 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/mopidy/backends/base/playback.py b/mopidy/backends/base/playback.py index 635146ff..b21c30dc 100644 --- a/mopidy/backends/base/playback.py +++ b/mopidy/backends/base/playback.py @@ -75,24 +75,3 @@ class BasePlaybackProvider(object): :rtype: int """ return self.audio.get_position().get() - - def get_volume(self): - """ - Get current volume - - *MAY be reimplemented by subclass.* - - :rtype: int [0..100] or :class:`None` - """ - return self.audio.get_volume().get() - - def set_volume(self, volume): - """ - Get current volume - - *MAY be reimplemented by subclass.* - - :param: volume - :type volume: int [0..100] - """ - self.audio.set_volume(volume) diff --git a/mopidy/backends/dummy/__init__.py b/mopidy/backends/dummy/__init__.py index 5e028ea3..6c3e1437 100644 --- a/mopidy/backends/dummy/__init__.py +++ b/mopidy/backends/dummy/__init__.py @@ -44,7 +44,6 @@ class DummyPlaybackProvider(base.BasePlaybackProvider): def __init__(self, *args, **kwargs): super(DummyPlaybackProvider, self).__init__(*args, **kwargs) self._time_position = 0 - self._volume = None def pause(self): return True @@ -67,12 +66,6 @@ class DummyPlaybackProvider(base.BasePlaybackProvider): def get_time_position(self): return self._time_position - def get_volume(self): - return self._volume - - def set_volume(self, volume): - self._volume = volume - class DummyStoredPlaylistsProvider(base.BaseStoredPlaylistsProvider): def create(self, name): diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index 603b40a4..a86c5650 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -86,6 +86,7 @@ class PlaybackController(object): self._state = PlaybackState.STOPPED self._shuffled = [] self._first_shuffle = True + self._volume = None def _get_cpid(self, cp_track): if cp_track is None: @@ -296,12 +297,20 @@ class PlaybackController(object): @property def volume(self): - """Volume as int in range [0..100].""" - return self.backend.playback.get_volume().get() + """Volume as int in range [0..100] or :class:`None`""" + if self.audio: + return self.audio.get_volume().get() + else: + # For testing + return self._volume @volume.setter def volume(self, volume): - self.backend.playback.set_volume(volume).get() + if self.audio: + self.audio.set_volume(volume) + else: + # For testing + self._volume = volume def change_track(self, cp_track, on_error_step=1): """ From fe80189accc89f65ebe94fda93366609e7ae26a4 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 02:20:35 +0200 Subject: [PATCH 14/15] Simplify import --- mopidy/__main__.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index dbdb193b..a67c58b8 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -32,12 +32,10 @@ from mopidy import (get_version, settings, OptionalDependencyError, SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) from mopidy.audio import Audio from mopidy.core import Core -from mopidy.utils import get_class +from mopidy.utils import get_class, process from mopidy.utils.deps import list_deps_optparse_callback from mopidy.utils.log import setup_logging from mopidy.utils.path import get_or_create_folder, get_or_create_file -from mopidy.utils.process import (exit_handler, stop_remaining_actors, - stop_actors_by_class) from mopidy.utils.settings import list_settings_optparse_callback @@ -45,7 +43,7 @@ logger = logging.getLogger('mopidy.main') def main(): - signal.signal(signal.SIGTERM, exit_handler) + signal.signal(signal.SIGTERM, process.exit_handler) loop = gobject.MainLoop() options = parse_options() try: @@ -69,7 +67,7 @@ def main(): stop_core() stop_backend() stop_audio() - stop_remaining_actors() + process.stop_remaining_actors() def parse_options(): @@ -125,7 +123,7 @@ def setup_audio(): def stop_audio(): - stop_actors_by_class(Audio) + process.stop_actors_by_class(Audio) def setup_backend(audio): @@ -133,7 +131,7 @@ def setup_backend(audio): def stop_backend(): - stop_actors_by_class(get_class(settings.BACKENDS[0])) + process.stop_actors_by_class(get_class(settings.BACKENDS[0])) def setup_core(audio, backend): @@ -141,7 +139,7 @@ def setup_core(audio, backend): def stop_core(): - stop_actors_by_class(Core) + process.stop_actors_by_class(Core) def setup_frontends(core): @@ -155,7 +153,7 @@ def setup_frontends(core): def stop_frontends(): for frontend_class_name in settings.FRONTENDS: try: - stop_actors_by_class(get_class(frontend_class_name)) + process.stop_actors_by_class(get_class(frontend_class_name)) except OptionalDependencyError: pass From 3c66b3a011ca8833b0e54ad01c69139f33b05e41 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 28 Sep 2012 11:40:31 +0200 Subject: [PATCH 15/15] Use module imports --- mopidy/__main__.py | 56 +++++++++++++++------------------ mopidy/core/current_playlist.py | 4 +-- mopidy/core/playback.py | 16 +++++----- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index a67c58b8..3e586044 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -28,14 +28,10 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) -from mopidy import (get_version, settings, OptionalDependencyError, - SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) -from mopidy.audio import Audio -from mopidy.core import Core -from mopidy.utils import get_class, process +import mopidy +from mopidy import audio, core, settings, utils +from mopidy.utils import log, path, process from mopidy.utils.deps import list_deps_optparse_callback -from mopidy.utils.log import setup_logging -from mopidy.utils.path import get_or_create_folder, get_or_create_file from mopidy.utils.settings import list_settings_optparse_callback @@ -47,7 +43,7 @@ def main(): loop = gobject.MainLoop() options = parse_options() try: - setup_logging(options.verbosity_level, options.save_debug_log) + log.setup_logging(options.verbosity_level, options.save_debug_log) check_old_folders() setup_settings(options.interactive) audio = setup_audio() @@ -55,12 +51,12 @@ def main(): core = setup_core(audio, backend) setup_frontends(core) loop.run() - except SettingsError as e: - logger.error(e.message) + except mopidy.SettingsError as ex: + logger.error(ex.message) except KeyboardInterrupt: logger.info(u'Interrupted. Exiting...') - except Exception as e: - logger.exception(e) + except Exception as ex: + logger.exception(ex) finally: loop.quit() stop_frontends() @@ -71,7 +67,7 @@ def main(): def parse_options(): - parser = optparse.OptionParser(version=u'Mopidy %s' % get_version()) + parser = optparse.OptionParser(version=u'Mopidy %s' % mopidy.get_version()) parser.add_option('--help-gst', action='store_true', dest='help_gst', help='show GStreamer help options') @@ -104,57 +100,57 @@ def check_old_folders(): logger.warning(u'Old settings folder found at %s, settings.py should be ' 'moved to %s, any cache data should be deleted. See release notes ' - 'for further instructions.', old_settings_folder, SETTINGS_PATH) + 'for further instructions.', old_settings_folder, mopidy.SETTINGS_PATH) def setup_settings(interactive): - get_or_create_folder(SETTINGS_PATH) - get_or_create_folder(DATA_PATH) - get_or_create_file(SETTINGS_FILE) + path.get_or_create_folder(mopidy.SETTINGS_PATH) + path.get_or_create_folder(mopidy.DATA_PATH) + path.get_or_create_file(mopidy.SETTINGS_FILE) try: settings.validate(interactive) - except SettingsError, e: - logger.error(e.message) + except mopidy.SettingsError as ex: + logger.error(ex.message) sys.exit(1) def setup_audio(): - return Audio.start().proxy() + return audio.Audio.start().proxy() def stop_audio(): - process.stop_actors_by_class(Audio) + process.stop_actors_by_class(audio.Audio) def setup_backend(audio): - return get_class(settings.BACKENDS[0]).start(audio=audio).proxy() + return utils.get_class(settings.BACKENDS[0]).start(audio=audio).proxy() def stop_backend(): - process.stop_actors_by_class(get_class(settings.BACKENDS[0])) + process.stop_actors_by_class(utils.get_class(settings.BACKENDS[0])) def setup_core(audio, backend): - return Core.start(audio=audio, backend=backend).proxy() + return core.Core.start(audio=audio, backend=backend).proxy() def stop_core(): - process.stop_actors_by_class(Core) + process.stop_actors_by_class(core.Core) def setup_frontends(core): for frontend_class_name in settings.FRONTENDS: try: - get_class(frontend_class_name).start(core=core) - except OptionalDependencyError as e: - logger.info(u'Disabled: %s (%s)', frontend_class_name, e) + utils.get_class(frontend_class_name).start(core=core) + except mopidy.OptionalDependencyError as ex: + logger.info(u'Disabled: %s (%s)', frontend_class_name, ex) def stop_frontends(): for frontend_class_name in settings.FRONTENDS: try: - process.stop_actors_by_class(get_class(frontend_class_name)) - except OptionalDependencyError: + process.stop_actors_by_class(utils.get_class(frontend_class_name)) + except mopidy.OptionalDependencyError: pass diff --git a/mopidy/core/current_playlist.py b/mopidy/core/current_playlist.py index 973fe71f..17cd70ad 100644 --- a/mopidy/core/current_playlist.py +++ b/mopidy/core/current_playlist.py @@ -4,7 +4,7 @@ import random from mopidy.models import CpTrack -from .listener import CoreListener +from . import listener logger = logging.getLogger('mopidy.core') @@ -241,4 +241,4 @@ class CurrentPlaylistController(object): def _trigger_playlist_changed(self): logger.debug(u'Triggering playlist changed event') - CoreListener.send('playlist_changed') + listener.CoreListener.send('playlist_changed') diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index a86c5650..f3592831 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -1,7 +1,7 @@ import logging import random -from .listener import CoreListener +from . import listener logger = logging.getLogger('mopidy.backends.base') @@ -488,7 +488,7 @@ class PlaybackController(object): logger.debug(u'Triggering track playback paused event') if self.current_track is None: return - CoreListener.send('track_playback_paused', + listener.CoreListener.send('track_playback_paused', track=self.current_track, time_position=self.time_position) @@ -496,7 +496,7 @@ class PlaybackController(object): logger.debug(u'Triggering track playback resumed event') if self.current_track is None: return - CoreListener.send('track_playback_resumed', + listener.CoreListener.send('track_playback_resumed', track=self.current_track, time_position=self.time_position) @@ -504,26 +504,26 @@ class PlaybackController(object): logger.debug(u'Triggering track playback started event') if self.current_track is None: return - CoreListener.send('track_playback_started', + listener.CoreListener.send('track_playback_started', track=self.current_track) def _trigger_track_playback_ended(self): logger.debug(u'Triggering track playback ended event') if self.current_track is None: return - CoreListener.send('track_playback_ended', + listener.CoreListener.send('track_playback_ended', track=self.current_track, time_position=self.time_position) def _trigger_playback_state_changed(self, old_state, new_state): logger.debug(u'Triggering playback state change event') - CoreListener.send('playback_state_changed', + listener.CoreListener.send('playback_state_changed', old_state=old_state, new_state=new_state) def _trigger_options_changed(self): logger.debug(u'Triggering options changed event') - CoreListener.send('options_changed') + listener.CoreListener.send('options_changed') def _trigger_seeked(self, time_position): logger.debug(u'Triggering seeked event') - CoreListener.send('seeked', time_position=time_position) + listener.CoreListener.send('seeked', time_position=time_position)