From 2f1ac61d4f57d2a3fc8fcad1ebadaadc4b482374 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 25 Mar 2012 17:02:52 -0700 Subject: [PATCH] track and album artist sort names (GH-25, GC-77) Previously, there was just an "artist sort name" field -- now there's a corresponding sort name for both track artists and album artists. I also made the names shorter (artist_sort and albumartist_sort). --- beets/autotag/__init__.py | 11 +++++++---- beets/autotag/hooks.py | 13 ++++++------- beets/autotag/mb.py | 11 ++++------- beets/library.py | 3 ++- beets/mediafile.py | 15 ++++++++++----- docs/changelog.rst | 3 +++ docs/reference/pathformat.rst | 4 +++- test/rsrc/test.blb | Bin 7168 -> 7168 bytes test/test_mb.py | 11 ++++++++++- test/test_mediafile_basic.py | 10 ++++++++-- 10 files changed, 53 insertions(+), 28 deletions(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index bcd43554e..84f826ed1 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -125,13 +125,16 @@ def apply_metadata(items, album_info): item.artist = track_info.artist else: item.artist = album_info.artist - if track_info.artist_sort_name: - item.artist_sort_name = track_info.artist_sort_name - elif album_info.artist_sort_name: - item.artist_sort_name = album_info.artist_sort_name item.albumartist = album_info.artist item.album = album_info.album item.tracktotal = len(items) + + # Artist sort names. + if track_info.artist_sort: + item.artist_sort = track_info.artist_sort + else: + item.artist_sort = album_info.artist_sort + item.albumartist_sort = album_info.artist_sort # Release date. if album_info.year: diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index a03e79706..4f3ee3752 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -36,14 +36,14 @@ class AlbumInfo(object): - ``day``: release day - ``label``: music label responsible for the release - ``mediums``: the number of discs in this release - - ``artist_sort_name``: name of the release's artists for sorting + - ``artist_sort``: name of the release's artist for sorting The fields up through ``tracks`` are required. The others are optional and may be None. """ def __init__(self, album, album_id, artist, artist_id, tracks, asin=None, albumtype=None, va=False, year=None, month=None, day=None, - label=None, mediums=None, artist_sort_name=None): + label=None, mediums=None, artist_sort=None): self.album = album self.album_id = album_id self.artist = artist @@ -57,8 +57,7 @@ class AlbumInfo(object): self.day = day self.label = label self.mediums = mediums - if artist_sort_name != '': - self.artist_sort_name = artist_sort_name + self.artist_sort = artist_sort class TrackInfo(object): """Describes a canonical track present on a release. Appears as part @@ -71,14 +70,14 @@ class TrackInfo(object): - ``length``: float: duration of the track in seconds - ``medium``: the disc number this track appears on in the album - ``medium_index``: the track's position on the disc - - ``artist_sort_name``: name of the release's artists for sorting + - ``artist_sort``: name of the track artist for sorting Only ``title`` and ``track_id`` are required. The rest of the fields may be None. """ def __init__(self, title, track_id, artist=None, artist_id=None, length=None, medium=None, medium_index=None, - artist_sort_name=None): + artist_sort=None): self.title = title self.track_id = track_id self.artist = artist @@ -86,7 +85,7 @@ class TrackInfo(object): self.length = length self.medium = medium self.medium_index = medium_index - self.artist_sort_name = artist_sort_name + self.artist_sort = artist_sort # Aggregation of sources. diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index 1accb2d0a..af7c2eb8d 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -55,15 +55,15 @@ def track_info(recording, medium=None, medium_index=None): medium=medium, medium_index=medium_index) - # Get the name of the track artist. + # Get the track artist credit. if recording.get('artist-credit-phrase'): info.artist = recording['artist-credit-phrase'] - # Get the ID of the first artist. + # Get the ID and sort name of the first artist. if 'artist-credit' in recording: artist = recording['artist-credit'][0]['artist'] info.artist_id = artist['id'] - info.artist_sort_name = artist['sort-name'] + info.artist_sort = artist['sort-name'] if recording.get('length'): info.length = int(recording['length'])/(1000.0) @@ -86,15 +86,12 @@ def album_info(release): """ # Get artist name using join phrases. artist_parts = [] - artist_sort_parts = [] for el in release['artist-credit']: if isinstance(el, basestring): artist_parts.append(el) else: artist_parts.append(el['artist']['name']) - artist_sort_parts.append(el['artist']['sort-name']) artist_name = ''.join(artist_parts) - artist_sort_name = ', '.join(artist_sort_parts) # Basic info. track_infos = [] @@ -115,7 +112,7 @@ def album_info(release): release['artist-credit'][0]['artist']['id'], track_infos, mediums=len(release['medium-list']), - artist_sort_name = artist_sort_name, + artist_sort=release['artist-credit'][0]['artist']['sort-name'], ) info.va = info.artist_id == VARIOUS_ARTISTS_ID if 'asin' in release: diff --git a/beets/library.py b/beets/library.py index 0b80a440a..c07f5ba10 100644 --- a/beets/library.py +++ b/beets/library.py @@ -42,9 +42,10 @@ ITEM_FIELDS = [ ('title', 'text', True, True), ('artist', 'text', True, True), - ('artist_sort_name', 'text', True, True), + ('artist_sort', 'text', True, True), ('album', 'text', True, True), ('albumartist', 'text', True, True), + ('albumartist_sort', 'text', True, True), ('genre', 'text', True, True), ('composer', 'text', True, True), ('grouping', 'text', True, True), diff --git a/beets/mediafile.py b/beets/mediafile.py index 312f5971a..f114fba10 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -743,11 +743,6 @@ class MediaFile(object): mp3 = StorageStyle('TPE1'), mp4 = StorageStyle("\xa9ART"), etc = StorageStyle('artist'), - ) - artist_sort_name = MediaField( - mp3 = StorageStyle('TSOP'), - mp4 = StorageStyle("soar"), - etc = StorageStyle('ARTISTSORT'), ) album = MediaField( mp3 = StorageStyle('TALB'), @@ -890,6 +885,16 @@ class MediaFile(object): etc = [StorageStyle('label'), StorageStyle('publisher')] # Traktor ) + artist_sort = MediaField( + mp3 = StorageStyle('TSOP'), + mp4 = StorageStyle("soar"), + etc = StorageStyle('ARTISTSORT'), + ) + albumartist_sort = MediaField( + mp3 = StorageStyle('TXXX', id3_desc=u'ALBUMARTISTSORT'), + mp4 = StorageStyle("soaa"), + etc = StorageStyle('ALBUMARTISTSORT'), + ) # Album art. art = ImageField() diff --git a/docs/changelog.rst b/docs/changelog.rst index 0db9df4bb..a2543c1be 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,9 @@ Changelog choices: skip the new music (the previous behavior), keep both, or remove the old music. See the :ref:`guide-duplicates` section in the autotagging guide for details. +* Artist **sort names** are now fetched from MusicBrainz. There are two new data + fields, ``artist_sort`` and ``albumartist_sort``, that contain sortable artist + names like "Beatles, The". Thanks to Paul Provost. * New :doc:`/plugins/rdm`: Randomly select albums and tracks from your library. Thanks to Philippe Mongeau. * The :doc:`/plugins/mbcollection` by Jeffrey Aylesworth was added to the core diff --git a/docs/reference/pathformat.rst b/docs/reference/pathformat.rst index 471c982ad..916ccd0b4 100644 --- a/docs/reference/pathformat.rst +++ b/docs/reference/pathformat.rst @@ -109,14 +109,16 @@ can be found definitively `in the source`_.) Note that plugins can add new (or replace existing) template values (see :ref:`writing-plugins`). .. _in the source: - http://code.google.com/p/beets/source/browse/beets/library.py#36 + https://github.com/sampsyo/beets/blob/master/beets/library.py#L39 Ordinary metadata: * title * artist +* artist_sort * album * albumartist +* albumartist_sort * genre * composer * grouping diff --git a/test/rsrc/test.blb b/test/rsrc/test.blb index f71d6ec2cc0f58befdd2745ad3390c0e5b2546c8..b4e0ddf799a126b3dcc1c298d227d40e31ed3d61 100644 GIT binary patch delta 109 zcmZp$Xt0