Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/extra tags #559

Merged
merged 14 commits into from
Nov 14, 2013
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ v0.17.0 (UNRELEASED)
(Fixes: :issue:`565`)
- Fix scanner so that mtime is respected when deciding which files can be skipped.

**MPD frontend**

- Add support for ``composer``, ``comment``, ``genre``, and ``performer``.
These tags can be used with ``list ...``, ``search ...``, and
``find ...`` and their variants, and are supported in the ``any`` tag also

v0.16.1 (2013-11-02)
====================
Expand Down
1 change: 0 additions & 1 deletion docs/ext/mpd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ Items on this list will probably not be supported in the near future.
- Crossfade is not supported
- Replay gain is not supported
- ``stats`` does not provide any statistics
- ``list`` does not support listing tracks by genre
- ``decoders`` does not provide information about available decoders

The following items are currently not supported, but should be added in the
Expand Down
44 changes: 33 additions & 11 deletions mopidy/audio/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ def audio_data_to_track(data):
albumartist_kwargs = {}
album_kwargs = {}
artist_kwargs = {}
composer_kwargs = {}
performer_kwargs = {}
track_kwargs = {}

def _retrieve(source_key, target_key, target):
Expand All @@ -115,28 +117,32 @@ def _retrieve(source_key, target_key, target):
_retrieve(gst.TAG_TRACK_COUNT, 'num_tracks', album_kwargs)
_retrieve(gst.TAG_ALBUM_VOLUME_COUNT, 'num_discs', album_kwargs)
_retrieve(gst.TAG_ARTIST, 'name', artist_kwargs)

if gst.TAG_DATE in data and data[gst.TAG_DATE]:
date = data[gst.TAG_DATE]
try:
date = datetime.date(date.year, date.month, date.day)
except ValueError:
pass # Ignore invalid dates
else:
track_kwargs['date'] = date.isoformat()

_retrieve(gst.TAG_COMPOSER, 'name', composer_kwargs)
_retrieve(gst.TAG_PERFORMER, 'name', performer_kwargs)
_retrieve(gst.TAG_ALBUM_ARTIST, 'name', albumartist_kwargs)
_retrieve(gst.TAG_TITLE, 'name', track_kwargs)
_retrieve(gst.TAG_TRACK_NUMBER, 'track_no', track_kwargs)
_retrieve(gst.TAG_ALBUM_VOLUME_NUMBER, 'disc_no', track_kwargs)
_retrieve(gst.TAG_GENRE, 'genre', track_kwargs)
_retrieve(gst.TAG_BITRATE, 'bitrate', track_kwargs)

# Following keys don't seem to have TAG_* constant.
_retrieve('album-artist', 'name', albumartist_kwargs)
_retrieve('comment', 'comment', track_kwargs)
_retrieve('musicbrainz-trackid', 'musicbrainz_id', track_kwargs)
_retrieve('musicbrainz-artistid', 'musicbrainz_id', artist_kwargs)
_retrieve('musicbrainz-albumid', 'musicbrainz_id', album_kwargs)
_retrieve(
'musicbrainz-albumartistid', 'musicbrainz_id', albumartist_kwargs)

if gst.TAG_DATE in data and data[gst.TAG_DATE]:
date = data[gst.TAG_DATE]
try:
date = datetime.date(date.year, date.month, date.day)
except ValueError:
pass # Ignore invalid dates
else:
track_kwargs['date'] = date.isoformat()

if albumartist_kwargs:
album_kwargs['artists'] = [Artist(**albumartist_kwargs)]

Expand All @@ -146,4 +152,20 @@ def _retrieve(source_key, target_key, target):
track_kwargs['album'] = Album(**album_kwargs)
track_kwargs['artists'] = [Artist(**artist_kwargs)]

if ('name' in composer_kwargs
and not isinstance(composer_kwargs['name'], basestring)):
track_kwargs['composers'] = [Artist(name=artist)
for artist in composer_kwargs['name']]
else:
track_kwargs['composers'] = \
[Artist(**composer_kwargs)] if composer_kwargs else ''

if ('name' in performer_kwargs
and not isinstance(performer_kwargs['name'], basestring)):
track_kwargs['performers'] = [Artist(name=artist)
for artist in performer_kwargs['name']]
else:
track_kwargs['performers'] = \
[Artist(**performer_kwargs)] if performer_kwargs else ''

return Track(**track_kwargs)
46 changes: 44 additions & 2 deletions mopidy/backends/local/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,28 @@ def find_exact(self, query=None, uris=None):
albumartist_filter = lambda t: any([
q == a.name
for a in getattr(t.album, 'artists', [])])
composer_filter = lambda t: any([
q == a.name
for a in getattr(t, 'composers', [])])
performer_filter = lambda t: any([
q == a.name
for a in getattr(t, 'performers', [])])
track_no_filter = lambda t: q == t.track_no
genre_filter = lambda t: t.genre and q == t.genre
date_filter = lambda t: q == t.date
comment_filter = lambda t: q == t.comment
any_filter = lambda t: (
uri_filter(t) or
track_name_filter(t) or
album_filter(t) or
artist_filter(t) or
albumartist_filter(t) or
date_filter(t))
composer_filter(t) or
performer_filter(t) or
track_no_filter(t) or
genre_filter(t) or
date_filter(t) or
comment_filter(t))

if field == 'uri':
result_tracks = filter(uri_filter, result_tracks)
Expand All @@ -99,10 +112,18 @@ def find_exact(self, query=None, uris=None):
result_tracks = filter(artist_filter, result_tracks)
elif field == 'albumartist':
result_tracks = filter(albumartist_filter, result_tracks)
elif field == 'composer':
result_tracks = filter(composer_filter, result_tracks)
elif field == 'performer':
result_tracks = filter(performer_filter, result_tracks)
elif field == 'track_no':
result_tracks = filter(track_no_filter, result_tracks)
elif field == 'genre':
result_tracks = filter(genre_filter, result_tracks)
elif field == 'date':
result_tracks = filter(date_filter, result_tracks)
elif field == 'comment':
result_tracks = filter(comment_filter, result_tracks)
elif field == 'any':
result_tracks = filter(any_filter, result_tracks)
else:
Expand Down Expand Up @@ -137,15 +158,28 @@ def search(self, query=None, uris=None):
albumartist_filter = lambda t: any([
q in a.name.lower()
for a in getattr(t.album, 'artists', [])])
composer_filter = lambda t: any([
q in a.name.lower()
for a in getattr(t, 'composers', [])])
performer_filter = lambda t: any([
q in a.name.lower()
for a in getattr(t, 'performers', [])])
track_no_filter = lambda t: q == t.track_no
genre_filter = lambda t: t.genre and q in t.genre.lower()
date_filter = lambda t: t.date and t.date.startswith(q)
comment_filter = lambda t: t.comment and q in t.comment.lower()
any_filter = lambda t: (
uri_filter(t) or
track_name_filter(t) or
album_filter(t) or
artist_filter(t) or
albumartist_filter(t) or
date_filter(t))
composer_filter(t) or
performer_filter(t) or
track_no_filter(t) or
genre_filter(t) or
date_filter(t) or
comment_filter(t))

if field == 'uri':
result_tracks = filter(uri_filter, result_tracks)
Expand All @@ -157,10 +191,18 @@ def search(self, query=None, uris=None):
result_tracks = filter(artist_filter, result_tracks)
elif field == 'albumartist':
result_tracks = filter(albumartist_filter, result_tracks)
elif field == 'composer':
result_tracks = filter(composer_filter, result_tracks)
elif field == 'performer':
result_tracks = filter(performer_filter, result_tracks)
elif field == 'track_no':
result_tracks = filter(track_no_filter, result_tracks)
elif field == 'genre':
result_tracks = filter(genre_filter, result_tracks)
elif field == 'date':
result_tracks = filter(date_filter, result_tracks)
elif field == 'comment':
result_tracks = filter(comment_filter, result_tracks)
elif field == 'any':
result_tracks = filter(any_filter, result_tracks)
else:
Expand Down
12 changes: 12 additions & 0 deletions mopidy/backends/local/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,27 @@ def _convert_mpd_data(data, tracks):
if 'albumartist' in data:
albumartist_kwargs['name'] = data['albumartist']

if 'composer' in data:
track_kwargs['composers'] = [Artist(name=data['composer'])]

if 'performer' in data:
track_kwargs['performers'] = [Artist(name=data['performer'])]

if 'album' in data:
album_kwargs['name'] = data['album']

if 'title' in data:
track_kwargs['name'] = data['title']

if 'genre' in data:
track_kwargs['genre'] = data['genre']

if 'date' in data:
track_kwargs['date'] = data['date']

if 'comment' in data:
track_kwargs['comment'] = data['comment']

if 'musicbrainz_trackid' in data:
track_kwargs['musicbrainz_id'] = data['musicbrainz_trackid']

Expand Down
52 changes: 45 additions & 7 deletions mopidy/frontends/mpd/protocol/music_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@


QUERY_RE = (
r'(?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Aa]lbumartist|[Dd]ate|[Ff]ile|'
r'[Ff]ilename|[Tt]itle|[Tt]rack|[Aa]ny)"? "[^"]*"\s?)+)$')
r'(?P<mpd_query>("?([Aa]lbum|[Aa]rtist|[Aa]lbumartist|[Cc]omment|'
r'[Cc]omposer|[Dd]ate|[Ff]ile|[Ff]ilename|[Gg]enre|[Pp]erformer|'
r'[Tt]itle|[Tt]rack|[Aa]ny)"? "[^"]*"\s?)+)$')


def _get_field(field, search_results):
Expand Down Expand Up @@ -100,9 +101,12 @@ def find(context, mpd_query):
return
results = context.core.library.find_exact(**query).get()
result_tracks = []
if 'artist' not in query and 'albumartist' not in query:
if ('artist' not in query and
'albumartist' not in query and
'composer' not in query and
'performer' not in query):
result_tracks += [_artist_as_track(a) for a in _get_artists(results)]
if 'album' not in query:
if 'album' not in query and 'genre' not in query:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you want albums in the result when genre is in the search query?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I guess I don't need to filter really - but my thinking was along the lines of albums not having genres?
The genre relates to the track, right?
So in reality we will never get a hit on an album?

result_tracks += [_album_as_track(a) for a in _get_albums(results)]
result_tracks += _get_tracks(results)
return translator.tracks_to_mpd_format(result_tracks)
Expand All @@ -127,8 +131,9 @@ def findadd(context, mpd_query):


@handle_request(
r'^list "?(?P<field>([Aa]rtist|[Aa]lbumartist|[Aa]lbum|[Dd]ate|'
r'[Gg]enre))"?( (?P<mpd_query>.*))?$')
r'^list "?(?P<field>([Aa]rtist|[Aa]lbumartist|[Aa]lbum|[Cc]omposer|'
r'[Dd]ate|[Gg]enre|[Pp]erformer))"?'
r'( (?P<mpd_query>.*))?$')
def list_(context, field, mpd_query=None):
"""
*musicpd.org, music database section:*
Expand Down Expand Up @@ -222,10 +227,14 @@ def list_(context, field, mpd_query=None):
return _list_albumartist(context, query)
elif field == 'album':
return _list_album(context, query)
elif field == 'composer':
return _list_composer(context, query)
elif field == 'performer':
return _list_performer(context, query)
elif field == 'date':
return _list_date(context, query)
elif field == 'genre':
pass # TODO We don't have genre in our internal data structures yet
return _list_genre(context, query)


def _list_artist(context, query):
Expand Down Expand Up @@ -258,6 +267,26 @@ def _list_album(context, query):
return albums


def _list_composer(context, query):
composers = set()
results = context.core.library.find_exact(**query).get()
for track in _get_tracks(results):
for composer in track.composers:
if composer.name:
composers.add(('Composer', composer.name))
return composers


def _list_performer(context, query):
performers = set()
results = context.core.library.find_exact(**query).get()
for track in _get_tracks(results):
for performer in track.performers:
if performer.name:
performers.add(('Performer', performer.name))
return performers


def _list_date(context, query):
dates = set()
results = context.core.library.find_exact(**query).get()
Expand All @@ -267,6 +296,15 @@ def _list_date(context, query):
return dates


def _list_genre(context, query):
genres = set()
results = context.core.library.find_exact(**query).get()
for track in _get_tracks(results):
if track.genre:
genres.add(('Genre', track.genre))
return genres


@handle_request(r'^listall$')
@handle_request(r'^listall "(?P<uri>[^"]+)"$')
def listall(context, uri=None):
Expand Down
Loading