From 7d23302737cff32eb482dc2801ea9a08f175b029 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 12:12:45 +0100 Subject: [PATCH 1/6] mpd: Remove Python 2.6-ism --- mopidy/frontends/mpd/translator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index df3338ba..d0198f13 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -204,7 +204,6 @@ def query_from_mpd_search_format(mpd_query): field = 'track' elif field in ('file', 'filename'): field = 'uri' - field = str(field) # Needed for kwargs keys on OS X and Windows what = m.groupdict()['what'] if not what: raise ValueError From d8227244261a4b20a621d5e9ab87cd49dc959610 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 20:06:42 +0100 Subject: [PATCH 2/6] mpd: Format search query regexps better --- mopidy/frontends/mpd/translator.py | 48 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index d0198f13..d4686597 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -179,6 +179,42 @@ def query_from_mpd_list_format(field, mpd_query): raise MpdArgError('not able to parse args', command='list') +# XXX The regexps below should be refactored to reuse common patterns here +# and in mopidy.frontends.mpd.protocol.music_db.QUERY_RE. + +MPD_SEARCH_QUERY_RE = re.compile(r""" + "? # Optional quote around the field type + (?: # A non-capturing group for the field type + [Aa]lbum + | [Aa]rtist + | [Dd]ate + | [Ff]ile + | [Ff]ilename + | [Tt]itle + | [Aa]ny + ) + "? # End of optional quote around the field type + \s # A single space + "[^"]+" # Matching a quoted search string +""", re.VERBOSE) + +MPD_SEARCH_QUERY_PART_RE = re.compile(r""" + "? # Optional quote around the field type + (?P( # A capturing group for the field type + [Aa]lbum + | [Aa]rtist + | [Dd]ate + | [Ff]ile + | [Ff]ilename + | [Tt]itle + | [Aa]ny + )) + "? # End of optional quote around the field type + \s # A single space + "(?P[^"]+)" # Capturing a quoted search string +""", re.VERBOSE) + + def query_from_mpd_search_format(mpd_query): """ Parses an MPD ``search`` or ``find`` query and converts it to the Mopidy @@ -187,18 +223,10 @@ def query_from_mpd_search_format(mpd_query): :param mpd_query: the MPD search query :type mpd_query: string """ - # XXX The regexps below should be refactored to reuse common patterns here - # and in mopidy.frontends.mpd.protocol.music_db. - query_pattern = ( - r'"?(?:[Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile|[Ff]ilename|' - r'[Tt]itle|[Aa]ny)"? "[^"]+"') - query_parts = re.findall(query_pattern, mpd_query) - query_part_pattern = ( - r'"?(?P([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile|[Ff]ilename|' - r'[Tt]itle|[Aa]ny))"? "(?P[^"]+)"') + query_parts = re.findall(MPD_SEARCH_QUERY_RE, mpd_query) query = {} for query_part in query_parts: - m = re.match(query_part_pattern, query_part) + m = re.match(MPD_SEARCH_QUERY_PART_RE, query_part) field = m.groupdict()['field'].lower() if field == 'title': field = 'track' From dabddd81fda70b5a6ab7e95cdbc03967b0517ed7 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 20:22:45 +0100 Subject: [PATCH 3/6] mpd: Accept 'albumartist' type to 'find' and 'search' commands --- mopidy/frontends/mpd/protocol/music_db.py | 4 ++-- tests/frontends/mpd/protocol/music_db_test.py | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index f81d57ee..49384cb0 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -10,8 +10,8 @@ from mopidy.frontends.mpd.protocol import handle_request, stored_playlists QUERY_RE = ( - r'(?P("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile|[Ff]ilename|' - r'[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$') + r'(?P("?([Aa]lbum|[Aa]rtist|[Aa]lbumartist|[Dd]ate|[Ff]ile|' + r'[Ff]ilename|[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$') def _get_field(field, search_results): diff --git a/tests/frontends/mpd/protocol/music_db_test.py b/tests/frontends/mpd/protocol/music_db_test.py index eaa5da06..47d5bb87 100644 --- a/tests/frontends/mpd/protocol/music_db_test.py +++ b/tests/frontends/mpd/protocol/music_db_test.py @@ -211,6 +211,14 @@ class MusicDatabaseFindTest(protocol.BaseTestCase): self.sendRequest('find artist "what"') self.assertInResponse('OK') + def test_find_albumartist(self): + self.sendRequest('find "albumartist" "what"') + self.assertInResponse('OK') + + def test_find_albumartist_without_quotes(self): + self.sendRequest('find albumartist "what"') + self.assertInResponse('OK') + def test_find_filename(self): self.sendRequest('find "filename" "afilename"') self.assertInResponse('OK') @@ -545,6 +553,18 @@ class MusicDatabaseSearchTest(protocol.BaseTestCase): self.sendRequest('search "artist" ""') self.assertInResponse('OK') + def test_search_albumartist(self): + self.sendRequest('search "albumartist" "analbumartist"') + self.assertInResponse('OK') + + def test_search_albumartist_without_quotes(self): + self.sendRequest('search albumartist "analbumartist"') + self.assertInResponse('OK') + + def test_search_albumartist_without_filter_value(self): + self.sendRequest('search "albumartist" ""') + self.assertInResponse('OK') + def test_search_filename(self): self.sendRequest('search "filename" "afilename"') self.assertInResponse('OK') From 6af0ace8aca9263054a95d133ea17b64c5959e28 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 20:23:22 +0100 Subject: [PATCH 4/6] mpd: Map 'albumartist' field from MPD to Mopidy query --- mopidy/frontends/mpd/translator.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index d4686597..266d0d88 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -183,10 +183,12 @@ def query_from_mpd_list_format(field, mpd_query): # and in mopidy.frontends.mpd.protocol.music_db.QUERY_RE. MPD_SEARCH_QUERY_RE = re.compile(r""" + \b # Only begin matching at word bundaries "? # Optional quote around the field type (?: # A non-capturing group for the field type [Aa]lbum | [Aa]rtist + | [Aa]lbumartist | [Dd]ate | [Ff]ile | [Ff]ilename @@ -199,10 +201,12 @@ MPD_SEARCH_QUERY_RE = re.compile(r""" """, re.VERBOSE) MPD_SEARCH_QUERY_PART_RE = re.compile(r""" + \b # Only begin matching at word bundaries "? # Optional quote around the field type (?P( # A capturing group for the field type [Aa]lbum | [Aa]rtist + | [Aa]lbumartist | [Dd]ate | [Ff]ile | [Ff]ilename From 24a2b08fc53e0fab7c8c7ec3155055b5e6a26301 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 20:24:07 +0100 Subject: [PATCH 5/6] mpd: Don't return fake artists when searching by albumartist --- mopidy/frontends/mpd/protocol/music_db.py | 2 +- tests/frontends/mpd/protocol/music_db_test.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index 49384cb0..7c99c538 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -91,7 +91,7 @@ def find(context, mpd_query): return results = context.core.library.find_exact(**query).get() result_tracks = [] - if 'artist' not in query: + if 'artist' not in query and 'albumartist' not in query: result_tracks += [_artist_as_track(a) for a in _get_artists(results)] if 'album' not in query: result_tracks += [_album_as_track(a) for a in _get_albums(results)] diff --git a/tests/frontends/mpd/protocol/music_db_test.py b/tests/frontends/mpd/protocol/music_db_test.py index 47d5bb87..65f76d37 100644 --- a/tests/frontends/mpd/protocol/music_db_test.py +++ b/tests/frontends/mpd/protocol/music_db_test.py @@ -175,6 +175,26 @@ class MusicDatabaseFindTest(protocol.BaseTestCase): self.assertInResponse('OK') + def test_find_albumartist_does_not_include_fake_artist_tracks(self): + self.backend.library.dummy_find_exact_result = SearchResult( + albums=[Album(uri='dummy:album:a', name='A', date='2001')], + artists=[Artist(uri='dummy:artist:b', name='B')], + tracks=[Track(uri='dummy:track:c', name='C')]) + + self.sendRequest('find "albumartist" "foo"') + + self.assertNotInResponse('file: dummy:artist:b') + self.assertNotInResponse('Title: Artist: B') + + self.assertInResponse('file: dummy:album:a') + self.assertInResponse('Title: Album: A') + self.assertInResponse('Date: 2001') + + self.assertInResponse('file: dummy:track:c') + self.assertInResponse('Title: C') + + self.assertInResponse('OK') + def test_find_artist_and_album_does_not_include_fake_tracks(self): self.backend.library.dummy_find_exact_result = SearchResult( albums=[Album(uri='dummy:album:a', name='A', date='2001')], From 38bbaeee18bf556b495b6d6b1e85e8fbf94f5cfb Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 27 Oct 2013 20:59:46 +0100 Subject: [PATCH 6/6] mpd: Review fixes --- mopidy/frontends/mpd/translator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index 266d0d88..d2b0f2d4 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -227,10 +227,10 @@ def query_from_mpd_search_format(mpd_query): :param mpd_query: the MPD search query :type mpd_query: string """ - query_parts = re.findall(MPD_SEARCH_QUERY_RE, mpd_query) + query_parts = MPD_SEARCH_QUERY_RE.findall(mpd_query) query = {} for query_part in query_parts: - m = re.match(MPD_SEARCH_QUERY_PART_RE, query_part) + m = MPD_SEARCH_QUERY_PART_RE.match(query_part) field = m.groupdict()['field'].lower() if field == 'title': field = 'track'