fix(scanner): treat explicit '[Unknown Artist]' ALBUMARTIST as missing

The old parseArtists function (removed in this branch) substituted
consts.UnknownArtist when albumartist tags were empty, so the
downstream compilation/fallback check matched both cases. The
inlined replacement only checked len(albumNames)==0, narrowing the
condition: files explicitly tagged ALBUMARTIST='[Unknown Artist]'
(emitted by some rippers, and matching what Navidrome itself stores
for untagged files) stopped routing to Various Artists for
compilations.

Restore the original semantics by treating len==1 with the literal
UnknownArtist string as equivalent to no tag.
This commit is contained in:
Deluan 2026-05-24 21:37:01 -03:00
parent 363b93ef25
commit 87cd3f1037
2 changed files with 29 additions and 1 deletions

View File

@ -53,8 +53,16 @@ func (md Metadata) mapParticipants() model.Participants {
albumMbids := md.Strings(model.TagMusicBrainzAlbumArtistID)
albumCredits := md.getArtistValues(model.TagAlbumArtistCredit, model.TagAlbumArtistsCredit)
// Treat both "no albumartist tag" and "albumartist tag literally set to
// the UnknownArtist placeholder" as missing — some rippers emit the
// literal '[Unknown Artist]' string, and the original parseArtists path
// (replaced in this branch) substituted UnknownArtist on its own so the
// downstream check matched either case.
albumArtistMissing := len(albumNames) == 0 ||
(len(albumNames) == 1 && albumNames[0] == consts.UnknownArtist)
var albumArtistParticipants []model.Participant
if len(albumNames) == 0 {
if albumArtistMissing {
if md.Bool(model.TagCompilation) {
albumArtistParticipants = md.buildParticipants(
[]string{consts.VariousArtists}, nil,

View File

@ -460,6 +460,26 @@ var _ = Describe("Participants", func() {
})
})
When("the COMPILATION tag is true and ALBUMARTIST is the UnknownArtist placeholder", func() {
BeforeEach(func() {
// Some rippers emit the literal '[Unknown Artist]' string
// when no album artist is set. The fallback must still
// route to Various Artists for compilations.
mf = toMediaFile(model.RawTags{
"COMPILATION": {"1"},
"ALBUMARTIST": {consts.UnknownArtist},
})
})
It("should substitute Various Artists as the album artist", func() {
participants := mf.Participants
Expect(participants).To(HaveKeyWithValue(model.RoleAlbumArtist, HaveLen(1)))
albumArtist := participants[model.RoleAlbumArtist][0]
Expect(albumArtist.Name).To(Equal("Various Artists"))
Expect(albumArtist.MbzArtistID).To(Equal(consts.VariousArtistsMbzId))
})
})
When("the COMPILATION tag is true and there are ALBUMARTIST tags", func() {
BeforeEach(func() {
mf = toMediaFile(model.RawTags{