Make core.library support multiple backends
This commit is contained in:
parent
c47cec9e65
commit
a35deec050
@ -1,10 +1,25 @@
|
||||
import pykka
|
||||
|
||||
from mopidy.models import Playlist
|
||||
|
||||
|
||||
class LibraryController(object):
|
||||
pykka_traversable = True
|
||||
|
||||
def __init__(self, backends, core):
|
||||
self.backends = backends
|
||||
uri_schemes_by_backend = {backend: backend.uri_schemes.get()
|
||||
for backend in backends}
|
||||
self.backends_by_uri_scheme = {uri_scheme: backend
|
||||
for backend, uri_schemes in uri_schemes_by_backend.items()
|
||||
for uri_scheme in uri_schemes}
|
||||
|
||||
self.core = core
|
||||
|
||||
def _get_backend(self, uri):
|
||||
uri_scheme = uri.split(':', 1)[0]
|
||||
return self.backends_by_uri_scheme.get(uri_scheme)
|
||||
|
||||
def find_exact(self, **query):
|
||||
"""
|
||||
Search the library for tracks where ``field`` is ``values``.
|
||||
@ -22,7 +37,12 @@ class LibraryController(object):
|
||||
:type query: dict
|
||||
:rtype: :class:`mopidy.models.Playlist`
|
||||
"""
|
||||
return self.backends[0].library.find_exact(**query).get()
|
||||
futures = []
|
||||
for backend in self.backends:
|
||||
futures.append(backend.library.find_exact(**query))
|
||||
results = pykka.get_all(futures)
|
||||
return Playlist(tracks=[
|
||||
track for playlist in results for track in playlist.tracks])
|
||||
|
||||
def lookup(self, uri):
|
||||
"""
|
||||
@ -32,7 +52,9 @@ class LibraryController(object):
|
||||
:type uri: string
|
||||
:rtype: :class:`mopidy.models.Track` or :class:`None`
|
||||
"""
|
||||
return self.backends[0].library.lookup(uri).get()
|
||||
backend = self._get_backend(uri)
|
||||
if backend:
|
||||
return backend.library.lookup(uri).get()
|
||||
|
||||
def refresh(self, uri=None):
|
||||
"""
|
||||
@ -41,7 +63,15 @@ class LibraryController(object):
|
||||
:param uri: directory or track URI
|
||||
:type uri: string
|
||||
"""
|
||||
return self.backends[0].library.refresh(uri).get()
|
||||
if uri is not None:
|
||||
backend = self._get_backend(uri)
|
||||
if backend:
|
||||
return backend.library.refresh(uri).get()
|
||||
else:
|
||||
futures = []
|
||||
for backend in self.backends:
|
||||
futures.append(backend.library.refresh(uri))
|
||||
return pykka.get_all(futures)
|
||||
|
||||
def search(self, **query):
|
||||
"""
|
||||
@ -60,4 +90,9 @@ class LibraryController(object):
|
||||
:type query: dict
|
||||
:rtype: :class:`mopidy.models.Playlist`
|
||||
"""
|
||||
return self.backends[0].library.search(**query).get()
|
||||
futures = []
|
||||
for backend in self.backends:
|
||||
futures.append(backend.library.search(**query))
|
||||
results = pykka.get_all(futures)
|
||||
return Playlist(tracks=[
|
||||
track for playlist in results for track in playlist.tracks])
|
||||
|
||||
82
tests/core/library_test.py
Normal file
82
tests/core/library_test.py
Normal file
@ -0,0 +1,82 @@
|
||||
import mock
|
||||
|
||||
from mopidy.backends import base
|
||||
from mopidy.core import Core
|
||||
from mopidy.models import Playlist, Track
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
||||
class CoreLibraryTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.backend1 = mock.Mock()
|
||||
self.backend1.uri_schemes.get.return_value = ['dummy1']
|
||||
self.library1 = mock.Mock(spec=base.BaseLibraryProvider)
|
||||
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.backend2.library = self.library2
|
||||
|
||||
self.core = Core(audio=None, backends=[self.backend1, self.backend2])
|
||||
|
||||
def test_lookup_selects_dummy1_backend(self):
|
||||
self.core.library.lookup('dummy1:a')
|
||||
|
||||
self.library1.lookup.assert_called_once_with('dummy1:a')
|
||||
self.assertFalse(self.library2.lookup.called)
|
||||
|
||||
def test_lookup_selects_dummy2_backend(self):
|
||||
self.core.library.lookup('dummy2:a')
|
||||
|
||||
self.assertFalse(self.library1.lookup.called)
|
||||
self.library2.lookup.assert_called_once_with('dummy2:a')
|
||||
|
||||
def test_refresh_with_uri_selects_dummy1_backend(self):
|
||||
self.core.library.refresh('dummy1:a')
|
||||
|
||||
self.library1.refresh.assert_called_once_with('dummy1:a')
|
||||
self.assertFalse(self.library2.refresh.called)
|
||||
|
||||
def test_refresh_with_uri_selects_dummy2_backend(self):
|
||||
self.core.library.refresh('dummy2:a')
|
||||
|
||||
self.assertFalse(self.library1.refresh.called)
|
||||
self.library2.refresh.assert_called_once_with('dummy2:a')
|
||||
|
||||
def test_refresh_without_uri_calls_all_backends(self):
|
||||
self.core.library.refresh()
|
||||
|
||||
self.library1.refresh.assert_called_once_with(None)
|
||||
self.library2.refresh.assert_called_once_with(None)
|
||||
|
||||
def test_find_exact_combines_results_from_all_backends(self):
|
||||
track1 = Track(uri='dummy1:a')
|
||||
track2 = Track(uri='dummy2:a')
|
||||
self.library1.find_exact().get.return_value = Playlist(tracks=[track1])
|
||||
self.library1.find_exact.reset_mock()
|
||||
self.library2.find_exact().get.return_value = Playlist(tracks=[track2])
|
||||
self.library2.find_exact.reset_mock()
|
||||
|
||||
result = self.core.library.find_exact(any=['a'])
|
||||
|
||||
self.assertIn(track1, result.tracks)
|
||||
self.assertIn(track2, result.tracks)
|
||||
self.library1.find_exact.assert_called_once_with(any=['a'])
|
||||
self.library2.find_exact.assert_called_once_with(any=['a'])
|
||||
|
||||
def test_search_combines_results_from_all_backends(self):
|
||||
track1 = Track(uri='dummy1:a')
|
||||
track2 = Track(uri='dummy2:a')
|
||||
self.library1.search().get.return_value = Playlist(tracks=[track1])
|
||||
self.library1.search.reset_mock()
|
||||
self.library2.search().get.return_value = Playlist(tracks=[track2])
|
||||
self.library2.search.reset_mock()
|
||||
|
||||
result = self.core.library.search(any=['a'])
|
||||
|
||||
self.assertIn(track1, result.tracks)
|
||||
self.assertIn(track2, result.tracks)
|
||||
self.library1.search.assert_called_once_with(any=['a'])
|
||||
self.library2.search.assert_called_once_with(any=['a'])
|
||||
Loading…
Reference in New Issue
Block a user