diff --git a/mopidy/mpd/protocol/music_db.py b/mopidy/mpd/protocol/music_db.py index b31d295b..302d37eb 100644 --- a/mopidy/mpd/protocol/music_db.py +++ b/mopidy/mpd/protocol/music_db.py @@ -6,7 +6,8 @@ import re from mopidy.models import Ref, Track from mopidy.mpd import translator -from mopidy.mpd.exceptions import MpdArgError, MpdNotImplemented +from mopidy.mpd.exceptions import ( + MpdArgError, MpdNoExistError, MpdNotImplemented) from mopidy.mpd.protocol import handle_request, stored_playlists @@ -417,7 +418,25 @@ def listall(context, uri=None): Lists all songs and directories in ``URI``. """ - raise MpdNotImplemented # TODO + if uri is None: + uri = '/' + if not uri.startswith('/'): + uri = '/%s' % uri + + result = [] + browse_futures = [context.core.library.browse(uri)] + while browse_futures: + for ref in browse_futures.pop().get(): + if ref.type == Ref.DIRECTORY: + result.append(('directory', ref.uri)) + browse_futures.append(context.core.library.browse(ref.uri)) + elif ref.type == Ref.TRACK: + result.append(('file', ref.uri)) + + if not result: + raise MpdNoExistError('Not found', command='listall') + + return [('directory', uri)] + result @handle_request(r'listallinfo$') diff --git a/tests/mpd/protocol/test_music_db.py b/tests/mpd/protocol/test_music_db.py index 163ccf88..78a94a78 100644 --- a/tests/mpd/protocol/test_music_db.py +++ b/tests/mpd/protocol/test_music_db.py @@ -123,12 +123,41 @@ class MusicDatabaseHandlerTest(protocol.BaseTestCase): self.assertInResponse('OK') def test_listall_without_uri(self): + tracks = [Track(uri='dummy:/a', name='a'), + Track(uri='dummy:/b', name='b')] + self.backend.library.dummy_library = tracks + self.backend.library.dummy_browse_result = { + '/': [Ref.track(uri='dummy:/a', name='a'), + Ref.directory(uri='/foo')], + '/foo': [Ref.track(uri='dummy:/b', name='b')]} + self.sendRequest('listall') - self.assertEqualResponse('ACK [0@0] {} Not implemented') + + self.assertInResponse('file: dummy:/a') + self.assertInResponse('directory: /dummy/foo') + self.assertInResponse('file: dummy:/b') + self.assertInResponse('OK') def test_listall_with_uri(self): - self.sendRequest('listall "file:///dev/urandom"') - self.assertEqualResponse('ACK [0@0] {} Not implemented') + tracks = [Track(uri='dummy:/a', name='a'), + Track(uri='dummy:/b', name='b')] + self.backend.library.dummy_library = tracks + self.backend.library.dummy_browse_result = { + '/': [Ref.track(uri='dummy:/a', name='a'), + Ref.directory(uri='/foo')], + '/foo': [Ref.track(uri='dummy:/b', name='b')]} + + self.sendRequest('listall "/dummy/foo"') + + self.assertNotInResponse('file: dummy:/a') + self.assertInResponse('directory: /dummy/foo') + self.assertInResponse('file: dummy:/b') + self.assertInResponse('OK') + + def test_listall_with_unknown_uri(self): + self.sendRequest('listall "/unknown"') + + self.assertEqualResponse('ACK [50@0] {listall} Not found') def test_listallinfo_without_uri(self): self.sendRequest('listallinfo')