core: Add library.browse()
This commit is contained in:
parent
a3731c8187
commit
6027ed1fac
@ -5,6 +5,8 @@ import urlparse
|
||||
|
||||
import pykka
|
||||
|
||||
from mopidy.models import Ref
|
||||
|
||||
|
||||
class LibraryController(object):
|
||||
pykka_traversable = True
|
||||
@ -29,6 +31,63 @@ class LibraryController(object):
|
||||
(b, None) for b in self.backends.with_library.values()])
|
||||
return backends_to_uris
|
||||
|
||||
def browse(self, path):
|
||||
"""
|
||||
Browse directories and tracks at the given ``path``.
|
||||
|
||||
``path`` is a string that always starts with "/". It points to a
|
||||
directory in Mopidy's virtual file system.
|
||||
|
||||
Returns a list of :class:`mopidy.models.Ref` objects for the
|
||||
directories and tracks at the given ``path``.
|
||||
|
||||
The :class:`~mopidy.models.Ref` objects representing tracks keeps the
|
||||
track's original URI. A matching pair of objects can look like this::
|
||||
|
||||
Track(uri='dummy:/foo.mp3', name='foo', artists=..., album=...)
|
||||
Ref(uri='dummy:/foo.mp3', name='foo', type='track')
|
||||
|
||||
The :class:`~mopidy.models.Ref` objects representing directories has
|
||||
plain paths, not including any URI schema. For example, the dummy
|
||||
library's ``/bar`` directory is returned like this::
|
||||
|
||||
Ref(uri='/dummy/bar', name='bar', type='directory')
|
||||
|
||||
Note to backend implementors: The ``/dummy`` part of the URI is added
|
||||
by Mopidy core, not the individual backends.
|
||||
|
||||
:param path: path to browse
|
||||
:type path: string
|
||||
:rtype: list of :class:`mopidy.models.Ref`
|
||||
"""
|
||||
if not path.startswith('/'):
|
||||
return []
|
||||
if path == '/':
|
||||
library_names = [
|
||||
backend.library.name.get()
|
||||
for backend in self.backends.with_library.values()
|
||||
if backend.library.browse('/').get()]
|
||||
return [
|
||||
Ref(uri='/%s' % name, name=name, type='directory')
|
||||
for name in library_names]
|
||||
uri_scheme = path.split('/', 2)[1]
|
||||
backend = self.backends.with_library.get(uri_scheme, None)
|
||||
if backend:
|
||||
backend_path = path.replace('/%s' % uri_scheme, '')
|
||||
if not backend_path.startswith('/'):
|
||||
backend_path = '/%s' % backend_path
|
||||
refs = backend.library.browse(backend_path).get()
|
||||
result = []
|
||||
for ref in refs:
|
||||
if ref.type == 'directory':
|
||||
result.append(
|
||||
ref.copy(uri='/%s%s' % (uri_scheme, ref.uri)))
|
||||
else:
|
||||
result.append(ref)
|
||||
return result
|
||||
else:
|
||||
return []
|
||||
|
||||
def find_exact(self, query=None, uris=None, **kwargs):
|
||||
"""
|
||||
Search the library for tracks where ``field`` is ``values``.
|
||||
|
||||
@ -5,7 +5,7 @@ import unittest
|
||||
|
||||
from mopidy.backends import base
|
||||
from mopidy.core import Core
|
||||
from mopidy.models import SearchResult, Track
|
||||
from mopidy.models import Ref, SearchResult, Track
|
||||
|
||||
|
||||
class CoreLibraryTest(unittest.TestCase):
|
||||
@ -13,11 +13,13 @@ class CoreLibraryTest(unittest.TestCase):
|
||||
self.backend1 = mock.Mock()
|
||||
self.backend1.uri_schemes.get.return_value = ['dummy1']
|
||||
self.library1 = mock.Mock(spec=base.BaseLibraryProvider)
|
||||
self.library1.name.get.return_value = 'dummy1'
|
||||
self.backend1.library = self.library1
|
||||
|
||||
self.backend2 = mock.Mock()
|
||||
self.backend2.uri_schemes.get.return_value = ['dummy2']
|
||||
self.library2 = mock.Mock(spec=base.BaseLibraryProvider)
|
||||
self.library2.name.get.return_value = 'dummy2'
|
||||
self.backend2.library = self.library2
|
||||
|
||||
# A backend without the optional library provider
|
||||
@ -28,6 +30,72 @@ class CoreLibraryTest(unittest.TestCase):
|
||||
self.core = Core(audio=None, backends=[
|
||||
self.backend1, self.backend2, self.backend3])
|
||||
|
||||
def test_browse_root_returns_dir_ref_for_each_library_with_content(self):
|
||||
result1 = [
|
||||
Ref(uri='/foo/bar', name='bar', type='directory'),
|
||||
Ref(uri='dummy1:/foo/baz.mp3', name='Baz', type='track'),
|
||||
]
|
||||
self.library1.browse().get.return_value = result1
|
||||
self.library1.browse.reset_mock()
|
||||
self.library2.browse().get.return_value = []
|
||||
self.library2.browse.reset_mock()
|
||||
|
||||
result = self.core.library.browse('/')
|
||||
|
||||
self.assertEqual(result, [
|
||||
Ref(uri='/dummy1', name='dummy1', type='directory'),
|
||||
])
|
||||
self.assertTrue(self.library1.browse.called)
|
||||
self.assertTrue(self.library2.browse.called)
|
||||
self.assertFalse(self.backend3.library.browse.called)
|
||||
|
||||
def test_browse_empty_string_returns_nothing(self):
|
||||
result = self.core.library.browse('')
|
||||
|
||||
self.assertEqual(result, [])
|
||||
self.assertFalse(self.library1.browse.called)
|
||||
self.assertFalse(self.library2.browse.called)
|
||||
|
||||
def test_browse_dummy1_selects_dummy1_backend(self):
|
||||
self.library1.browse().get.return_value = []
|
||||
self.library1.browse.reset_mock()
|
||||
|
||||
self.core.library.browse('/dummy1/foo')
|
||||
|
||||
self.library1.browse.assert_called_once_with('/foo')
|
||||
self.assertFalse(self.library2.browse.called)
|
||||
|
||||
def test_browse_dummy2_selects_dummy2_backend(self):
|
||||
self.library2.browse().get.return_value = []
|
||||
self.library2.browse.reset_mock()
|
||||
|
||||
self.core.library.browse('/dummy2/bar')
|
||||
|
||||
self.assertFalse(self.library1.browse.called)
|
||||
self.library2.browse.assert_called_once_with('/bar')
|
||||
|
||||
def test_browse_dummy3_returns_nothing(self):
|
||||
result = self.core.library.browse('/dummy3')
|
||||
|
||||
self.assertEqual(result, [])
|
||||
self.assertFalse(self.library1.browse.called)
|
||||
self.assertFalse(self.library2.browse.called)
|
||||
|
||||
def test_browse_dir_returns_subdirs_and_tracks(self):
|
||||
result1 = [
|
||||
Ref(uri='/foo/bar', name='bar', type='directory'),
|
||||
Ref(uri='dummy1:/foo/baz.mp3', name='Baz', type='track'),
|
||||
]
|
||||
self.library1.browse().get.return_value = result1
|
||||
self.library1.browse.reset_mock()
|
||||
|
||||
result = self.core.library.browse('/dummy1/foo')
|
||||
|
||||
self.assertEqual(result, [
|
||||
Ref(uri='/dummy1/foo/bar', name='bar', type='directory'),
|
||||
Ref(uri='dummy1:/foo/baz.mp3', name='Baz', type='track'),
|
||||
])
|
||||
|
||||
def test_lookup_selects_dummy1_backend(self):
|
||||
self.core.library.lookup('dummy1:a')
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user