fix(artwork): treat missing local playlist cover as definitive, not transient

A playlist ExternalImageURL pointing at a local file that fails to open was
routed through extError, causing failed/48h-retry loops that burn a rate
limiter token forever instead of falling through to the generated grid.
This commit is contained in:
Deluan 2026-07-22 12:04:17 -04:00
parent 0fbbd01357
commit c57496d50d
2 changed files with 18 additions and 1 deletions

View File

@ -278,7 +278,10 @@ func fromPlaylistExternalSource(ctx context.Context, pl model.Playlist) sourceFu
}
return fromURL(ctx, parsed)
}
return fromLocalFile(imgURL)()
// A missing/unreadable local file is a definitive miss, not a transient
// failure to retry: swallow the open error and fall through to the grid.
r, path, _ := fromLocalFile(imgURL)()
return r, path, nil
}
}

View File

@ -398,6 +398,20 @@ var _ = Describe("resolveItem", func() {
Expect(extGateCalls).To(Equal(1))
})
It("treats a missing local ExternalImageURL as a definitive miss, not extError", func() {
folderRepo.result = nil // no grid tiles, so the local-file miss is what surfaces
plRepo := tests.CreateMockPlaylistRepo()
plRepo.SetData(model.Playlists{{ID: "plm", Name: "Playlist", ExternalImageURL: "/nonexistent/path/cover.jpg"}})
plRepo.TracksRepo = &tests.MockPlaylistTrackRepo{AlbumIDs: []string{"t1"}}
ds.MockedPlaylist = plRepo
res, err := resolveItem(ctx, ds, prov, ffm, model.ArtworkQueueItem{ItemKind: "pl", ItemID: "plm"}, nil)
Expect(err).ToNot(HaveOccurred())
Expect(res.reader).To(BeNil())
Expect(res.extError).To(BeFalse())
})
It("yields an empty resolution when no album has art", func() {
ds.MockedAlbum.(*tests.MockAlbumRepo).SetData(model.Albums{
{ID: "empty1", Name: "Empty"},