mirror of
https://github.com/beetbox/beets.git
synced 2026-02-18 21:36:35 +01:00
parse artist credits from MB responses (GC-286)
This commit is contained in:
parent
b04096de25
commit
1387f30295
3 changed files with 65 additions and 21 deletions
|
|
@ -47,6 +47,7 @@ class AlbumInfo(object):
|
|||
- ``albumstatus``: MusicBrainz release status (Official, etc.)
|
||||
- ``media``: delivery mechanism (Vinyl, etc.)
|
||||
- ``albumdisambig``: MusicBrainz release disambiguation comment
|
||||
- ``artist_credit``: Release-specific artist name
|
||||
|
||||
The fields up through ``tracks`` are required. The others are
|
||||
optional and may be None.
|
||||
|
|
@ -56,7 +57,7 @@ class AlbumInfo(object):
|
|||
label=None, mediums=None, artist_sort=None,
|
||||
releasegroup_id=None, catalognum=None, script=None,
|
||||
language=None, country=None, albumstatus=None, media=None,
|
||||
albumdisambig=None):
|
||||
albumdisambig=None, artist_credit=None):
|
||||
self.album = album
|
||||
self.album_id = album_id
|
||||
self.artist = artist
|
||||
|
|
@ -79,6 +80,7 @@ class AlbumInfo(object):
|
|||
self.albumstatus = albumstatus
|
||||
self.media = media
|
||||
self.albumdisambig = albumdisambig
|
||||
self.artist_credit = artist_credit
|
||||
|
||||
class TrackInfo(object):
|
||||
"""Describes a canonical track present on a release. Appears as part
|
||||
|
|
@ -93,13 +95,14 @@ class TrackInfo(object):
|
|||
- ``medium_index``: the track's position on the disc
|
||||
- ``artist_sort``: name of the track artist for sorting
|
||||
- ``disctitle``: name of the individual medium (subtitle)
|
||||
- ``artist_credit``: Recording-specific artist name
|
||||
|
||||
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=None, disctitle=None):
|
||||
artist_sort=None, disctitle=None, artist_credit=None):
|
||||
self.title = title
|
||||
self.track_id = track_id
|
||||
self.artist = artist
|
||||
|
|
@ -109,6 +112,7 @@ class TrackInfo(object):
|
|||
self.medium_index = medium_index
|
||||
self.artist_sort = artist_sort
|
||||
self.disctitle = disctitle
|
||||
self.artist_credit = artist_credit
|
||||
|
||||
|
||||
# Aggregation of sources.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,26 @@ else:
|
|||
_mb_release_search = musicbrainzngs.search_releases
|
||||
_mb_recording_search = musicbrainzngs.search_recordings
|
||||
|
||||
def _flatten_artist_credit(credit):
|
||||
"""Given a list representing an ``artist-credit`` block, flatten the
|
||||
data into a pair of strings: the "canonical" joined artist name and
|
||||
the specific "credit" joined artist name.
|
||||
"""
|
||||
artist_parts = []
|
||||
artist_credit_parts = []
|
||||
for el in credit:
|
||||
if isinstance(el, basestring):
|
||||
artist_parts.append(el)
|
||||
artist_credit_parts.append(el)
|
||||
else:
|
||||
cur_artist_name = el['artist']['name']
|
||||
artist_parts.append(cur_artist_name)
|
||||
if 'name' in el: # Special artist credit.
|
||||
artist_credit_parts.append(el['name'])
|
||||
else:
|
||||
artist_credit_parts.append(cur_artist_name)
|
||||
return ''.join(artist_parts), ''.join(artist_credit_parts)
|
||||
|
||||
def track_info(recording, medium=None, medium_index=None):
|
||||
"""Translates a MusicBrainz recording result dictionary into a beets
|
||||
``TrackInfo`` object. ``medium_index``, if provided, is the track's
|
||||
|
|
@ -67,12 +87,12 @@ def track_info(recording, medium=None, medium_index=None):
|
|||
medium=medium,
|
||||
medium_index=medium_index)
|
||||
|
||||
# Get the track artist credit.
|
||||
if recording.get('artist-credit-phrase'):
|
||||
info.artist = recording['artist-credit-phrase']
|
||||
if recording.get('artist-credit'):
|
||||
# Get the artist names.
|
||||
info.artist, info.artist_credit = \
|
||||
_flatten_artist_credit(recording['artist-credit'])
|
||||
|
||||
# Get the ID and sort name of the first artist.
|
||||
if 'artist-credit' in recording:
|
||||
# Get the ID and sort name of the first artist.
|
||||
artist = recording['artist-credit'][0]['artist']
|
||||
info.artist_id = artist['id']
|
||||
info.artist_sort = artist['sort-name']
|
||||
|
|
@ -97,13 +117,8 @@ def album_info(release):
|
|||
AlbumInfo object containing the interesting data about that release.
|
||||
"""
|
||||
# Get artist name using join phrases.
|
||||
artist_parts = []
|
||||
for el in release['artist-credit']:
|
||||
if isinstance(el, basestring):
|
||||
artist_parts.append(el)
|
||||
else:
|
||||
artist_parts.append(el['artist']['name'])
|
||||
artist_name = ''.join(artist_parts)
|
||||
artist_name, artist_credit_name = \
|
||||
_flatten_artist_credit(release['artist-credit'])
|
||||
|
||||
# Basic info.
|
||||
track_infos = []
|
||||
|
|
@ -127,6 +142,7 @@ def album_info(release):
|
|||
track_infos,
|
||||
mediums=len(release['medium-list']),
|
||||
artist_sort=release['artist-credit'][0]['artist']['sort-name'],
|
||||
artist_credit=artist_credit_name,
|
||||
)
|
||||
info.va = info.artist_id == VARIOUS_ARTISTS_ID
|
||||
info.asin = release.get('asin')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# This file is part of beets.
|
||||
# Copyright 2010, Adrian Sampson.
|
||||
# Copyright 2012, Adrian Sampson.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
|
|
@ -30,11 +30,14 @@ class MBAlbumInfoTest(unittest.TestCase):
|
|||
'disambiguation': 'DISAMBIGUATION',
|
||||
},
|
||||
'artist-credit': [
|
||||
{'artist': {
|
||||
'name': 'ARTIST NAME',
|
||||
'id': 'ARTIST ID',
|
||||
'sort-name': 'ARTIST SORT NAME',
|
||||
}}
|
||||
{
|
||||
'artist': {
|
||||
'name': 'ARTIST NAME',
|
||||
'id': 'ARTIST ID',
|
||||
'sort-name': 'ARTIST SORT NAME',
|
||||
},
|
||||
'name': 'ARTIST CREDIT',
|
||||
}
|
||||
],
|
||||
'date': '3001',
|
||||
'medium-list': [],
|
||||
|
|
@ -64,13 +67,24 @@ class MBAlbumInfoTest(unittest.TestCase):
|
|||
})
|
||||
return release
|
||||
|
||||
def _make_track(self, title, tr_id, duration):
|
||||
def _make_track(self, title, tr_id, duration, artist=False):
|
||||
track = {
|
||||
'title': title,
|
||||
'id': tr_id,
|
||||
}
|
||||
if duration is not None:
|
||||
track['length'] = duration
|
||||
if artist:
|
||||
track['artist-credit'] = [
|
||||
{
|
||||
'artist': {
|
||||
'name': 'TRACK ARTIST NAME',
|
||||
'id': 'TRACK ARTIST ID',
|
||||
'sort-name': 'TRACK ARTIST SORT NAME',
|
||||
},
|
||||
'name': 'TRACK ARTIST CREDIT',
|
||||
}
|
||||
]
|
||||
return track
|
||||
|
||||
def test_parse_release_with_year(self):
|
||||
|
|
@ -81,6 +95,7 @@ class MBAlbumInfoTest(unittest.TestCase):
|
|||
self.assertEqual(d.artist, 'ARTIST NAME')
|
||||
self.assertEqual(d.artist_id, 'ARTIST ID')
|
||||
self.assertEqual(d.year, 1984)
|
||||
self.assertEqual(d.artist_credit, 'ARTIST CREDIT')
|
||||
|
||||
def test_parse_release_type(self):
|
||||
release = self._make_release('1984')
|
||||
|
|
@ -245,6 +260,15 @@ class MBAlbumInfoTest(unittest.TestCase):
|
|||
d = mb.album_info(release)
|
||||
self.assertEqual(d.language, None)
|
||||
|
||||
def test_parse_track_artist(self):
|
||||
tracks = [self._make_track('a', 'b', 1, True)]
|
||||
release = self._make_release(None, tracks=tracks)
|
||||
track = mb.album_info(release).tracks[0]
|
||||
self.assertEqual(track.artist, 'TRACK ARTIST NAME')
|
||||
self.assertEqual(track.artist_id, 'TRACK ARTIST ID')
|
||||
self.assertEqual(track.artist_sort, 'TRACK ARTIST SORT NAME')
|
||||
self.assertEqual(track.artist_credit, 'TRACK ARTIST CREDIT')
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue