From ccbae310c67c3e79a6399e565246657d525ac90d Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 1 Sep 2013 23:10:36 +0200 Subject: [PATCH 1/4] local: Add albumartist support to search/find_exact --- mopidy/backends/local/library.py | 10 +++++ tests/backends/local/library_test.py | 59 +++++++++++++++++++++++----- tests/data/library_tag_cache | 6 ++- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/mopidy/backends/local/library.py b/mopidy/backends/local/library.py index 9dd112e9..319049f0 100644 --- a/mopidy/backends/local/library.py +++ b/mopidy/backends/local/library.py @@ -62,6 +62,9 @@ class LocalLibraryProvider(base.BaseLibraryProvider): album_filter = lambda t: q == getattr(t, 'album', Album()).name artist_filter = lambda t: filter( lambda a: q == a.name, t.artists) + albumartist_filter = lambda t: any([ + q == a.name + for a in getattr(t.album, 'artists', [])]) date_filter = lambda t: q == t.date any_filter = lambda t: ( track_filter(t) or album_filter(t) or @@ -75,6 +78,8 @@ class LocalLibraryProvider(base.BaseLibraryProvider): result_tracks = filter(album_filter, result_tracks) elif field == 'artist': result_tracks = filter(artist_filter, result_tracks) + elif field == 'albumartist': + result_tracks = filter(albumartist_filter, result_tracks) elif field == 'date': result_tracks = filter(date_filter, result_tracks) elif field == 'any': @@ -105,6 +110,9 @@ class LocalLibraryProvider(base.BaseLibraryProvider): t, 'album', Album()).name.lower() artist_filter = lambda t: filter( lambda a: q in a.name.lower(), t.artists) + albumartist_filter = lambda t: any([ + q in a.name.lower() + for a in getattr(t.album, 'artists', [])]) date_filter = lambda t: t.date and t.date.startswith(q) any_filter = lambda t: track_filter(t) or album_filter(t) or \ artist_filter(t) or uri_filter(t) @@ -117,6 +125,8 @@ class LocalLibraryProvider(base.BaseLibraryProvider): result_tracks = filter(album_filter, result_tracks) elif field == 'artist': result_tracks = filter(artist_filter, result_tracks) + elif field == 'albumartist': + result_tracks = filter(albumartist_filter, result_tracks) elif field == 'date': result_tracks = filter(date_filter, result_tracks) elif field == 'any': diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index 8f988503..149a9cb3 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -12,19 +12,33 @@ from tests import path_to_data_dir class LocalLibraryControllerTest(unittest.TestCase): - artists = [Artist(name='artist1'), Artist(name='artist2'), Artist()] + artists = [ + Artist(name='artist1'), + Artist(name='artist2'), + Artist(name='artist3'), + Artist(name='artist4'), + ] albums = [ - Album(name='album1', artists=artists[:1]), - Album(name='album2', artists=artists[1:2]), - Album()] + Album(name='album1', artists=[artists[0]]), + Album(name='album2', artists=[artists[1]]), + Album(name='album3', artists=[artists[2]]), + ] tracks = [ - Track(uri='local:track:path1', name='track1', artists=artists[:1], - album=albums[0], date='2001-02-03', length=4000), - Track(uri='local:track:path2', name='track2', artists=artists[1:2], - album=albums[1], date='2002', length=4000), - Track()] + Track( + uri='local:track:path1', name='track1', + artists=[artists[0]], album=albums[0], + date='2001-02-03', length=4000), + Track( + uri='local:track:path2', name='track2', + artists=[artists[1]], album=albums[1], + date='2002', length=4000), + Track( + uri='local:track:path3', name='track3', + artists=[artists[3]], album=albums[2], + date='2003', length=4000), + ] config = { 'local': { @@ -35,6 +49,7 @@ class LocalLibraryControllerTest(unittest.TestCase): } def setUp(self): + self.backend = actor.LocalBackend.start( config=self.config, audio=None).proxy() self.core = core.Core(backends=[self.backend]) @@ -102,6 +117,19 @@ class LocalLibraryControllerTest(unittest.TestCase): result = self.library.find_exact(album=['album2']) self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + def test_find_exact_albumartist(self): + # Artist is both track artist and album artist + result = self.library.find_exact(albumartist=['artist1']) + self.assertEqual(list(result[0].tracks), [self.tracks[0]]) + + # Artist is both track and album artist + result = self.library.find_exact(albumartist=['artist2']) + self.assertEqual(list(result[0].tracks), [self.tracks[1]]) + + # Artist is just album artist + result = self.library.find_exact(albumartist=['artist3']) + self.assertEqual(list(result[0].tracks), [self.tracks[2]]) + def test_find_exact_date(self): result = self.library.find_exact(date=['2001']) self.assertEqual(list(result[0].tracks), []) @@ -163,6 +191,19 @@ class LocalLibraryControllerTest(unittest.TestCase): result = self.library.search(artist=['Tist2']) self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + def test_search_albumartist(self): + # Artist is both track artist and album artist + result = self.library.search(albumartist=['Tist1']) + self.assertEqual(list(result[0].tracks), [self.tracks[0]]) + + # Artist is both track artist and album artist + result = self.library.search(albumartist=['Tist2']) + self.assertEqual(list(result[0].tracks), [self.tracks[1]]) + + # Artist is just album artist + result = self.library.search(albumartist=['Tist3']) + self.assertEqual(list(result[0].tracks), [self.tracks[2]]) + def test_search_album(self): result = self.library.search(album=['Bum1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) diff --git a/tests/data/library_tag_cache b/tests/data/library_tag_cache index 9dc11777..2272a114 100644 --- a/tests/data/library_tag_cache +++ b/tests/data/library_tag_cache @@ -10,7 +10,7 @@ Title: track1 Album: album1 Date: 2001-02-03 Time: 4 -key: key1 +key: key2 file: /path2 Artist: artist2 Title: track2 @@ -19,8 +19,10 @@ Date: 2002 Time: 4 key: key3 file: /path3 -Artist: artist3 +Artist: artist4 +AlbumArtist: artist3 Title: track3 Album: album3 +Date: 2003 Time: 4 songList end From 76b70aa0c557c63826c1adae5acb10ab94ef3a8c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 31 Jul 2013 22:49:42 +0200 Subject: [PATCH 2/4] mpd: Make 'list' support 'albumartist' key --- mopidy/frontends/mpd/translator.py | 2 +- tests/frontends/mpd/protocol/music_db_test.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index 804f693a..df3338ba 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -166,7 +166,7 @@ def query_from_mpd_list_format(field, mpd_query): key = tokens[0].lower() value = tokens[1] tokens = tokens[2:] - if key not in ('artist', 'album', 'date', 'genre'): + if key not in ('artist', 'album', 'albumartist', 'date', 'genre'): raise MpdArgError('not able to parse args', command='list') if not value: raise ValueError diff --git a/tests/frontends/mpd/protocol/music_db_test.py b/tests/frontends/mpd/protocol/music_db_test.py index 21c6721f..eaa5da06 100644 --- a/tests/frontends/mpd/protocol/music_db_test.py +++ b/tests/frontends/mpd/protocol/music_db_test.py @@ -366,6 +366,10 @@ class MusicDatabaseListTest(protocol.BaseTestCase): self.sendRequest('list "album" "album" "analbum"') self.assertInResponse('OK') + def test_list_album_by_albumartist(self): + self.sendRequest('list "album" "albumartist" "anartist"') + self.assertInResponse('OK') + def test_list_album_by_full_date(self): self.sendRequest('list "album" "date" "2001-01-01"') self.assertInResponse('OK') From 7d874873bd1aac6294f0c9a20e22f7fbb61ebf6a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 19 Oct 2013 22:14:53 +0200 Subject: [PATCH 3/4] local: Include albumartist in 'any' searches --- mopidy/backends/local/library.py | 15 ++++++++---- tests/backends/local/library_test.py | 36 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/mopidy/backends/local/library.py b/mopidy/backends/local/library.py index 319049f0..0de63faf 100644 --- a/mopidy/backends/local/library.py +++ b/mopidy/backends/local/library.py @@ -67,8 +67,11 @@ class LocalLibraryProvider(base.BaseLibraryProvider): for a in getattr(t.album, 'artists', [])]) date_filter = lambda t: q == t.date any_filter = lambda t: ( - track_filter(t) or album_filter(t) or - artist_filter(t) or uri_filter(t)) + track_filter(t) or + album_filter(t) or + artist_filter(t) or + albumartist_filter(t) or + uri_filter(t)) if field == 'uri': result_tracks = filter(uri_filter, result_tracks) @@ -114,8 +117,12 @@ class LocalLibraryProvider(base.BaseLibraryProvider): q in a.name.lower() for a in getattr(t.album, 'artists', [])]) date_filter = lambda t: t.date and t.date.startswith(q) - any_filter = lambda t: track_filter(t) or album_filter(t) or \ - artist_filter(t) or uri_filter(t) + any_filter = lambda t: ( + track_filter(t) or + album_filter(t) or + artist_filter(t) or + albumartist_filter(t) or + uri_filter(t)) if field == 'uri': result_tracks = filter(uri_filter, result_tracks) diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index 149a9cb3..bc7181eb 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -140,6 +140,29 @@ class LocalLibraryControllerTest(unittest.TestCase): result = self.library.find_exact(date=['2002']) self.assertEqual(list(result[0].tracks), self.tracks[1:2]) + def test_find_exact_any(self): + # Matches on track artist + result = self.library.find_exact(any=['artist1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track + result = self.library.find_exact(any=['track1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track album + result = self.library.find_exact(any=['album1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track album artists + result = self.library.find_exact(any=['artist3']) + self.assertEqual(list(result[0].tracks), self.tracks[2:3]) + + # Matches on URI + result = self.library.find_exact(any=['local:track:path1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + result = self.library.find_exact(any=['local:track:path1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) + def test_find_exact_wrong_type(self): test = lambda: self.library.find_exact(wrong=['test']) self.assertRaises(LookupError, test) @@ -225,12 +248,25 @@ class LocalLibraryControllerTest(unittest.TestCase): self.assertEqual(list(result[0].tracks), self.tracks[1:2]) def test_search_any(self): + # Matches on track artist result = self.library.search(any=['Tist1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track result = self.library.search(any=['Rack1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track album result = self.library.search(any=['Bum1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) + + # Matches on track album artists + result = self.library.search(any=['Tist3']) + self.assertEqual(list(result[0].tracks), self.tracks[2:3]) + + # Matches on URI + result = self.library.search(any=['TH1']) + self.assertEqual(list(result[0].tracks), self.tracks[:1]) result = self.library.search(any=['TH1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) From 27a63b16888177a3747ffd5ba3bae12ba1d98ed8 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 19 Oct 2013 22:17:04 +0200 Subject: [PATCH 4/4] local: Remove redundant test asserts --- tests/backends/local/library_test.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index c0843dd5..6b0cd6f6 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -160,8 +160,6 @@ class LocalLibraryProviderTest(unittest.TestCase): # Matches on URI result = self.library.find_exact(any=['local:track:path1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) - result = self.library.find_exact(any=['local:track:path1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) def test_find_exact_wrong_type(self): test = lambda: self.library.find_exact(wrong=['test']) @@ -267,8 +265,6 @@ class LocalLibraryProviderTest(unittest.TestCase): # Matches on URI result = self.library.search(any=['TH1']) self.assertEqual(list(result[0].tracks), self.tracks[:1]) - result = self.library.search(any=['TH1']) - self.assertEqual(list(result[0].tracks), self.tracks[:1]) def test_search_wrong_type(self): test = lambda: self.library.search(wrong=['test'])