Merge branch 'master' of git://github.com/jodal/mopidy into gstreamer
This commit is contained in:
commit
da05ed8f87
@ -15,10 +15,21 @@ Another great release.
|
||||
- Exit early if not Python >= 2.6, < 3.
|
||||
- Include Sphinx scripts for building docs, pylintrc, tests and test data in
|
||||
the packages created by ``setup.py`` for i.e. PyPI.
|
||||
- MPD frontend:
|
||||
|
||||
- Search improvements, including support for multi-word search.
|
||||
|
||||
- Backend API:
|
||||
|
||||
- The ``id`` field of :class:`mopidy.models.Track` has been removed, as it is
|
||||
no longer needed after the CPID refactoring.
|
||||
- :meth:`mopidy.backends.BaseLibraryController.find_exact()` now accepts
|
||||
keyword arguments of the form ``find_exact(artist=['foo'],
|
||||
album=['bar'])``.
|
||||
- :meth:`mopidy.backends.BaseLibraryController.search()` now accepts
|
||||
keyword arguments of the form ``search(artist=['foo', 'fighters'],
|
||||
album=['bar', 'grooves'])``.
|
||||
|
||||
|
||||
|
||||
0.1.0a3 (2010-08-03)
|
||||
|
||||
@ -283,12 +283,21 @@ class BaseLibraryController(object):
|
||||
"""Cleanup after component."""
|
||||
pass
|
||||
|
||||
def find_exact(self, query):
|
||||
def find_exact(self, **query):
|
||||
"""
|
||||
Find tracks in the library where ``field`` matches ``what`` exactly.
|
||||
Search the library for tracks where ``field`` is ``values``.
|
||||
|
||||
:param query: Example: [(u'artist', u'anArtist'), (u'album', u'anAlbum')]
|
||||
:type query: list of (field, what) tuples.
|
||||
Examples::
|
||||
|
||||
# Returns results matching 'a'
|
||||
find_exact(any=['a'])
|
||||
# Returns results matching artist 'xyz'
|
||||
find_exact(artist=['xyz'])
|
||||
# Returns results matching 'a' and 'b' and artist 'xyz'
|
||||
find_exact(any=['a', 'b'], artist=['xyz'])
|
||||
|
||||
:param query: one or more queries to search for
|
||||
:type query: dict
|
||||
:rtype: :class:`mopidy.models.Playlist`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
@ -318,9 +327,12 @@ class BaseLibraryController(object):
|
||||
|
||||
Examples::
|
||||
|
||||
search(any=['a']) # Returns results matching 'a'
|
||||
search(artist=['xyz']) # Returns results matching artist 'xyz'
|
||||
search(any=['a', 'b'], artist=['xyz']) # Returns results matching 'a' and 'b' and artist 'xyz'
|
||||
# Returns results matching 'a'
|
||||
search(any=['a'])
|
||||
# Returns results matching artist 'xyz'
|
||||
search(artist=['xyz'])
|
||||
# Returns results matching 'a' and 'b' and artist 'xyz'
|
||||
search(any=['a', 'b'], artist=['xyz'])
|
||||
|
||||
:param query: one or more queries to search for
|
||||
:type query: dict
|
||||
|
||||
@ -53,6 +53,9 @@ class DespotifyCurrentPlaylistController(BaseCurrentPlaylistController):
|
||||
|
||||
|
||||
class DespotifyLibraryController(BaseLibraryController):
|
||||
def find_exact(self, **query):
|
||||
return self.search(**query)
|
||||
|
||||
def lookup(self, uri):
|
||||
track = self.backend.spotify.lookup(uri.encode(ENCODING))
|
||||
return DespotifyTranslator.to_mopidy_track(track)
|
||||
@ -76,8 +79,6 @@ class DespotifyLibraryController(BaseLibraryController):
|
||||
return Playlist()
|
||||
return DespotifyTranslator.to_mopidy_playlist(result.playlist)
|
||||
|
||||
find_exact = search
|
||||
|
||||
|
||||
class DespotifyPlaybackController(BasePlaybackController):
|
||||
def _pause(self):
|
||||
|
||||
@ -217,38 +217,55 @@ class GStreamerLibraryController(BaseLibraryController):
|
||||
except KeyError:
|
||||
raise LookupError('%s not found.' % uri)
|
||||
|
||||
def find_exact(self, query):
|
||||
for (field, what) in query:
|
||||
if not what:
|
||||
raise LookupError('Missing query')
|
||||
|
||||
def find_exact(self, **query):
|
||||
self._validate_query(query)
|
||||
result_tracks = self._uri_mapping.values()
|
||||
for (field, what) in query:
|
||||
if field == 'track':
|
||||
filter_func = lambda t: t.name == what
|
||||
elif field == 'album':
|
||||
filter_func = lambda t: getattr(t, 'album', Album()).name == what
|
||||
elif field == 'artist':
|
||||
filter_func = lambda t: filter(lambda a: a.name == what, t.artists)
|
||||
else:
|
||||
raise LookupError('Invalid lookup field: %s' % field)
|
||||
|
||||
result_tracks = filter(filter_func, result_tracks)
|
||||
for (field, values) in query.iteritems():
|
||||
if not hasattr(values, '__iter__'):
|
||||
values = [values]
|
||||
# FIXME this is bound to be slow for large libraries
|
||||
for value in values:
|
||||
q = value.strip()
|
||||
|
||||
track_filter = lambda t: q == t.name
|
||||
album_filter = lambda t: q == getattr(t, 'album', Album()).name
|
||||
artist_filter = lambda t: filter(
|
||||
lambda a: q == a.name, t.artists)
|
||||
uri_filter = lambda t: q == t.uri
|
||||
any_filter = lambda t: (track_filter(t) or album_filter(t) or
|
||||
artist_filter(t) or uri_filter(t))
|
||||
|
||||
if field == 'track':
|
||||
result_tracks = filter(track_filter, result_tracks)
|
||||
elif field == 'album':
|
||||
result_tracks = filter(album_filter, result_tracks)
|
||||
elif field == 'artist':
|
||||
result_tracks = filter(artist_filter, result_tracks)
|
||||
elif field == 'uri':
|
||||
result_tracks = filter(uri_filter, result_tracks)
|
||||
elif field == 'any':
|
||||
result_tracks = filter(any_filter, result_tracks)
|
||||
else:
|
||||
raise LookupError('Invalid lookup field: %s' % field)
|
||||
return Playlist(tracks=result_tracks)
|
||||
|
||||
def search(self, **query):
|
||||
self._validate_query(query)
|
||||
result_tracks = self._uri_mapping.values()
|
||||
for (field, values) in query:
|
||||
|
||||
for (field, values) in query.iteritems():
|
||||
if not hasattr(values, '__iter__'):
|
||||
values = [values]
|
||||
# FIXME this is bound to be slow for large libraries
|
||||
for value in values:
|
||||
q = value.strip().lower()
|
||||
|
||||
# FIXME this is bound to be slow for large libraries
|
||||
track_filter = lambda t: q in t.name.lower()
|
||||
album_filter = lambda t: q in getattr(t, 'album', Album()).name.lower()
|
||||
artist_filter = lambda t: filter(lambda a: q in a.name.lower(),
|
||||
t.artists)
|
||||
album_filter = lambda t: q in getattr(
|
||||
t, 'album', Album()).name.lower()
|
||||
artist_filter = lambda t: filter(
|
||||
lambda a: q in a.name.lower(), t.artists)
|
||||
uri_filter = lambda t: q in t.uri.lower()
|
||||
any_filter = lambda t: track_filter(t) or album_filter(t) or \
|
||||
artist_filter(t) or uri_filter(t)
|
||||
@ -265,5 +282,12 @@ class GStreamerLibraryController(BaseLibraryController):
|
||||
result_tracks = filter(any_filter, result_tracks)
|
||||
else:
|
||||
raise LookupError('Invalid lookup field: %s' % field)
|
||||
|
||||
return Playlist(tracks=result_tracks)
|
||||
|
||||
def _validate_query(self, query):
|
||||
for (field, values) in query.iteritems():
|
||||
if not values:
|
||||
raise LookupError('Missing query')
|
||||
for value in values:
|
||||
if not value:
|
||||
raise LookupError('Missing query')
|
||||
|
||||
@ -680,7 +680,9 @@ class MpdFrontend(object):
|
||||
Lists all tags of the specified type. ``TYPE`` should be ``album``,
|
||||
``artist``, ``date``, or ``genre``.
|
||||
|
||||
``ARTIST`` is an optional parameter when type is ``album``, ``date``, or ``genre``
|
||||
``ARTIST`` is an optional parameter when type is ``album``,
|
||||
``date``, or ``genre``.
|
||||
|
||||
This filters the result list by an artist.
|
||||
|
||||
*GMPC:*
|
||||
|
||||
@ -1079,120 +1079,120 @@ class BaseLibraryControllerTest(object):
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
def test_find_exact_no_hits(self):
|
||||
result = self.library.find_exact([('track', 'unknown track')])
|
||||
result = self.library.find_exact(track=['unknown track'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.find_exact([('artist', 'unknown artist')])
|
||||
result = self.library.find_exact(artist=['unknown artist'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.find_exact([('album', 'unknown artist')])
|
||||
result = self.library.find_exact(album=['unknown artist'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
def test_find_exact_artist(self):
|
||||
result = self.library.find_exact([('artist', 'artist1')])
|
||||
result = self.library.find_exact(artist=['artist1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.find_exact([('artist', 'artist2')])
|
||||
result = self.library.find_exact(artist=['artist2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_find_exact_track(self):
|
||||
result = self.library.find_exact([('track', 'track1')])
|
||||
result = self.library.find_exact(track=['track1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.find_exact([('track', 'track2')])
|
||||
result = self.library.find_exact(track=['track2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_find_exact_album(self):
|
||||
result = self.library.find_exact([('album', 'album1')])
|
||||
result = self.library.find_exact(album=['album1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.find_exact([('album', 'album2')])
|
||||
result = self.library.find_exact(album=['album2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_find_exact_wrong_type(self):
|
||||
test = lambda: self.library.find_exact([('wrong', 'test')])
|
||||
test = lambda: self.library.find_exact(wrong=['test'])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
def test_find_exact_with_empty_query(self):
|
||||
test = lambda: self.library.find_exact([('artist', '')])
|
||||
test = lambda: self.library.find_exact(artist=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.find_exact([('track', '')])
|
||||
test = lambda: self.library.find_exact(track=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.find_exact([('album', '')])
|
||||
test = lambda: self.library.find_exact(album=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
def test_search_no_hits(self):
|
||||
result = self.library.search([('track', 'unknown track')])
|
||||
result = self.library.search(track=['unknown track'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.search([('artist', 'unknown artist')])
|
||||
result = self.library.search(artist=['unknown artist'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.search([('album', 'unknown artist')])
|
||||
result = self.library.search(album=['unknown artist'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.search([('uri', 'unknown')])
|
||||
result = self.library.search(uri=['unknown'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
result = self.library.search([('any', 'unknown')])
|
||||
result = self.library.search(any=['unknown'])
|
||||
self.assertEqual(result, Playlist())
|
||||
|
||||
def test_search_artist(self):
|
||||
result = self.library.search([('artist', 'Tist1')])
|
||||
result = self.library.search(artist=['Tist1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.search([('artist', 'Tist2')])
|
||||
result = self.library.search(artist=['Tist2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_search_track(self):
|
||||
result = self.library.search([('track', 'Rack1')])
|
||||
result = self.library.search(track=['Rack1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.search([('track', 'Rack2')])
|
||||
result = self.library.search(track=['Rack2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_search_album(self):
|
||||
result = self.library.search([('album', 'Bum1')])
|
||||
result = self.library.search(album=['Bum1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.search([('album', 'Bum2')])
|
||||
result = self.library.search(album=['Bum2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_search_uri(self):
|
||||
result = self.library.search([('uri', 'RI1')])
|
||||
result = self.library.search(uri=['RI1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
result = self.library.search([('uri', 'RI2')])
|
||||
result = self.library.search(uri=['RI2'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[1:2]))
|
||||
|
||||
def test_search_any(self):
|
||||
result = self.library.search([('any', 'Tist1')])
|
||||
result = self.library.search(any=['Tist1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
result = self.library.search([('any', 'Rack1')])
|
||||
result = self.library.search(any=['Rack1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
result = self.library.search([('any', 'Bum1')])
|
||||
result = self.library.search(any=['Bum1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
result = self.library.search([('any', 'RI1')])
|
||||
result = self.library.search(any=['RI1'])
|
||||
self.assertEqual(result, Playlist(tracks=self.tracks[:1]))
|
||||
|
||||
def test_search_wrong_type(self):
|
||||
test = lambda: self.library.search([('wrong', 'test')])
|
||||
test = lambda: self.library.search(wrong=['test'])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
def test_search_with_empty_query(self):
|
||||
test = lambda: self.library.search([('artist', '')])
|
||||
test = lambda: self.library.search(artist=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.search([('track', '')])
|
||||
test = lambda: self.library.search(track=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.search([('album', '')])
|
||||
test = lambda: self.library.search(album=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.search([('uri', '')])
|
||||
test = lambda: self.library.search(uri=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
test = lambda: self.library.search([('any', '')])
|
||||
test = lambda: self.library.search(any=[''])
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
@ -45,7 +45,8 @@ class MusicDatabaseHandlerTest(unittest.TestCase):
|
||||
self.assertEqual(result[0], u'ACK [2@0] {find} incorrect arguments')
|
||||
|
||||
def test_find_album_and_artist(self):
|
||||
result = self.h.handle_request(u'find album "album_what" artist "artist_what"')
|
||||
result = self.h.handle_request(
|
||||
u'find album "album_what" artist "artist_what"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
def test_findadd(self):
|
||||
@ -75,7 +76,7 @@ class MusicDatabaseHandlerTest(unittest.TestCase):
|
||||
def test_list_album_with_artist(self):
|
||||
result = self.h.handle_request(u'list "album" "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
|
||||
def test_list_album_artist_with_artist_without_quotes(self):
|
||||
result = self.h.handle_request(u'list album artist "anartist"')
|
||||
self.assert_(u'OK' in result)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user