def split_artists(
- org_artists: str | tuple[str, ...], allow_ampersand: bool = False
+ org_artists: str | tuple[str, ...], allow_extra_splitters: bool = False
) -> tuple[str, ...]:
"""Parse all artists from a string."""
final_artists: list[str] = []
# when not using the multi artist tag, the artist string may contain
# multiple artists in freeform, even featuring artists may be included in this
# string. Try to parse the featuring artists and separate them.
- splitters = ("featuring", " feat. ", " feat ", "feat.")
- if allow_ampersand:
- splitters = (*splitters, " & ")
+ splitters = [
+ " featuring ",
+ " feat. ",
+ " feat ",
+ " duet with ",
+ " with ",
+ " ft. ",
+ " vs. ",
+ ]
+ splitters += [x.title() for x in splitters]
+ if allow_extra_splitters:
+ splitters += [" & ", ", ", " + "]
artists = split_items(org_artists, allow_unsafe_splitters=False)
for item in artists:
for splitter in splitters:
if tag := self.tags.get("artist"):
if TAG_SPLITTER in tag:
return split_items(tag)
+ if len(self.musicbrainz_artistids) > 1:
+ # special case: artist noted as 2 artists with ampersand or other splitter
+ # but with 2 mb ids so they should be treated as 2 artists
+ # example: John Travolta & Olivia Newton John on the Grease album
+ return split_artists(tag, allow_extra_splitters=True)
return split_artists(tag)
# fallback to parsing from filename
title = self.filename.rsplit(os.sep, 1)[-1].split(".")[0]
if TAG_SPLITTER in tag:
return split_items(tag)
if len(self.musicbrainz_albumartistids) > 1:
- # special case: album artist noted as 2 artists with ampersand
+ # special case: album artist noted as 2 artists with ampersand or other splitter
# but with 2 mb ids so they should be treated as 2 artists
# example: John Travolta & Olivia Newton John on the Grease album
- return split_artists(tag, allow_ampersand=True)
+ return split_artists(tag, allow_extra_splitters=True)
return split_artists(tag)
return ()