mpd: Extract query translators for direct testing
This commit is contained in:
parent
cb78dc6341
commit
08f0178425
@ -1,11 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
import shlex
|
||||
|
||||
from mopidy.frontends.mpd.exceptions import MpdArgError, MpdNotImplemented
|
||||
from mopidy.frontends.mpd import translator
|
||||
from mopidy.frontends.mpd.exceptions import MpdNotImplemented
|
||||
from mopidy.frontends.mpd.protocol import handle_request, stored_playlists
|
||||
from mopidy.frontends.mpd.translator import tracks_to_mpd_format
|
||||
|
||||
|
||||
QUERY_RE = (
|
||||
@ -13,35 +10,6 @@ QUERY_RE = (
|
||||
r'[Tt]itle|[Aa]ny)"? "[^"]*"\s?)+)$')
|
||||
|
||||
|
||||
def _build_query(mpd_query):
|
||||
"""
|
||||
Parses a MPD query string and converts it to the Mopidy query format.
|
||||
"""
|
||||
query_pattern = (
|
||||
r'"?(?:[Aa]lbum|[Aa]rtist|[Ff]ile[name]*|[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>[^"]+)"')
|
||||
query = {}
|
||||
for query_part in query_parts:
|
||||
m = re.match(query_part_pattern, query_part)
|
||||
field = m.groupdict()['field'].lower()
|
||||
if field == 'title':
|
||||
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
|
||||
if field in query:
|
||||
query[field].append(what)
|
||||
else:
|
||||
query[field] = [what]
|
||||
return query
|
||||
|
||||
|
||||
@handle_request(r'^count "(?P<tag>[^"]+)" "(?P<needle>[^"]*)"$')
|
||||
def count(context, tag, needle):
|
||||
"""
|
||||
@ -84,11 +52,11 @@ def find(context, mpd_query):
|
||||
- uses "file" instead of "filename".
|
||||
"""
|
||||
try:
|
||||
query = _build_query(mpd_query)
|
||||
query = translator.query_from_mpd_search_format(mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
result = context.core.library.find_exact(**query).get()
|
||||
return tracks_to_mpd_format(result)
|
||||
return translator.tracks_to_mpd_format(result)
|
||||
|
||||
|
||||
@handle_request(r'^findadd ' + QUERY_RE)
|
||||
@ -102,7 +70,7 @@ def findadd(context, mpd_query):
|
||||
current playlist. Parameters have the same meaning as for ``find``.
|
||||
"""
|
||||
try:
|
||||
query = _build_query(mpd_query)
|
||||
query = translator.query_from_mpd_search_format(mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
result = context.core.library.find_exact(**query).get()
|
||||
@ -196,7 +164,7 @@ def list_(context, field, mpd_query=None):
|
||||
"""
|
||||
field = field.lower()
|
||||
try:
|
||||
query = _list_build_query(field, mpd_query)
|
||||
query = translator.query_from_mpd_list_format(field, mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
if field == 'artist':
|
||||
@ -209,47 +177,6 @@ def list_(context, field, mpd_query=None):
|
||||
pass # TODO We don't have genre in our internal data structures yet
|
||||
|
||||
|
||||
def _list_build_query(field, mpd_query):
|
||||
"""Converts a ``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()
|
||||
key = str(key) # Needed for kwargs keys on OS X and Windows
|
||||
value = tokens[1]
|
||||
tokens = tokens[2:]
|
||||
if key not in ('artist', 'album', 'date', 'genre'):
|
||||
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')
|
||||
|
||||
|
||||
def _list_artist(context, query):
|
||||
artists = set()
|
||||
tracks = context.core.library.find_exact(**query).get()
|
||||
@ -367,11 +294,11 @@ def search(context, mpd_query):
|
||||
- uses "file" instead of "filename".
|
||||
"""
|
||||
try:
|
||||
query = _build_query(mpd_query)
|
||||
query = translator.query_from_mpd_search_format(mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
result = context.core.library.search(**query).get()
|
||||
return tracks_to_mpd_format(result)
|
||||
return translator.tracks_to_mpd_format(result)
|
||||
|
||||
|
||||
@handle_request(r'^searchadd ' + QUERY_RE)
|
||||
@ -388,7 +315,7 @@ def searchadd(context, mpd_query):
|
||||
not case sensitive.
|
||||
"""
|
||||
try:
|
||||
query = _build_query(mpd_query)
|
||||
query = translator.query_from_mpd_search_format(mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
result = context.core.library.search(**query).get()
|
||||
@ -411,7 +338,7 @@ def searchaddpl(context, playlist_name, mpd_query):
|
||||
not case sensitive.
|
||||
"""
|
||||
try:
|
||||
query = _build_query(mpd_query)
|
||||
query = translator.query_from_mpd_search_format(mpd_query)
|
||||
except ValueError:
|
||||
return
|
||||
result = context.core.library.search(**query).get()
|
||||
|
||||
@ -2,10 +2,12 @@ from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import urllib
|
||||
|
||||
from mopidy import settings
|
||||
from mopidy.frontends.mpd import protocol
|
||||
from mopidy.frontends.mpd.exceptions import MpdArgError
|
||||
from mopidy.models import TlTrack
|
||||
from mopidy.utils.path import mtime as get_mtime, uri_to_path, split_path
|
||||
|
||||
@ -134,6 +136,82 @@ def playlist_to_mpd_format(playlist, *args, **kwargs):
|
||||
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()
|
||||
key = str(key) # Needed for kwargs keys on OS X and Windows
|
||||
value = tokens[1]
|
||||
tokens = tokens[2:]
|
||||
if key not in ('artist', 'album', 'date', 'genre'):
|
||||
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')
|
||||
|
||||
|
||||
def query_from_mpd_search_format(mpd_query):
|
||||
"""
|
||||
Parses an MPD ``search`` or ``find`` query and converts it to the Mopidy
|
||||
query format.
|
||||
|
||||
:param mpd_query: the MPD search query
|
||||
:type mpd_query: string
|
||||
"""
|
||||
query_pattern = (
|
||||
r'"?(?:[Aa]lbum|[Aa]rtist|[Ff]ile[name]*|[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>[^"]+)"')
|
||||
query = {}
|
||||
for query_part in query_parts:
|
||||
m = re.match(query_part_pattern, query_part)
|
||||
field = m.groupdict()['field'].lower()
|
||||
if field == 'title':
|
||||
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
|
||||
if field in query:
|
||||
query[field].append(what)
|
||||
else:
|
||||
query[field] = [what]
|
||||
return query
|
||||
|
||||
|
||||
def tracks_to_tag_cache_format(tracks):
|
||||
"""
|
||||
Format list of tracks for output to MPD tag cache
|
||||
|
||||
Loading…
Reference in New Issue
Block a user