parse artist credits from MB responses (GC-286)

This commit is contained in:
Adrian Sampson 2012-05-19 15:42:08 -07:00
parent b04096de25
commit 1387f30295
3 changed files with 65 additions and 21 deletions

View file

@ -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.

View file

@ -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')

View file

@ -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__)