mpd: Include artists and albums in search results

This commit is contained in:
Stein Magnus Jodal 2012-12-21 23:08:18 +01:00
parent a8c0f6baa8
commit 455f0145e7
3 changed files with 71 additions and 4 deletions

View File

@ -58,6 +58,11 @@ v0.11.0 (in development)
- Add support for search by date.
- Include fake tracks representing albums and artists in the search results.
When these are added to the tracklist, they expand to either all tracks in
the album or all tracks by the artist. This makes it easy to play full albums
in proper order, which is a feature that have been frequently requested.
**Internal changes**
*Models:*

View File

@ -1,7 +1,9 @@
from __future__ import unicode_literals
import functools
import itertools
from mopidy.models import Track
from mopidy.frontends.mpd import translator
from mopidy.frontends.mpd.exceptions import MpdNotImplemented
from mopidy.frontends.mpd.protocol import handle_request, stored_playlists
@ -12,8 +14,28 @@ QUERY_RE = (
r'[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$')
def _get_tracks(search_results):
return list(itertools.chain(*[r.tracks for r in search_results]))
def _get_field(field, search_results):
return list(itertools.chain(*[getattr(r, field) for r in search_results]))
_get_albums = functools.partial(_get_field, 'albums')
_get_artists = functools.partial(_get_field, 'artists')
_get_tracks = functools.partial(_get_field, 'tracks')
def _album_as_track(album):
return Track(
uri=album.uri,
name='Album: ' + album.name,
album=album,
artists=album.artists)
def _artist_as_track(artist):
return Track(
uri=artist.uri,
name='Artist: ' + artist.name,
artists=[artist])
@handle_request(r'^count "(?P<tag>[^"]+)" "(?P<needle>[^"]*)"$')
@ -62,7 +84,10 @@ def find(context, mpd_query):
except ValueError:
return
results = context.core.library.find_exact(**query).get()
return translator.tracks_to_mpd_format(_get_tracks(results))
albums = [_album_as_track(a) for a in _get_albums(results)]
artists = [_artist_as_track(a) for a in _get_artists(results)]
tracks = _get_tracks(results)
return translator.tracks_to_mpd_format(artists + albums + tracks)
@handle_request(r'^findadd ' + QUERY_RE)
@ -304,7 +329,10 @@ def search(context, mpd_query):
except ValueError:
return
results = context.core.library.search(**query).get()
return translator.tracks_to_mpd_format(_get_tracks(results))
albums = [_album_as_track(a) for a in _get_albums(results)]
artists = [_artist_as_track(a) for a in _get_artists(results)]
tracks = _get_tracks(results)
return translator.tracks_to_mpd_format(artists + albums + tracks)
@handle_request(r'^searchadd ' + QUERY_RE)

View File

@ -115,6 +115,23 @@ class MusicDatabaseHandlerTest(protocol.BaseTestCase):
class MusicDatabaseFindTest(protocol.BaseTestCase):
def test_find(self):
self.backend.library.dummy_find_exact_result = SearchResult(
albums=[Album(uri='dummy:album:a', name='A')],
artists=[Artist(uri='dummy:artist:b', name='B')],
tracks=[Track(uri='dummy:track:c', name='C')])
self.sendRequest('find "any" "foo"')
self.assertInResponse('file: dummy:album:a')
self.assertInResponse('Title: Album: A')
self.assertInResponse('file: dummy:artist:b')
self.assertInResponse('Title: Artist: B')
self.assertInResponse('file: dummy:track:c')
self.assertInResponse('Title: C')
self.assertInResponse('OK')
def test_find_album(self):
self.sendRequest('find "album" "what"')
self.assertInResponse('OK')
@ -409,6 +426,23 @@ class MusicDatabaseListTest(protocol.BaseTestCase):
class MusicDatabaseSearchTest(protocol.BaseTestCase):
def test_search(self):
self.backend.library.dummy_search_result = SearchResult(
albums=[Album(uri='dummy:album:a', name='A')],
artists=[Artist(uri='dummy:artist:b', name='B')],
tracks=[Track(uri='dummy:track:c', name='C')])
self.sendRequest('search "any" "foo"')
self.assertInResponse('file: dummy:album:a')
self.assertInResponse('Title: Album: A')
self.assertInResponse('file: dummy:artist:b')
self.assertInResponse('Title: Artist: B')
self.assertInResponse('file: dummy:track:c')
self.assertInResponse('Title: C')
self.assertInResponse('OK')
def test_search_album(self):
self.sendRequest('search "album" "analbum"')
self.assertInResponse('OK')