Merge branch 'feature/search-by-date' into develop

This commit is contained in:
Stein Magnus Jodal 2012-12-20 21:34:53 +01:00
commit bb2c1e3e50
8 changed files with 95 additions and 35 deletions

View File

@ -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:*

View File

@ -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:

View File

@ -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']

View File

@ -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)

View File

@ -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):

View File

@ -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])

View File

@ -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

View File

@ -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'