fix(artwork): keep an eligible track's cover requestable when its album is absent

An embedded-eligible track with no resolved item_artwork row inherited the album's
ImageAbsent, so when the album resolved absent (e.g. CoverArtPriority without
'embedded') the track's coverArt was omitted permanently — the client never
requested it, so the lazy mediafile path never resolved it — even though the
serving path would extract and serve the track's own embedded art. Hydration now
never copies the album's absence onto an eligible-but-unresolved track.
This commit is contained in:
Deluan 2026-07-23 00:26:47 -04:00
parent ca4220b029
commit 0781c4a9b2
2 changed files with 39 additions and 3 deletions

View File

@ -233,6 +233,32 @@ var _ = Describe("Artwork hydration", func() {
Expect(byID["2002"].ImageAbsent).To(BeFalse())
})
It("keeps an eligible file optimistic when its own art is unresolved, even if the album is absent", func() {
// 1004 is eligible (has embedded cover) with no mf state row yet; its album (103) is absent.
setCover("1004", true)
DeferCleanup(func() { setCover("1004", false) })
putInfo("al", "103", "") // album known-absent
byID := getByID()
// The track's own embedded art is still unresolved, so it must NOT inherit the album's
// absence: coverArt stays requestable so serving can extract the embedded art.
Expect(byID["1004"].ImageAbsent).To(BeFalse())
Expect(byID["1004"].ImageHash).To(BeEmpty())
// A non-eligible sibling on the same absent album still inherits the absence.
Expect(byID["1003"].ImageAbsent).To(BeTrue())
})
It("uses the album hash for an eligible file whose own art is unresolved but album is found", func() {
setCover("1004", true)
DeferCleanup(func() { setCover("1004", false) })
putInfo("al", "103", "alh103found11111")
byID := getByID()
Expect(byID["1004"].ImageAbsent).To(BeFalse())
Expect(byID["1004"].ImageHash).To(Equal("alh103found11111"))
})
It("uses album info for an eligible file when EnableMediaFileCoverArt is off", func() {
conf.Server.EnableMediaFileCoverArt = false
setCover("1001", true)

View File

@ -241,11 +241,21 @@ func (r *mediaFileRepository) hydrateArtwork(mfs model.MediaFiles) {
mfInfos := hydrateItemImages(r.ctx, r.db, model.KindMediaFileArtwork.Prefix(), eligibleIDs)
for i := range mfs {
if mfs[i].HasCoverArt && conf.Server.EnableMediaFileCoverArt {
if info, ok := mfInfos[mfs[i].ID]; ok && !info.Absent() {
mfs[i].ImageHash = info.Hash
mfs[i].ImageAbsent = false
if info, ok := mfInfos[mfs[i].ID]; ok {
if !info.Absent() {
mfs[i].ImageHash = info.Hash
continue
}
// Own art resolved absent → serving delegates to the album, so mirror that.
applyItemImage(albumInfos, mfs[i].AlbumID, &mfs[i].ItemImage)
continue
}
// Eligible but unresolved: take a found album hash for caching, but never the
// album's absence — serving still extracts the track's own embedded art on request.
if albumInfo, ok := albumInfos[mfs[i].AlbumID]; ok && !albumInfo.Absent() {
mfs[i].ImageHash = albumInfo.Hash
}
continue
}
applyItemImage(albumInfos, mfs[i].AlbumID, &mfs[i].ItemImage)
}