diff --git a/docs/changelog.rst b/docs/changelog.rst index 320c776a..e1174c7d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -47,6 +47,9 @@ Models reuse instances. For the test data set this was developed against, a library of ~14000 tracks, went from needing ~75MB to ~17MB. (Fixes: :issue:`348`) +- Added :attr:`mopidy.models.Artist.sortname` field that is mapped to + ``musicbrainz-sortname`` tag. (Fixes: :issue:`940`) + MPD frontend ------------ diff --git a/mopidy/audio/utils.py b/mopidy/audio/utils.py index 3b9ea30f..a4333b5a 100644 --- a/mopidy/audio/utils.py +++ b/mopidy/audio/utils.py @@ -65,15 +65,21 @@ def supported_uri_schemes(uri_schemes): return supported_schemes -def _artists(tags, artist_name, artist_id=None): +def _artists(tags, artist_name, artist_id=None, artist_sortname=None): # Name missing, don't set artist if not tags.get(artist_name): return None - # One artist name and id, provide artist with id. - if len(tags[artist_name]) == 1 and artist_id in tags: - return [Artist(name=tags[artist_name][0], - musicbrainz_id=tags[artist_id][0])] - # Multiple artist, provide artists without id. + # One artist name and either id or sortname, include all available fields + if len(tags[artist_name]) == 1 and \ + (artist_id in tags or artist_sortname in tags): + attrs = {'name': tags[artist_name][0]} + if artist_id in tags: + attrs['musicbrainz_id'] = tags[artist_id][0] + if artist_sortname in tags: + attrs['sortname'] = tags[artist_sortname][0] + return [Artist(**attrs)] + + # Multiple artist, provide artists with name only to avoid ambiguity. return [Artist(name=name) for name in tags[artist_name]] @@ -91,8 +97,9 @@ def convert_tags_to_track(tags): track_kwargs['composers'] = _artists(tags, gst.TAG_COMPOSER) track_kwargs['performers'] = _artists(tags, gst.TAG_PERFORMER) - track_kwargs['artists'] = _artists( - tags, gst.TAG_ARTIST, 'musicbrainz-artistid') + track_kwargs['artists'] = _artists(tags, gst.TAG_ARTIST, + 'musicbrainz-artistid', + 'musicbrainz-sortname') album_kwargs['artists'] = _artists( tags, gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid') diff --git a/mopidy/models/__init__.py b/mopidy/models/__init__.py index 231a472a..c84254cd 100644 --- a/mopidy/models/__init__.py +++ b/mopidy/models/__init__.py @@ -117,6 +117,9 @@ class Artist(ValidatedImmutableObject): #: The artist name. Read-only. name = fields.String() + #: Artist name for better sorting, e.g. with articles stripped + sortname = fields.String() + #: The MusicBrainz ID of the artist. Read-only. musicbrainz_id = fields.Identifier() diff --git a/tests/audio/test_utils.py b/tests/audio/test_utils.py index 200d7729..0b497dad 100644 --- a/tests/audio/test_utils.py +++ b/tests/audio/test_utils.py @@ -31,11 +31,13 @@ class TagsToTrackTest(unittest.TestCase): 'musicbrainz-trackid': ['trackid'], 'musicbrainz-albumid': ['albumid'], 'musicbrainz-artistid': ['artistid'], + 'musicbrainz-sortname': ['sortname'], 'musicbrainz-albumartistid': ['albumartistid'], 'bitrate': [1000], } - artist = Artist(name='artist', musicbrainz_id='artistid') + artist = Artist(name='artist', musicbrainz_id='artistid', + sortname='sortname') composer = Artist(name='composer') performer = Artist(name='performer') albumartist = Artist(name='albumartist', @@ -245,3 +247,15 @@ class TagsToTrackTest(unittest.TestCase): del self.tags['comment'] self.tags['copyright'] = ['copyright1', 'copyright2'] self.check(self.track.replace(comment='copyright1; copyright2')) + + def test_sortname(self): + self.tags['musicbrainz-sortname'] = ['another_sortname'] + artist = Artist(name='artist', sortname='another_sortname', + musicbrainz_id='artistid') + self.check(self.track.replace(artists=[artist])) + + def test_missing_sortname(self): + del self.tags['musicbrainz-sortname'] + artist = Artist(name='artist', sortname=None, + musicbrainz_id='artistid') + self.check(self.track.replace(artists=[artist]))