backend: Move backend API to mopidy.backend
Keep imports from old locations working until extensions have been updated to use the new location.
This commit is contained in:
parent
ff4c965aff
commit
b6b542a60f
@ -4,46 +4,46 @@
|
|||||||
Backend API
|
Backend API
|
||||||
***********
|
***********
|
||||||
|
|
||||||
.. module:: mopidy.backends.base
|
.. module:: mopidy.backend
|
||||||
:synopsis: The API implemented by backends
|
:synopsis: The API implemented by backends
|
||||||
|
|
||||||
The backend API is the interface that must be implemented when you create a
|
The backend API is the interface that must be implemented when you create a
|
||||||
backend. If you are working on a frontend and need to access the backend, see
|
backend. If you are working on a frontend and need to access the backends, see
|
||||||
the :ref:`core-api`.
|
the :ref:`core-api` instead.
|
||||||
|
|
||||||
|
|
||||||
Backend class
|
Backend class
|
||||||
=============
|
=============
|
||||||
|
|
||||||
.. autoclass:: mopidy.backends.base.Backend
|
.. autoclass:: mopidy.backend.Backend
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Playback provider
|
Playback provider
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. autoclass:: mopidy.backends.base.BasePlaybackProvider
|
.. autoclass:: mopidy.backend.PlaybackProvider
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Playlists provider
|
Playlists provider
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. autoclass:: mopidy.backends.base.BasePlaylistsProvider
|
.. autoclass:: mopidy.backend.PlaylistsProvider
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Library provider
|
Library provider
|
||||||
================
|
================
|
||||||
|
|
||||||
.. autoclass:: mopidy.backends.base.BaseLibraryProvider
|
.. autoclass:: mopidy.backend.LibraryProvider
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Backend listener
|
Backend listener
|
||||||
================
|
================
|
||||||
|
|
||||||
.. autoclass:: mopidy.backends.listener.BackendListener
|
.. autoclass:: mopidy.backend.BackendListener
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,28 @@ v0.18.0 (UNRELEASED)
|
|||||||
virtual file system of tracks. Backends can implement support for this by
|
virtual file system of tracks. Backends can implement support for this by
|
||||||
implementing :meth:`mopidy.backends.base.BaseLibraryController.browse`.
|
implementing :meth:`mopidy.backends.base.BaseLibraryController.browse`.
|
||||||
|
|
||||||
|
**Backend API**
|
||||||
|
|
||||||
|
- Move the backend API classes from :mod:`mopidy.backends.base` to
|
||||||
|
:mod:`mopidy.backend` and remove the ``Base`` prefix from the class names:
|
||||||
|
|
||||||
|
- From :class:`mopidy.backends.base.Backend`
|
||||||
|
to :class:`mopidy.backend.Backend`
|
||||||
|
|
||||||
|
- From :class:`mopidy.backends.base.BaseLibraryProvider`
|
||||||
|
to :class:`mopidy.backend.LibraryProvider`
|
||||||
|
|
||||||
|
- From :class:`mopidy.backends.base.BasePlaybackProvider`
|
||||||
|
to :class:`mopidy.backend.PlaybackProvider`
|
||||||
|
|
||||||
|
- From :class:`mopidy.backends.base.BasePlaylistsProvider`
|
||||||
|
to :class:`mopidy.backend.PlaylistsProvider`
|
||||||
|
|
||||||
|
- From :class:`mopidy.backends.listener.BackendListener`
|
||||||
|
to :class:`mopidy.backend.BackendListener`
|
||||||
|
|
||||||
|
Imports from the old locations still works, but are deprecated.
|
||||||
|
|
||||||
**Configuration**
|
**Configuration**
|
||||||
|
|
||||||
- The default for the :option:`mopidy --config` option has been updated to
|
- The default for the :option:`mopidy --config` option has been updated to
|
||||||
|
|||||||
294
mopidy/backend.py
Normal file
294
mopidy/backend.py
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from mopidy import listener
|
||||||
|
|
||||||
|
|
||||||
|
class Backend(object):
|
||||||
|
#: Actor proxy to an instance of :class:`mopidy.audio.Audio`.
|
||||||
|
#:
|
||||||
|
#: Should be passed to the backend constructor as the kwarg ``audio``,
|
||||||
|
#: which will then set this field.
|
||||||
|
audio = None
|
||||||
|
|
||||||
|
#: The library provider. An instance of
|
||||||
|
#: :class:`~mopidy.backend.LibraryProvider`, or :class:`None` if
|
||||||
|
#: the backend doesn't provide a library.
|
||||||
|
library = None
|
||||||
|
|
||||||
|
#: The playback provider. An instance of
|
||||||
|
#: :class:`~mopidy.backend.PlaybackProvider`, or :class:`None` if
|
||||||
|
#: the backend doesn't provide playback.
|
||||||
|
playback = None
|
||||||
|
|
||||||
|
#: The playlists provider. An instance of
|
||||||
|
#: :class:`~mopidy.backend.PlaylistsProvider`, or class:`None` if
|
||||||
|
#: the backend doesn't provide playlists.
|
||||||
|
playlists = None
|
||||||
|
|
||||||
|
#: List of URI schemes this backend can handle.
|
||||||
|
uri_schemes = []
|
||||||
|
|
||||||
|
# Because the providers is marked as pykka_traversible, we can't get() them
|
||||||
|
# from another actor, and need helper methods to check if the providers are
|
||||||
|
# set or None.
|
||||||
|
|
||||||
|
def has_library(self):
|
||||||
|
return self.library is not None
|
||||||
|
|
||||||
|
def has_playback(self):
|
||||||
|
return self.playback is not None
|
||||||
|
|
||||||
|
def has_playlists(self):
|
||||||
|
return self.playlists is not None
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryProvider(object):
|
||||||
|
"""
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`mopidy.backend.Backend`
|
||||||
|
"""
|
||||||
|
|
||||||
|
pykka_traversable = True
|
||||||
|
|
||||||
|
root_directory_name = None
|
||||||
|
"""
|
||||||
|
Name of the library's root directory in Mopidy's virtual file system.
|
||||||
|
|
||||||
|
*MUST be set by any class that implements :meth:`browse`.*
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, backend):
|
||||||
|
self.backend = backend
|
||||||
|
|
||||||
|
def browse(self, path):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.LibraryController.browse`.
|
||||||
|
|
||||||
|
If you implement this method, make sure to also set
|
||||||
|
:attr:`root_directory_name`.
|
||||||
|
|
||||||
|
*MAY be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
# TODO: replace with search(query, exact=True, ...)
|
||||||
|
def find_exact(self, query=None, uris=None):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.LibraryController.find_exact`.
|
||||||
|
|
||||||
|
*MAY be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def lookup(self, uri):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.LibraryController.lookup`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def refresh(self, uri=None):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.LibraryController.refresh`.
|
||||||
|
|
||||||
|
*MAY be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def search(self, query=None, uris=None):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.LibraryController.search`.
|
||||||
|
|
||||||
|
*MAY be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PlaybackProvider(object):
|
||||||
|
"""
|
||||||
|
:param audio: the audio actor
|
||||||
|
:type audio: actor proxy to an instance of :class:`mopidy.audio.Audio`
|
||||||
|
:param backend: the backend
|
||||||
|
:type backend: :class:`mopidy.backend.Backend`
|
||||||
|
"""
|
||||||
|
|
||||||
|
pykka_traversable = True
|
||||||
|
|
||||||
|
def __init__(self, audio, backend):
|
||||||
|
self.audio = audio
|
||||||
|
self.backend = backend
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
"""
|
||||||
|
Pause playback.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
return self.audio.pause_playback().get()
|
||||||
|
|
||||||
|
def play(self, track):
|
||||||
|
"""
|
||||||
|
Play given track.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:param track: the track to play
|
||||||
|
:type track: :class:`mopidy.models.Track`
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
self.audio.prepare_change()
|
||||||
|
self.change_track(track)
|
||||||
|
return self.audio.start_playback().get()
|
||||||
|
|
||||||
|
def change_track(self, track):
|
||||||
|
"""
|
||||||
|
Swith to provided track.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:param track: the track to play
|
||||||
|
:type track: :class:`mopidy.models.Track`
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
self.audio.set_uri(track.uri).get()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
"""
|
||||||
|
Resume playback at the same time position playback was paused.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
return self.audio.start_playback().get()
|
||||||
|
|
||||||
|
def seek(self, time_position):
|
||||||
|
"""
|
||||||
|
Seek to a given time position.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:param time_position: time position in milliseconds
|
||||||
|
:type time_position: int
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
return self.audio.set_position(time_position).get()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Stop playback.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:rtype: :class:`True` if successful, else :class:`False`
|
||||||
|
"""
|
||||||
|
return self.audio.stop_playback().get()
|
||||||
|
|
||||||
|
def get_time_position(self):
|
||||||
|
"""
|
||||||
|
Get the current time position in milliseconds.
|
||||||
|
|
||||||
|
*MAY be reimplemented by subclass.*
|
||||||
|
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
return self.audio.get_position().get()
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistsProvider(object):
|
||||||
|
"""
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`mopidy.backend.Backend` instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
pykka_traversable = True
|
||||||
|
|
||||||
|
def __init__(self, backend):
|
||||||
|
self.backend = backend
|
||||||
|
self._playlists = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def playlists(self):
|
||||||
|
"""
|
||||||
|
Currently available playlists.
|
||||||
|
|
||||||
|
Read/write. List of :class:`mopidy.models.Playlist`.
|
||||||
|
"""
|
||||||
|
return copy.copy(self._playlists)
|
||||||
|
|
||||||
|
@playlists.setter # noqa
|
||||||
|
def playlists(self, playlists):
|
||||||
|
self._playlists = playlists
|
||||||
|
|
||||||
|
def create(self, name):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.PlaylistsController.create`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def delete(self, uri):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.PlaylistsController.delete`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def lookup(self, uri):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.PlaylistsController.lookup`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.PlaylistsController.refresh`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def save(self, playlist):
|
||||||
|
"""
|
||||||
|
See :meth:`mopidy.core.PlaylistsController.save`.
|
||||||
|
|
||||||
|
*MUST be implemented by subclass.*
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class BackendListener(listener.Listener):
|
||||||
|
"""
|
||||||
|
Marker interface for recipients of events sent by the backend actors.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Normally, only the Core actor should mix in this class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def send(event, **kwargs):
|
||||||
|
"""Helper to allow calling of backend listener events"""
|
||||||
|
listener.send_async(BackendListener, event, **kwargs)
|
||||||
|
|
||||||
|
def playlists_loaded(self):
|
||||||
|
"""
|
||||||
|
Called when playlists are loaded or refreshed.
|
||||||
|
|
||||||
|
*MAY* be implemented by actor.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
@ -1,265 +1,17 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import copy
|
from mopidy.backend import (
|
||||||
|
Backend,
|
||||||
|
LibraryProvider as BaseLibraryProvider,
|
||||||
class Backend(object):
|
PlaybackProvider as BasePlaybackProvider,
|
||||||
#: Actor proxy to an instance of :class:`mopidy.audio.Audio`.
|
PlaylistsProvider as BasePlaylistsProvider)
|
||||||
#:
|
|
||||||
#: Should be passed to the backend constructor as the kwarg ``audio``,
|
|
||||||
#: which will then set this field.
|
# Make classes previously residing here available in the old location for
|
||||||
audio = None
|
# backwards compatibility with extensions targeting Mopidy < 0.18.
|
||||||
|
__all__ = [
|
||||||
#: The library provider. An instance of
|
'Backend',
|
||||||
#: :class:`~mopidy.backends.base.BaseLibraryProvider`, or :class:`None` if
|
'BaseLibraryProvider',
|
||||||
#: the backend doesn't provide a library.
|
'BasePlaybackProvider',
|
||||||
library = None
|
'BasePlaylistsProvider',
|
||||||
|
]
|
||||||
#: The playback provider. An instance of
|
|
||||||
#: :class:`~mopidy.backends.base.BasePlaybackProvider`, or :class:`None` if
|
|
||||||
#: the backend doesn't provide playback.
|
|
||||||
playback = None
|
|
||||||
|
|
||||||
#: The playlists provider. An instance of
|
|
||||||
#: :class:`~mopidy.backends.base.BasePlaylistsProvider`, or class:`None` if
|
|
||||||
#: the backend doesn't provide playlists.
|
|
||||||
playlists = None
|
|
||||||
|
|
||||||
#: List of URI schemes this backend can handle.
|
|
||||||
uri_schemes = []
|
|
||||||
|
|
||||||
# Because the providers is marked as pykka_traversible, we can't get() them
|
|
||||||
# from another actor, and need helper methods to check if the providers are
|
|
||||||
# set or None.
|
|
||||||
|
|
||||||
def has_library(self):
|
|
||||||
return self.library is not None
|
|
||||||
|
|
||||||
def has_playback(self):
|
|
||||||
return self.playback is not None
|
|
||||||
|
|
||||||
def has_playlists(self):
|
|
||||||
return self.playlists is not None
|
|
||||||
|
|
||||||
|
|
||||||
class BaseLibraryProvider(object):
|
|
||||||
"""
|
|
||||||
:param backend: backend the controller is a part of
|
|
||||||
:type backend: :class:`mopidy.backends.base.Backend`
|
|
||||||
"""
|
|
||||||
|
|
||||||
pykka_traversable = True
|
|
||||||
|
|
||||||
root_directory_name = None
|
|
||||||
"""
|
|
||||||
Name of the library's root directory in Mopidy's virtual file system.
|
|
||||||
|
|
||||||
*MUST be set by any class that implements :meth:`browse`.*
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, backend):
|
|
||||||
self.backend = backend
|
|
||||||
|
|
||||||
def browse(self, path):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.LibraryController.browse`.
|
|
||||||
|
|
||||||
If you implement this method, make sure to also set
|
|
||||||
:attr:`root_directory_name`.
|
|
||||||
|
|
||||||
*MAY be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
return []
|
|
||||||
|
|
||||||
# TODO: replace with search(query, exact=True, ...)
|
|
||||||
def find_exact(self, query=None, uris=None):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.LibraryController.find_exact`.
|
|
||||||
|
|
||||||
*MAY be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def lookup(self, uri):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.LibraryController.lookup`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def refresh(self, uri=None):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.LibraryController.refresh`.
|
|
||||||
|
|
||||||
*MAY be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def search(self, query=None, uris=None):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.LibraryController.search`.
|
|
||||||
|
|
||||||
*MAY be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BasePlaybackProvider(object):
|
|
||||||
"""
|
|
||||||
:param audio: the audio actor
|
|
||||||
:type audio: actor proxy to an instance of :class:`mopidy.audio.Audio`
|
|
||||||
:param backend: the backend
|
|
||||||
:type backend: :class:`mopidy.backends.base.Backend`
|
|
||||||
"""
|
|
||||||
|
|
||||||
pykka_traversable = True
|
|
||||||
|
|
||||||
def __init__(self, audio, backend):
|
|
||||||
self.audio = audio
|
|
||||||
self.backend = backend
|
|
||||||
|
|
||||||
def pause(self):
|
|
||||||
"""
|
|
||||||
Pause playback.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
return self.audio.pause_playback().get()
|
|
||||||
|
|
||||||
def play(self, track):
|
|
||||||
"""
|
|
||||||
Play given track.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:param track: the track to play
|
|
||||||
:type track: :class:`mopidy.models.Track`
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
self.audio.prepare_change()
|
|
||||||
self.change_track(track)
|
|
||||||
return self.audio.start_playback().get()
|
|
||||||
|
|
||||||
def change_track(self, track):
|
|
||||||
"""
|
|
||||||
Swith to provided track.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:param track: the track to play
|
|
||||||
:type track: :class:`mopidy.models.Track`
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
self.audio.set_uri(track.uri).get()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def resume(self):
|
|
||||||
"""
|
|
||||||
Resume playback at the same time position playback was paused.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
return self.audio.start_playback().get()
|
|
||||||
|
|
||||||
def seek(self, time_position):
|
|
||||||
"""
|
|
||||||
Seek to a given time position.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:param time_position: time position in milliseconds
|
|
||||||
:type time_position: int
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
return self.audio.set_position(time_position).get()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
"""
|
|
||||||
Stop playback.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:rtype: :class:`True` if successful, else :class:`False`
|
|
||||||
"""
|
|
||||||
return self.audio.stop_playback().get()
|
|
||||||
|
|
||||||
def get_time_position(self):
|
|
||||||
"""
|
|
||||||
Get the current time position in milliseconds.
|
|
||||||
|
|
||||||
*MAY be reimplemented by subclass.*
|
|
||||||
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
return self.audio.get_position().get()
|
|
||||||
|
|
||||||
|
|
||||||
class BasePlaylistsProvider(object):
|
|
||||||
"""
|
|
||||||
:param backend: backend the controller is a part of
|
|
||||||
:type backend: :class:`mopidy.backends.base.Backend`
|
|
||||||
"""
|
|
||||||
|
|
||||||
pykka_traversable = True
|
|
||||||
|
|
||||||
def __init__(self, backend):
|
|
||||||
self.backend = backend
|
|
||||||
self._playlists = []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def playlists(self):
|
|
||||||
"""
|
|
||||||
Currently available playlists.
|
|
||||||
|
|
||||||
Read/write. List of :class:`mopidy.models.Playlist`.
|
|
||||||
"""
|
|
||||||
return copy.copy(self._playlists)
|
|
||||||
|
|
||||||
@playlists.setter # noqa
|
|
||||||
def playlists(self, playlists):
|
|
||||||
self._playlists = playlists
|
|
||||||
|
|
||||||
def create(self, name):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.PlaylistsController.create`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def delete(self, uri):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.PlaylistsController.delete`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def lookup(self, uri):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.PlaylistsController.lookup`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def refresh(self):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.PlaylistsController.refresh`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def save(self, playlist):
|
|
||||||
"""
|
|
||||||
See :meth:`mopidy.core.PlaylistsController.save`.
|
|
||||||
|
|
||||||
*MUST be implemented by subclass.*
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|||||||
@ -1,30 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from mopidy import listener
|
from mopidy.backend import BackendListener
|
||||||
|
|
||||||
|
|
||||||
class BackendListener(listener.Listener):
|
# Make classes previously residing here available in the old location for
|
||||||
"""
|
# backwards compatibility with extensions targeting Mopidy < 0.18.
|
||||||
Marker interface for recipients of events sent by the backend actors.
|
__all__ = ['BackendListener']
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Normally, only the Core actor should mix in this class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def send(event, **kwargs):
|
|
||||||
"""Helper to allow calling of backend listener events"""
|
|
||||||
listener.send_async(BackendListener, event, **kwargs)
|
|
||||||
|
|
||||||
def playlists_loaded(self):
|
|
||||||
"""
|
|
||||||
Called when playlists are loaded or refreshed.
|
|
||||||
|
|
||||||
*MAY* be implemented by actor.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user