From 455f0145e71e77121502556b05c2c98bc33b179c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 21 Dec 2012 23:08:18 +0100 Subject: [PATCH] mpd: Include artists and albums in search results --- docs/changes.rst | 5 +++ mopidy/frontends/mpd/protocol/music_db.py | 36 ++++++++++++++++--- tests/frontends/mpd/protocol/music_db_test.py | 34 ++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 8f887ed5..3bc68948 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -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:* diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index f9149a50..ca5ef730 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -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[^"]+)" "(?P[^"]*)"$') @@ -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) diff --git a/tests/frontends/mpd/protocol/music_db_test.py b/tests/frontends/mpd/protocol/music_db_test.py index 86fd8ad7..fedc34a1 100644 --- a/tests/frontends/mpd/protocol/music_db_test.py +++ b/tests/frontends/mpd/protocol/music_db_test.py @@ -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')