Merge branch 'feature/search-by-date' into develop
This commit is contained in:
commit
bb2c1e3e50
@ -24,6 +24,12 @@ v0.11.0 (in development)
|
||||
add "spotify:artist:5TgQ66WuWkoQ2xYxaSTnVP"
|
||||
add "spotify:user:p3.no:playlist:0XX6tamRiqEgh3t6FPFEkw"
|
||||
|
||||
**Local backend**
|
||||
|
||||
- Load track dates from tag cache.
|
||||
|
||||
- Add support for searching by track date.
|
||||
|
||||
**MPD frontend**
|
||||
|
||||
- Add :attr:`mopidy.settings.MPD_SERVER_CONNECTION_TIMEOUT` setting which
|
||||
@ -47,6 +53,8 @@ v0.11.0 (in development)
|
||||
|
||||
- Add empty stubs for channel commands for client to client communication.
|
||||
|
||||
- Add support for search by date.
|
||||
|
||||
**Internal changes**
|
||||
|
||||
*Models:*
|
||||
|
||||
@ -46,23 +46,26 @@ class LocalLibraryProvider(base.BaseLibraryProvider):
|
||||
for value in values:
|
||||
q = value.strip()
|
||||
|
||||
uri_filter = lambda t: q == t.uri
|
||||
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
|
||||
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))
|
||||
|
||||
if field == 'track':
|
||||
if field == 'uri':
|
||||
result_tracks = filter(uri_filter, result_tracks)
|
||||
elif 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 == 'date':
|
||||
result_tracks = filter(date_filter, result_tracks)
|
||||
elif field == 'any':
|
||||
result_tracks = filter(any_filter, result_tracks)
|
||||
else:
|
||||
@ -80,23 +83,26 @@ class LocalLibraryProvider(base.BaseLibraryProvider):
|
||||
for value in values:
|
||||
q = value.strip().lower()
|
||||
|
||||
uri_filter = lambda t: q in t.uri.lower()
|
||||
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)
|
||||
uri_filter = lambda t: q in t.uri.lower()
|
||||
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)
|
||||
|
||||
if field == 'track':
|
||||
if field == 'uri':
|
||||
result_tracks = filter(uri_filter, result_tracks)
|
||||
elif 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 == 'date':
|
||||
result_tracks = filter(date_filter, result_tracks)
|
||||
elif field == 'any':
|
||||
result_tracks = filter(any_filter, result_tracks)
|
||||
else:
|
||||
|
||||
@ -123,6 +123,9 @@ def _convert_mpd_data(data, tracks, music_dir):
|
||||
if 'title' in data:
|
||||
track_kwargs['name'] = data['title']
|
||||
|
||||
if 'date' in data:
|
||||
track_kwargs['date'] = data['date']
|
||||
|
||||
if 'musicbrainz_trackid' in data:
|
||||
track_kwargs['musicbrainz_id'] = data['musicbrainz_trackid']
|
||||
|
||||
|
||||
@ -187,12 +187,15 @@ 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|[Ff]ile[name]*|[Tt]itle|[Aa]ny)"? "[^"]+"')
|
||||
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<field>([Aa]lbum|[Aa]rtist|[Ff]ile[name]*|[Tt]itle|[Aa]ny))"? '
|
||||
r'"(?P<what>[^"]+)"')
|
||||
r'"?(?P<field>([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ile|[Ff]ilename|'
|
||||
r'[Tt]itle|[Aa]ny))"? "(?P<what>[^"]+)"')
|
||||
query = {}
|
||||
for query_part in query_parts:
|
||||
m = re.match(query_part_pattern, query_part)
|
||||
|
||||
@ -16,11 +16,12 @@ class LibraryControllerTest(object):
|
||||
Album()]
|
||||
tracks = [
|
||||
Track(
|
||||
name='track1', length=4000, artists=artists[:1],
|
||||
album=albums[0], uri='file://' + path_to_data_dir('uri1')),
|
||||
uri='file://' + path_to_data_dir('uri1'), name='track1',
|
||||
artists=artists[:1], album=albums[0], date='2001-02-03',
|
||||
length=4000),
|
||||
Track(
|
||||
name='track2', length=4000, artists=artists[1:2],
|
||||
album=albums[1], uri='file://' + path_to_data_dir('uri2')),
|
||||
uri='file://' + path_to_data_dir('uri2'), name='track2',
|
||||
artists=artists[1:2], album=albums[1], date='2002', length=4000),
|
||||
Track()]
|
||||
|
||||
def setUp(self):
|
||||
@ -60,11 +61,13 @@ class LibraryControllerTest(object):
|
||||
result = self.library.find_exact(album=['unknown artist'])
|
||||
self.assertEqual(result, [])
|
||||
|
||||
def test_find_exact_artist(self):
|
||||
result = self.library.find_exact(artist=['artist1'])
|
||||
def test_find_exact_uri(self):
|
||||
track_1_uri = 'file://' + path_to_data_dir('uri1')
|
||||
result = self.library.find_exact(uri=track_1_uri)
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.find_exact(artist=['artist2'])
|
||||
track_2_uri = 'file://' + path_to_data_dir('uri2')
|
||||
result = self.library.find_exact(uri=track_2_uri)
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_find_exact_track(self):
|
||||
@ -74,6 +77,13 @@ class LibraryControllerTest(object):
|
||||
result = self.library.find_exact(track=['track2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_find_exact_artist(self):
|
||||
result = self.library.find_exact(artist=['artist1'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.find_exact(artist=['artist2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_find_exact_album(self):
|
||||
result = self.library.find_exact(album=['album1'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
@ -81,13 +91,14 @@ class LibraryControllerTest(object):
|
||||
result = self.library.find_exact(album=['album2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_find_exact_uri(self):
|
||||
track_1_uri = 'file://' + path_to_data_dir('uri1')
|
||||
result = self.library.find_exact(uri=track_1_uri)
|
||||
def test_find_exact_date(self):
|
||||
result = self.library.find_exact(date=['2001'])
|
||||
self.assertEqual(result, [])
|
||||
|
||||
result = self.library.find_exact(date=['2001-02-03'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
track_2_uri = 'file://' + path_to_data_dir('uri2')
|
||||
result = self.library.find_exact(uri=track_2_uri)
|
||||
result = self.library.find_exact(date=['2002'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_find_exact_wrong_type(self):
|
||||
@ -120,11 +131,11 @@ class LibraryControllerTest(object):
|
||||
result = self.library.search(any=['unknown'])
|
||||
self.assertEqual(result, [])
|
||||
|
||||
def test_search_artist(self):
|
||||
result = self.library.search(artist=['Tist1'])
|
||||
def test_search_uri(self):
|
||||
result = self.library.search(uri=['RI1'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.search(artist=['Tist2'])
|
||||
result = self.library.search(uri=['RI2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_search_track(self):
|
||||
@ -134,6 +145,13 @@ class LibraryControllerTest(object):
|
||||
result = self.library.search(track=['Rack2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_search_artist(self):
|
||||
result = self.library.search(artist=['Tist1'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.search(artist=['Tist2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_search_album(self):
|
||||
result = self.library.search(album=['Bum1'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
@ -141,11 +159,17 @@ class LibraryControllerTest(object):
|
||||
result = self.library.search(album=['Bum2'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_search_uri(self):
|
||||
result = self.library.search(uri=['RI1'])
|
||||
def test_search_date(self):
|
||||
result = self.library.search(date=['2001'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.search(uri=['RI2'])
|
||||
result = self.library.search(date=['2001-02-03'])
|
||||
self.assertEqual(result, self.tracks[:1])
|
||||
|
||||
result = self.library.search(date=['2001-02-04'])
|
||||
self.assertEqual(result, [])
|
||||
|
||||
result = self.library.search(date=['2002'])
|
||||
self.assertEqual(result, self.tracks[1:2])
|
||||
|
||||
def test_search_any(self):
|
||||
|
||||
@ -99,8 +99,8 @@ expected_tracks = []
|
||||
def generate_track(path, ident):
|
||||
uri = path_to_uri(path_to_data_dir(path))
|
||||
track = Track(
|
||||
name='trackname', artists=expected_artists, track_no=1,
|
||||
album=expected_albums[0], length=4000, uri=uri)
|
||||
uri=uri, name='trackname', artists=expected_artists,
|
||||
album=expected_albums[0], track_no=1, date='2006', length=4000)
|
||||
expected_tracks.append(track)
|
||||
|
||||
|
||||
@ -126,8 +126,8 @@ class MPDTagCacheToTracksTest(unittest.TestCase):
|
||||
path_to_data_dir('simple_tag_cache'), path_to_data_dir(''))
|
||||
uri = path_to_uri(path_to_data_dir('song1.mp3'))
|
||||
track = Track(
|
||||
name='trackname', artists=expected_artists, track_no=1,
|
||||
album=expected_albums[0], length=4000, uri=uri)
|
||||
uri=uri, name='trackname', artists=expected_artists, track_no=1,
|
||||
album=expected_albums[0], date='2006', length=4000)
|
||||
self.assertEqual(set([track]), tracks)
|
||||
|
||||
def test_advanced_cache(self):
|
||||
@ -182,6 +182,6 @@ class MPDTagCacheToTracksTest(unittest.TestCase):
|
||||
artist = Artist(name='albumartistname')
|
||||
album = expected_albums[0].copy(artists=[artist])
|
||||
track = Track(
|
||||
name='trackname', artists=expected_artists, track_no=1,
|
||||
album=album, length=4000, uri=uri)
|
||||
uri=uri, name='trackname', artists=expected_artists, track_no=1,
|
||||
album=album, date='2006', length=4000)
|
||||
self.assertEqual(track, list(tracks)[0])
|
||||
|
||||
@ -8,12 +8,14 @@ file: /uri1
|
||||
Artist: artist1
|
||||
Title: track1
|
||||
Album: album1
|
||||
Date: 2001-02-03
|
||||
Time: 4
|
||||
key: uri2
|
||||
file: /uri2
|
||||
Artist: artist2
|
||||
Title: track2
|
||||
Album: album2
|
||||
Date: 2002
|
||||
Time: 4
|
||||
key: uri3
|
||||
file: /uri3
|
||||
|
||||
@ -121,6 +121,20 @@ class PlaylistMpdFormatTest(unittest.TestCase):
|
||||
self.assertEqual(dict(result[0])['Track'], 2)
|
||||
|
||||
|
||||
class QueryFromMpdSearchFormatTest(unittest.TestCase):
|
||||
def test_dates_are_extracted(self):
|
||||
result = translator.query_from_mpd_search_format(
|
||||
'Date "1974-01-02" Date "1975"')
|
||||
self.assertEqual(result['date'][0], '1974-01-02')
|
||||
self.assertEqual(result['date'][1], '1975')
|
||||
|
||||
# TODO Test more mappings
|
||||
|
||||
|
||||
class QueryFromMpdListFormatTest(unittest.TestCase):
|
||||
pass # TODO
|
||||
|
||||
|
||||
class TracksToTagCacheFormatTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
settings.LOCAL_MUSIC_PATH = '/dir/subdir'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user