mpd: Complete music db conversion with list

This commit is contained in:
Thomas Adamcik 2014-01-24 00:22:51 +01:00
parent 68aa0b556c
commit dc8d311bc3
3 changed files with 39 additions and 79 deletions

View File

@ -6,27 +6,7 @@ import itertools
from mopidy.models import Ref, Track
from mopidy.mpd import exceptions, protocol, translator
LIST_QUERY = r"""
("?) # Optional quote around the field type
(?P<field>( # Field to list in the response
[Aa]lbum
| [Aa]lbumartist
| [Aa]rtist
| [Cc]omposer
| [Dd]ate
| [Gg]enre
| [Pp]erformer
))
\1 # End of optional quote around the field type
(?: # Non-capturing group for optional search query
\ # A single space
(?P<mpd_query>.*)
)?
$
"""
_SEARCH_FIELD_MAPPING = {
_SEARCH_MAPPING = {
'album': 'album',
'albumartist': 'albumartist',
'any': 'any',
@ -41,13 +21,22 @@ _SEARCH_FIELD_MAPPING = {
'title': 'track_name',
'track': 'track_no'}
_LIST_MAPPING = {
'album': 'album',
'albumartist': 'albumartist',
'artist': 'artist',
'composer': 'composer',
'date': 'date',
'genre': 'genre',
'performer': 'performer'}
def _query_from_mpd_search_parameters(parameters):
def _query_from_mpd_search_parameters(parameters, mapping):
query = {}
parameters = list(parameters)
while parameters:
# TODO: does it matter that this is now case insensitive
field = _SEARCH_FIELD_MAPPING.get(parameters.pop(0).lower())
field = mapping.get(parameters.pop(0).lower())
if not field:
raise exceptions.MpdArgError('incorrect arguments')
if not parameters:
@ -97,7 +86,7 @@ def count(context, *args):
- use multiple tag-needle pairs to make more specific searches.
"""
try:
query = _query_from_mpd_search_parameters(args)
query = _query_from_mpd_search_parameters(args, _SEARCH_MAPPING)
except ValueError:
raise exceptions.MpdArgError('incorrect arguments')
results = context.core.library.find_exact(**query).get()
@ -137,7 +126,7 @@ def find(context, *args):
- uses "file" instead of "filename".
"""
try:
query = _query_from_mpd_search_parameters(args)
query = _query_from_mpd_search_parameters(args, _SEARCH_MAPPING)
except ValueError:
return
@ -165,15 +154,15 @@ def findadd(context, *args):
current playlist. Parameters have the same meaning as for ``find``.
"""
try:
query = _query_from_mpd_search_parameters(args)
query = _query_from_mpd_search_parameters(args, _SEARCH_MAPPING)
except ValueError:
return
results = context.core.library.find_exact(**query).get()
context.core.tracklist.add(_get_tracks(results))
@protocol.handle_request(r'list\ ' + LIST_QUERY)
def list_(context, field, mpd_query=None):
@protocol.commands.add('list')
def list_(context, *args):
"""
*musicpd.org, music database section:*
@ -255,11 +244,27 @@ def list_(context, field, mpd_query=None):
- does not add quotes around the field argument.
- capitalizes the field argument.
"""
field = field.lower()
parameters = list(args)
if not parameters:
raise exceptions.MpdArgError('incorrect arguments')
field = parameters.pop(0).lower()
if field not in _LIST_MAPPING:
raise exceptions.MpdArgError('incorrect arguments')
if len(parameters) == 1:
if field != 'album':
raise exceptions.MpdArgError('should be "Album" for 3 arguments')
return _list_artist(context, {'artist': parameters})
try:
query = translator.query_from_mpd_list_format(field, mpd_query)
query = _query_from_mpd_search_parameters(parameters, _LIST_MAPPING)
except exceptions.MpdArgError as e:
e.message = 'not able to parse args'
raise
except ValueError:
return
if field == 'artist':
return _list_artist(context, query)
if field == 'albumartist':
@ -509,7 +514,7 @@ def search(context, *args):
- uses "file" instead of "filename".
"""
try:
query = _query_from_mpd_search_parameters(args)
query = _query_from_mpd_search_parameters(args, _SEARCH_MAPPING)
except ValueError:
return
results = context.core.library.search(**query).get()
@ -533,7 +538,7 @@ def searchadd(context, *args):
not case sensitive.
"""
try:
query = _query_from_mpd_search_parameters(args)
query = _query_from_mpd_search_parameters(args, _SEARCH_MAPPING)
except ValueError:
return
results = context.core.library.search(**query).get()
@ -560,7 +565,7 @@ def searchaddpl(context, *args):
raise exceptions.MpdArgError('incorrect arguments')
playlist_name = parameters.pop(0)
try:
query = _query_from_mpd_search_parameters(parameters)
query = _query_from_mpd_search_parameters(parameters, _SEARCH_MAPPING)
except ValueError:
return
results = context.core.library.search(**query).get()

View File

@ -1,9 +1,7 @@
from __future__ import unicode_literals
import re
import shlex
from mopidy.mpd.exceptions import MpdArgError
from mopidy.models import TlTrack
# TODO: special handling of local:// uri scheme
@ -137,46 +135,3 @@ def playlist_to_mpd_format(playlist, *args, **kwargs):
Arguments as for :func:`tracks_to_mpd_format`, except the first one.
"""
return tracks_to_mpd_format(playlist.tracks, *args, **kwargs)
def query_from_mpd_list_format(field, mpd_query):
"""
Converts an MPD ``list`` query to a Mopidy query.
"""
if mpd_query is None:
return {}
try:
# shlex does not seem to be friends with unicode objects
tokens = shlex.split(mpd_query.encode('utf-8'))
except ValueError as error:
if str(error) == 'No closing quotation':
raise MpdArgError('Invalid unquoted character', command='list')
else:
raise
tokens = [t.decode('utf-8') for t in tokens]
if len(tokens) == 1:
if field == 'album':
if not tokens[0]:
raise ValueError
return {'artist': [tokens[0]]}
else:
raise MpdArgError(
'should be "Album" for 3 arguments', command='list')
elif len(tokens) % 2 == 0:
query = {}
while tokens:
key = tokens[0].lower()
value = tokens[1]
tokens = tokens[2:]
if key not in ('artist', 'album', 'albumartist', 'composer',
'date', 'genre', 'performer'):
raise MpdArgError('not able to parse args', command='list')
if not value:
raise ValueError
if key in query:
query[key].append(value)
else:
query[key] = [value]
return query
else:
raise MpdArgError('not able to parse args', command='list')

View File

@ -12,7 +12,7 @@ from tests.mpd import protocol
class QueryFromMpdSearchFormatTest(unittest.TestCase):
def test_dates_are_extracted(self):
result = music_db._query_from_mpd_search_parameters(
['Date', '1974-01-02', 'Date', '1975'])
['Date', '1974-01-02', 'Date', '1975'], music_db._SEARCH_MAPPING)
self.assertEqual(result['date'][0], '1974-01-02')
self.assertEqual(result['date'][1], '1975')