From c57496d50d581d5c8e591f5a8d3629516c999f30 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 22 Jul 2026 12:04:17 -0400 Subject: [PATCH] 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. --- core/artwork/resolve.go | 5 ++++- core/artwork/resolve_test.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/artwork/resolve.go b/core/artwork/resolve.go index 272234c9d..af151ef4a 100644 --- a/core/artwork/resolve.go +++ b/core/artwork/resolve.go @@ -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 } } diff --git a/core/artwork/resolve_test.go b/core/artwork/resolve_test.go index cab757dbb..a80d02ca9 100644 --- a/core/artwork/resolve_test.go +++ b/core/artwork/resolve_test.go @@ -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"},