diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index f22ea22748..3dc9624646 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -339,7 +339,7 @@ def get_album_info(self, result): # convenient `.tracklist` property, which will strip out useful artist # information and leave us with skeleton `Artist` objects that will # each make an API call just to get the same data back. - tracks = self.get_tracks(result.data["tracklist"]) + tracks = self.get_tracks(result.data["tracklist"], artist, artist_id) # Extract information for the optional AlbumInfo fields, if possible. va = result.data["artists"][0].get("name", "").lower() == "various" @@ -386,10 +386,6 @@ def get_album_info(self, result): for track in tracks: track.media = media track.medium_total = mediums.count(track.medium) - if not track.artist: # get_track_info often fails to find artist - track.artist = artist - if not track.artist_id: - track.artist_id = artist_id # Discogs does not have track IDs. Invent our own IDs as proposed # in #2336. track.track_id = f"{album_id}-{track.track_alt}" @@ -446,7 +442,7 @@ def format(self, classification): else: return None - def get_tracks(self, tracklist): + def get_tracks(self, tracklist, album_artist, album_artist_id): """Returns a list of TrackInfo objects for a discogs tracklist.""" try: clean_tracklist = self.coalesce_tracks(tracklist) @@ -471,7 +467,9 @@ def get_tracks(self, tracklist): # divisions. divisions += next_divisions del next_divisions[:] - track_info = self.get_track_info(track, index, divisions) + track_info = self.get_track_info( + track, index, divisions, album_artist, album_artist_id + ) track_info.track_alt = track["position"] tracks.append(track_info) else: @@ -638,7 +636,9 @@ def strip_disambiguation(self, text: str) -> str: return text return DISAMBIGUATION_RE.sub("", text) - def get_track_info(self, track, index, divisions): + def get_track_info( + self, track, index, divisions, album_artist, album_artist_id + ): """Returns a TrackInfo object for a discogs track.""" title = track["title"] if self.config["index_tracks"]: @@ -650,8 +650,21 @@ def get_track_info(self, track, index, divisions): artist, artist_id = self.get_artist( track.get("artists", []), join_key="join" ) - artist = self.strip_disambiguation(artist) + # If no artist and artist is returned, set to match album artist + if not artist: + artist = album_artist + artist_id = album_artist_id length = self.get_track_length(track["duration"]) + # Add featured artists + extraartists = track.get("extraartists", []) + featured = [ + artist["name"] + for artist in extraartists + if "Featuring" in artist["role"] + ] + if featured: + artist = f"{artist} feat. {', '.join(featured)}" + artist = self.strip_disambiguation(artist) return TrackInfo( title=title, track_id=track_id, diff --git a/docs/changelog.rst b/docs/changelog.rst index ef7eb9ff80..cbcfe73f0f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,7 @@ New features: converted files. - :doc:`plugins/discogs`: New config option `strip_disambiguation` to toggle stripping discogs numeric disambiguation on artist and label fields. +- :doc:`plugins/discogs` Added support for featured artists. Bug fixes: @@ -27,6 +28,8 @@ Bug fixes: matching. :bug:`5189` - :doc:`plugins/discogs` Fixed inconsistency in stripping disambiguation from artists but not labels. :bug:`5366` +- :doc:`plugins/discogs` Fixed issue with ignoring featured artists in the + extraartists field. - :doc:`plugins/spotify` Fixed an issue where candidate lookup would not find matches due to query escaping (single vs double quotes). diff --git a/test/plugins/test_discogs.py b/test/plugins/test_discogs.py index 92301380ea..3652c0a547 100644 --- a/test/plugins/test_discogs.py +++ b/test/plugins/test_discogs.py @@ -450,6 +450,52 @@ def test_strip_disambiguation_false(self): assert d.artist == "ARTIST NAME (2) & OTHER ARTIST (5)" assert d.tracks[0].artist == "TEST ARTIST (5)" assert d.label == "LABEL NAME (5)" + config["discogs"]["strip_disambiguation"] = True + + +@pytest.mark.parametrize( + "track, expected_artist", + [ + ( + { + "type_": "track", + "title": "track", + "position": "1", + "duration": "5:00", + "artists": [ + {"name": "NEW ARTIST", "tracks": "", "id": 11146}, + {"name": "VOCALIST", "tracks": "", "id": 344, "join": "&"}, + ], + "extraartists": [ + { + "name": "SOLOIST", + "role": "Featuring", + }, + { + "name": "PERFORMER (1)", + "role": "Other Role, Featuring", + }, + { + "name": "RANDOM", + "role": "Written-By", + }, + { + "name": "MUSICIAN", + "role": "Featuring [Uncredited]", + }, + ], + }, + "NEW ARTIST, VOCALIST feat. SOLOIST, PERFORMER, MUSICIAN", + ), + ], +) +@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock()) +def test_parse_featured_artists(track, expected_artist): + """Tests the plugins ability to parse a featured artist. + Initial check with one featured artist, two featured artists, + and three. Ignores artists that are not listed as featured.""" + t = DiscogsPlugin().get_track_info(track, 1, 1, "ARTIST", 2) + assert t.artist == expected_artist @pytest.mark.parametrize(