Merge branch 'master' of git://github.com/jodal/mopidy
This commit is contained in:
commit
45af7ef21e
@ -24,10 +24,46 @@ modular, so we can extend it with other backends in the future, like file
|
|||||||
playback and other online music services such as Last.fm.
|
playback and other online music services such as Last.fm.
|
||||||
|
|
||||||
|
|
||||||
|
Code style
|
||||||
|
==========
|
||||||
|
|
||||||
|
We generally follow the `PEP-8 <http://www.python.org/dev/peps/pep-0008/>`_
|
||||||
|
style guidelines, with a couple of notable exceptions:
|
||||||
|
|
||||||
|
- We indent continuation lines with four spaces more than the previous line.
|
||||||
|
For example::
|
||||||
|
|
||||||
|
from mopidy.backends import (BaseBackend, BaseCurrentPlaylistController,
|
||||||
|
BasePlaybackController, BaseLibraryController,
|
||||||
|
BaseStoredPlaylistsController)
|
||||||
|
|
||||||
|
And not::
|
||||||
|
|
||||||
|
from mopidy.backends import (BaseBackend, BaseCurrentPlaylistController,
|
||||||
|
BasePlaybackController, BaseLibraryController,
|
||||||
|
BaseStoredPlaylistsController)
|
||||||
|
|
||||||
|
- An exception to the previous exception: When continuing control flow
|
||||||
|
statements like ``if``, ``for`` and ``while``, we indent with eight spaces
|
||||||
|
more than the previous line. In other words, the line is indented one level
|
||||||
|
further to the right than the following block of code. For example::
|
||||||
|
|
||||||
|
if (old_state in (self.PLAYING, self.STOPPED)
|
||||||
|
and new_state == self.PLAYING):
|
||||||
|
self._play_time_start()
|
||||||
|
|
||||||
|
And not::
|
||||||
|
|
||||||
|
if (old_state in (self.PLAYING, self.STOPPED)
|
||||||
|
and new_state == self.PLAYING):
|
||||||
|
self._play_time_start()
|
||||||
|
|
||||||
|
|
||||||
Running tests
|
Running tests
|
||||||
=============
|
=============
|
||||||
|
|
||||||
To run tests, you need a couple of dependiencies. Some can be installed through Debian/Ubuntu package management::
|
To run tests, you need a couple of dependencies. Some can be installed through
|
||||||
|
Debian/Ubuntu package management::
|
||||||
|
|
||||||
sudo aptitude install python-coverage
|
sudo aptitude install python-coverage
|
||||||
|
|
||||||
|
|||||||
@ -23,34 +23,58 @@ Dependencies
|
|||||||
.. _despotify:
|
.. _despotify:
|
||||||
|
|
||||||
despotify backend
|
despotify backend
|
||||||
=================
|
-----------------
|
||||||
|
|
||||||
To use the despotify backend, you first need to install despotify and spytify.
|
To use the despotify backend, you first need to install despotify and spytify.
|
||||||
|
|
||||||
*This backend requires a Spotify premium account.*
|
.. note::
|
||||||
|
|
||||||
|
This backend requires a Spotify premium account.
|
||||||
|
|
||||||
|
|
||||||
Installing despotify and spytify
|
Installing despotify
|
||||||
--------------------------------
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Install despotify's dependencies. At Debian/Ubuntu systems::
|
*Linux:* Install despotify's dependencies. At Debian/Ubuntu systems::
|
||||||
|
|
||||||
sudo aptitude install libssl-dev zlib1g-dev libvorbis-dev \
|
sudo aptitude install libssl-dev zlib1g-dev libvorbis-dev \
|
||||||
libtool libncursesw5-dev libao-dev
|
libtool libncursesw5-dev libao-dev
|
||||||
|
|
||||||
Check out revision 503 of the despotify source code::
|
*OS X:* In OS X you need to have `XCode
|
||||||
|
<http://developer.apple.com/tools/xcode/>`_ and `MacPorts
|
||||||
|
<http://www.macports.org/>`_ installed. Then, to install despotify's
|
||||||
|
dependencies::
|
||||||
|
|
||||||
svn co https://despotify.svn.sourceforge.net/svnroot/despotify@503 despotify
|
sudo port install openssl zlib libvorbis libtool ncursesw libao
|
||||||
|
|
||||||
Build and install despotify::
|
*All OS:* Check out revision 503 of the despotify source code::
|
||||||
|
|
||||||
|
svn co https://despotify.svn.sourceforge.net/svnroot/despotify@503
|
||||||
|
|
||||||
|
*OS X:* Edit ``despotify/src/Makefile.local.mk`` and uncomment the last two
|
||||||
|
lines so that it reads::
|
||||||
|
|
||||||
|
## If you're on Mac OS X and have installed libvorbisfile
|
||||||
|
## via 'port install ..', try uncommenting these lines
|
||||||
|
CFLAGS += -I/opt/local/include
|
||||||
|
LDFLAGS += -L/opt/local/lib
|
||||||
|
|
||||||
|
*All OS:* Build and install despotify::
|
||||||
|
|
||||||
cd despotify/src/
|
cd despotify/src/
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
|
|
||||||
|
Installing spytify
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
spytify's source comes bundled with despotify.
|
||||||
|
|
||||||
Build and install spytify::
|
Build and install spytify::
|
||||||
|
|
||||||
cd despotify/src/bindings/python/
|
cd despotify/src/bindings/python/
|
||||||
|
export PKG_CONFIG_PATH=../../lib # Needed on OS X
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
@ -64,22 +88,24 @@ Spotify Premium account), ask for a search query, list all your playlists with
|
|||||||
tracks, play 10s from a random song from the search result, pause for two
|
tracks, play 10s from a random song from the search result, pause for two
|
||||||
seconds, play for five more seconds, and quit.
|
seconds, play for five more seconds, and quit.
|
||||||
|
|
||||||
|
|
||||||
.. _libspotify:
|
.. _libspotify:
|
||||||
|
|
||||||
libspotify backend
|
libspotify backend
|
||||||
==================
|
------------------
|
||||||
|
|
||||||
As an alternative to the despotify backend, we are working on a libspotify
|
As an alternative to the despotify backend, we are working on a libspotify
|
||||||
backend. To use the libspotify backend you must install libspotify and
|
backend. To use the libspotify backend you must install libspotify and
|
||||||
pyspotify.
|
pyspotify.
|
||||||
|
|
||||||
*This backend requires a Spotify premium account.*
|
.. note::
|
||||||
|
|
||||||
*This backend requires you to get an application key from Spotify before use.*
|
This backend requires a Spotify premium account, and it requires you to get
|
||||||
|
an application key from Spotify before use.
|
||||||
|
|
||||||
|
|
||||||
Installing libspotify and pyspotify
|
Installing libspotify
|
||||||
-----------------------------------
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
As libspotify's installation script at the moment is somewhat broken (see this
|
As libspotify's installation script at the moment is somewhat broken (see this
|
||||||
`GetSatisfaction thread <http://getsatisfaction.com/spotify/topics/libspotify_please_fix_the_installation_script>`_
|
`GetSatisfaction thread <http://getsatisfaction.com/spotify/topics/libspotify_please_fix_the_installation_script>`_
|
||||||
@ -87,6 +113,10 @@ for details), it is easiest to use the libspotify files bundled with pyspotify.
|
|||||||
The files bundled with pyspotify are for 64-bit, so if you run a 32-bit OS, you
|
The files bundled with pyspotify are for 64-bit, so if you run a 32-bit OS, you
|
||||||
must get libspotify from https://developer.spotify.com/en/libspotify/.
|
must get libspotify from https://developer.spotify.com/en/libspotify/.
|
||||||
|
|
||||||
|
|
||||||
|
Installing pyspotify
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Install pyspotify's dependencies. At Debian/Ubuntu systems::
|
Install pyspotify's dependencies. At Debian/Ubuntu systems::
|
||||||
|
|
||||||
sudo aptitude install python-alsaaudio
|
sudo aptitude install python-alsaaudio
|
||||||
@ -106,13 +136,15 @@ Test your libspotify setup::
|
|||||||
|
|
||||||
./example1.py -u USERNAME -p PASSWORD
|
./example1.py -u USERNAME -p PASSWORD
|
||||||
|
|
||||||
Until Spotify fixes their installation script, you'll have to set
|
.. note::
|
||||||
``LD_LIBRARY_PATH`` every time you are going to use libspotify (in other words
|
|
||||||
before starting Mopidy).
|
Until Spotify fixes their installation script, you'll have to set
|
||||||
|
``LD_LIBRARY_PATH`` every time you are going to use libspotify (in other
|
||||||
|
words before starting Mopidy).
|
||||||
|
|
||||||
|
|
||||||
Running Mopidy
|
Settings
|
||||||
==============
|
========
|
||||||
|
|
||||||
Create a file name ``local_settings.py`` in the same directory as
|
Create a file name ``local_settings.py`` in the same directory as
|
||||||
``settings.py``. Enter your Spotify Premium account's username and password
|
``settings.py``. Enter your Spotify Premium account's username and password
|
||||||
@ -128,6 +160,9 @@ libspotify backend, copy the Spotify application key to
|
|||||||
|
|
||||||
BACKEND = u'mopidy.backends.libspotify.LibspotifyBackend'
|
BACKEND = u'mopidy.backends.libspotify.LibspotifyBackend'
|
||||||
|
|
||||||
|
Running Mopidy
|
||||||
|
==============
|
||||||
|
|
||||||
To start Mopidy, go to the root of the Mopidy project, then simply run::
|
To start Mopidy, go to the root of the Mopidy project, then simply run::
|
||||||
|
|
||||||
python mopidy
|
python mopidy
|
||||||
|
|||||||
@ -74,6 +74,7 @@ class BaseCurrentPlaylistController(object):
|
|||||||
|
|
||||||
:param id: track ID
|
:param id: track ID
|
||||||
:type id: int
|
:type id: int
|
||||||
|
:rtype: :class:`mopidy.models.Track`
|
||||||
"""
|
"""
|
||||||
matches = filter(lambda t: t.id == id, self._playlist.tracks)
|
matches = filter(lambda t: t.id == id, self._playlist.tracks)
|
||||||
if matches:
|
if matches:
|
||||||
@ -87,6 +88,7 @@ class BaseCurrentPlaylistController(object):
|
|||||||
|
|
||||||
:param uri: track URI
|
:param uri: track URI
|
||||||
:type uri: string
|
:type uri: string
|
||||||
|
:rtype: :class:`mopidy.models.Track`
|
||||||
"""
|
"""
|
||||||
matches = filter(lambda t: t.uri == uri, self._playlist.tracks)
|
matches = filter(lambda t: t.uri == uri, self._playlist.tracks)
|
||||||
if matches:
|
if matches:
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import datetime as dt
|
import datetime as dt
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import time
|
|
||||||
|
|
||||||
from spotify import Link
|
from spotify import Link
|
||||||
from spotify.manager import SpotifySessionManager
|
from spotify.manager import SpotifySessionManager
|
||||||
@ -42,21 +41,23 @@ class LibspotifyCurrentPlaylistController(BaseCurrentPlaylistController):
|
|||||||
|
|
||||||
|
|
||||||
class LibspotifyLibraryController(BaseLibraryController):
|
class LibspotifyLibraryController(BaseLibraryController):
|
||||||
search_results = False
|
_search_results = None
|
||||||
|
_search_results_received = threading.Event()
|
||||||
|
|
||||||
def search(self, type, what):
|
def search(self, type, what):
|
||||||
# XXX This is slow
|
# FIXME When searching while playing music, this is really slow, like
|
||||||
self.search_results = None
|
# 12-14s between querying and getting results.
|
||||||
|
self._search_results_received.clear()
|
||||||
|
query = u'%s:%s' % (type, what)
|
||||||
def callback(results, userdata):
|
def callback(results, userdata):
|
||||||
logger.debug(u'Search results received')
|
logger.debug(u'Search results received')
|
||||||
self.search_results = results
|
self._search_results = results
|
||||||
query = u'%s:%s' % (type, what)
|
self._search_results_received.set()
|
||||||
self.backend.spotify.search(query.encode(ENCODING), callback)
|
self.backend.spotify.search(query.encode(ENCODING), callback)
|
||||||
while self.search_results is None:
|
self._search_results_received.wait()
|
||||||
time.sleep(0.01)
|
|
||||||
result = Playlist(tracks=[self.backend.translate.to_mopidy_track(t)
|
result = Playlist(tracks=[self.backend.translate.to_mopidy_track(t)
|
||||||
for t in self.search_results.tracks()])
|
for t in self._search_results.tracks()])
|
||||||
self.search_results = False
|
self._search_results = None
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
class ImmutableObject(object):
|
class ImmutableObject(object):
|
||||||
|
"""
|
||||||
|
Superclass for immutable objects whose fields can only be modified via the
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
:param kwargs: kwargs to set as fields on the object
|
||||||
|
:type kwargs: any
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
|
|||||||
@ -66,10 +66,19 @@ class MpdHandler(object):
|
|||||||
response.append(u'%s: %s' % (key, value))
|
response.append(u'%s: %s' % (key, value))
|
||||||
else:
|
else:
|
||||||
response.append(line)
|
response.append(line)
|
||||||
if add_ok:
|
if add_ok and (not response or not response[-1].startswith(u'ACK')):
|
||||||
response.append(u'OK')
|
response.append(u'OK')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@register(r'^ack$')
|
||||||
|
def _ack(self):
|
||||||
|
"""
|
||||||
|
Always returns an 'ACK' and not 'OK'.
|
||||||
|
|
||||||
|
Not a part of the MPD protocol.
|
||||||
|
"""
|
||||||
|
raise MpdNotImplemented
|
||||||
|
|
||||||
@register(r'^add "(?P<uri>[^"]*)"$')
|
@register(r'^add "(?P<uri>[^"]*)"$')
|
||||||
def _add(self, uri):
|
def _add(self, uri):
|
||||||
raise MpdNotImplemented # TODO
|
raise MpdNotImplemented # TODO
|
||||||
@ -109,10 +118,16 @@ class MpdHandler(object):
|
|||||||
response = self.handle_request(command, add_ok=False)
|
response = self.handle_request(command, add_ok=False)
|
||||||
if response is not None:
|
if response is not None:
|
||||||
result.append(response)
|
result.append(response)
|
||||||
|
if response and response[-1].startswith(u'ACK'):
|
||||||
|
return result
|
||||||
if command_list_ok:
|
if command_list_ok:
|
||||||
response.append(u'list_OK')
|
response.append(u'list_OK')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@register(r'^commands$')
|
||||||
|
def _commands(self):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^consume "(?P<state>[01])"$')
|
@register(r'^consume "(?P<state>[01])"$')
|
||||||
def _consume(self, state):
|
def _consume(self, state):
|
||||||
state = int(state)
|
state = int(state)
|
||||||
@ -133,7 +148,12 @@ class MpdHandler(object):
|
|||||||
@register(r'^currentsong$')
|
@register(r'^currentsong$')
|
||||||
def _currentsong(self):
|
def _currentsong(self):
|
||||||
if self.backend.playback.current_track is not None:
|
if self.backend.playback.current_track is not None:
|
||||||
return self.backend.playback.current_track.mpd_format()
|
return self.backend.playback.current_track.mpd_format(
|
||||||
|
position=self.backend.playback.playlist_position)
|
||||||
|
|
||||||
|
@register(r'^decoders$')
|
||||||
|
def _decoders(self):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^delete "(?P<songpos>\d+)"$')
|
@register(r'^delete "(?P<songpos>\d+)"$')
|
||||||
@register(r'^delete "(?P<start>\d+):(?P<end>\d+)*"$')
|
@register(r'^delete "(?P<start>\d+):(?P<end>\d+)*"$')
|
||||||
@ -142,12 +162,25 @@ class MpdHandler(object):
|
|||||||
|
|
||||||
@register(r'^deleteid "(?P<songid>\d+)"$')
|
@register(r'^deleteid "(?P<songid>\d+)"$')
|
||||||
def _deleteid(self, songid):
|
def _deleteid(self, songid):
|
||||||
|
songid = int(songid)
|
||||||
|
try:
|
||||||
|
track = self.backend.current_playlist.get_by_id(songid)
|
||||||
|
return self.backend.current_playlist.remove(track)
|
||||||
|
except KeyError, e:
|
||||||
|
raise MpdAckError(unicode(e))
|
||||||
|
|
||||||
|
@register(r'^disableoutput "(?P<outputid>\d+)"$')
|
||||||
|
def _disableoutput(self, outputid):
|
||||||
raise MpdNotImplemented # TODO
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^$')
|
@register(r'^$')
|
||||||
def _empty(self):
|
def _empty(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@register(r'^enableoutput "(?P<outputid>\d+)"$')
|
||||||
|
def _enableoutput(self, outputid):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^find "(?P<type>(album|artist|title))" "(?P<what>[^"]+)"$')
|
@register(r'^find "(?P<type>(album|artist|title))" "(?P<what>[^"]+)"$')
|
||||||
def _find(self, type, what):
|
def _find(self, type, what):
|
||||||
raise MpdNotImplemented # TODO
|
raise MpdNotImplemented # TODO
|
||||||
@ -220,6 +253,10 @@ class MpdHandler(object):
|
|||||||
def _next(self):
|
def _next(self):
|
||||||
return self.backend.playback.next()
|
return self.backend.playback.next()
|
||||||
|
|
||||||
|
@register(r'^notcommands$')
|
||||||
|
def _notcommands(self):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^outputs$')
|
@register(r'^outputs$')
|
||||||
def _outputs(self):
|
def _outputs(self):
|
||||||
return [
|
return [
|
||||||
@ -511,6 +548,26 @@ class MpdHandler(object):
|
|||||||
def _status_xfade(self):
|
def _status_xfade(self):
|
||||||
return 0 # TODO
|
return 0 # TODO
|
||||||
|
|
||||||
|
@register(r'^sticker delete "(?P<type>[^"]+)" "(?P<uri>[^"]+)"( "(?P<name>[^"]+)")*$')
|
||||||
|
def _sticker_delete(self, type, uri, name=None):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
@register(r'^sticker find "(?P<type>[^"]+)" "(?P<uri>[^"]+)" "(?P<name>[^"]+)"$')
|
||||||
|
def sticker_find(self, type, uri, name):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
@register(r'^sticker get "(?P<type>[^"]+)" "(?P<uri>[^"]+)" "(?P<name>[^"]+)"$')
|
||||||
|
def _sticker_get(self, type, uri, name):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
@register(r'^sticker list "(?P<type>[^"]+)" "(?P<uri>[^"]+)"$')
|
||||||
|
def _sticker_list(self, type, uri):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
@register(r'^sticker set "(?P<type>[^"]+)" "(?P<uri>[^"]+)" "(?P<name>[^"]+)" "(?P<value>[^"]+)"$')
|
||||||
|
def _sticker_set(self, type, uri, name, value):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^swap "(?P<songpos1>\d+)" "(?P<songpos2>\d+)"$')
|
@register(r'^swap "(?P<songpos1>\d+)" "(?P<songpos2>\d+)"$')
|
||||||
def _swap(self, songpos1, songpos2):
|
def _swap(self, songpos1, songpos2):
|
||||||
raise MpdNotImplemented # TODO
|
raise MpdNotImplemented # TODO
|
||||||
@ -519,6 +576,10 @@ class MpdHandler(object):
|
|||||||
def _swapid(self, songid1, songid2):
|
def _swapid(self, songid1, songid2):
|
||||||
raise MpdNotImplemented # TODO
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
|
@register(r'^tagtypes$')
|
||||||
|
def _tagtypes(self):
|
||||||
|
raise MpdNotImplemented # TODO
|
||||||
|
|
||||||
@register(r'^update( "(?P<uri>[^"]+)")*$')
|
@register(r'^update( "(?P<uri>[^"]+)")*$')
|
||||||
def _update(self, uri=None, rescan_unmodified_files=False):
|
def _update(self, uri=None, rescan_unmodified_files=False):
|
||||||
return {'updating_db': 0} # TODO
|
return {'updating_db': 0} # TODO
|
||||||
|
|||||||
@ -48,7 +48,8 @@ class MpdSession(asynchat.async_chat):
|
|||||||
def handle_request(self, input):
|
def handle_request(self, input):
|
||||||
try:
|
try:
|
||||||
response = self.handler.handle_request(input)
|
response = self.handler.handle_request(input)
|
||||||
self.handle_response(response)
|
if response is not None:
|
||||||
|
self.handle_response(response)
|
||||||
except MpdAckError, e:
|
except MpdAckError, e:
|
||||||
logger.warning(e)
|
logger.warning(e)
|
||||||
return self.send_response(u'ACK %s' % e)
|
return self.send_response(u'ACK %s' % e)
|
||||||
|
|||||||
@ -66,6 +66,12 @@ class CommandListsTest(unittest.TestCase):
|
|||||||
self.assert_(u'OK' in result)
|
self.assert_(u'OK' in result)
|
||||||
self.assertEquals(False, self.h.command_list)
|
self.assertEquals(False, self.h.command_list)
|
||||||
|
|
||||||
|
def test_command_list_with_error(self):
|
||||||
|
self.h.handle_request(u'command_list_begin')
|
||||||
|
self.h.handle_request(u'ack')
|
||||||
|
result = self.h.handle_request(u'command_list_end')
|
||||||
|
self.assert_(u'ACK' in result[-1])
|
||||||
|
|
||||||
def test_command_list_ok_begin(self):
|
def test_command_list_ok_begin(self):
|
||||||
result = self.h.handle_request(u'command_list_ok_begin')
|
result = self.h.handle_request(u'command_list_ok_begin')
|
||||||
self.assert_(result is None)
|
self.assert_(result is None)
|
||||||
@ -94,7 +100,9 @@ class StatusHandlerTest(unittest.TestCase):
|
|||||||
self.assert_(u'ACK Not implemented' in result)
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
def test_currentsong(self):
|
def test_currentsong(self):
|
||||||
self.b.playback.current_track = Track()
|
track = Track()
|
||||||
|
self.b.current_playlist.playlist = Playlist(tracks=[track])
|
||||||
|
self.b.playback.current_track = track
|
||||||
result = self.h.handle_request(u'currentsong')
|
result = self.h.handle_request(u'currentsong')
|
||||||
self.assert_(u'file: ' in result)
|
self.assert_(u'file: ' in result)
|
||||||
self.assert_(u'Time: 0' in result)
|
self.assert_(u'Time: 0' in result)
|
||||||
@ -460,7 +468,8 @@ class PlaybackControlHandlerTest(unittest.TestCase):
|
|||||||
|
|
||||||
class CurrentPlaylistHandlerTest(unittest.TestCase):
|
class CurrentPlaylistHandlerTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.h = handler.MpdHandler(backend=DummyBackend())
|
self.b = DummyBackend()
|
||||||
|
self.h = handler.MpdHandler(backend=self.b)
|
||||||
|
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
result = self.h.handle_request(u'add "file:///dev/urandom"')
|
result = self.h.handle_request(u'add "file:///dev/urandom"')
|
||||||
@ -491,8 +500,13 @@ class CurrentPlaylistHandlerTest(unittest.TestCase):
|
|||||||
self.assert_(u'ACK Not implemented' in result)
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
def test_deleteid(self):
|
def test_deleteid(self):
|
||||||
|
self.b.current_playlist.load(Playlist(tracks=[Track(id=0)]))
|
||||||
result = self.h.handle_request(u'deleteid "0"')
|
result = self.h.handle_request(u'deleteid "0"')
|
||||||
self.assert_(u'ACK Not implemented' in result)
|
self.assert_(u'OK' in result)
|
||||||
|
|
||||||
|
def test_deleteid_does_not_exist(self):
|
||||||
|
result = self.h.handle_request(u'deleteid "0"')
|
||||||
|
self.assert_(u'ACK Track with ID "0" not found' in result)
|
||||||
|
|
||||||
def test_move_songpos(self):
|
def test_move_songpos(self):
|
||||||
result = self.h.handle_request(u'move "5" "0"')
|
result = self.h.handle_request(u'move "5" "0"')
|
||||||
@ -746,7 +760,35 @@ class StickersHandlerTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.h = handler.MpdHandler(backend=DummyBackend())
|
self.h = handler.MpdHandler(backend=DummyBackend())
|
||||||
|
|
||||||
pass # TODO
|
def test_sticker_get(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker get "song" "file:///dev/urandom" "a_name"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_sticker_set(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker set "song" "file:///dev/urandom" "a_name" "a_value"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_sticker_delete_with_name(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker delete "song" "file:///dev/urandom" "a_name"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_sticker_delete_without_name(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker delete "song" "file:///dev/urandom"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_sticker_list(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker list "song" "file:///dev/urandom"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_sticker_find(self):
|
||||||
|
result = self.h.handle_request(
|
||||||
|
u'sticker find "song" "file:///dev/urandom" "a_name"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
|
||||||
class ConnectionHandlerTest(unittest.TestCase):
|
class ConnectionHandlerTest(unittest.TestCase):
|
||||||
@ -779,6 +821,14 @@ class AudioOutputHandlerTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.h = handler.MpdHandler(backend=DummyBackend())
|
self.h = handler.MpdHandler(backend=DummyBackend())
|
||||||
|
|
||||||
|
def test_enableoutput(self):
|
||||||
|
result = self.h.handle_request(u'enableoutput "0"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_disableoutput(self):
|
||||||
|
result = self.h.handle_request(u'disableoutput "0"')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
def test_outputs(self):
|
def test_outputs(self):
|
||||||
result = self.h.handle_request(u'outputs')
|
result = self.h.handle_request(u'outputs')
|
||||||
self.assert_(u'outputid: 0' in result)
|
self.assert_(u'outputid: 0' in result)
|
||||||
@ -791,10 +841,24 @@ class ReflectionHandlerTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.h = handler.MpdHandler(backend=DummyBackend())
|
self.h = handler.MpdHandler(backend=DummyBackend())
|
||||||
|
|
||||||
|
def test_commands(self):
|
||||||
|
result = self.h.handle_request(u'commands')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_decoders(self):
|
||||||
|
result = self.h.handle_request(u'decoders')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_notcommands(self):
|
||||||
|
result = self.h.handle_request(u'notcommands')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
|
def test_tagtypes(self):
|
||||||
|
result = self.h.handle_request(u'tagtypes')
|
||||||
|
self.assert_(u'ACK Not implemented' in result)
|
||||||
|
|
||||||
def test_urlhandlers(self):
|
def test_urlhandlers(self):
|
||||||
result = self.h.handle_request(u'urlhandlers')
|
result = self.h.handle_request(u'urlhandlers')
|
||||||
self.assert_(u'OK' in result)
|
self.assert_(u'OK' in result)
|
||||||
result = result[0]
|
result = result[0]
|
||||||
self.assert_('dummy:' in result)
|
self.assert_('dummy:' in result)
|
||||||
|
|
||||||
pass # TODO
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user