14 Commits

Author SHA1 Message Date
Deluan
aba7ed925c fix(artwork): honor disabled per-track art at serve time; use nanosecond mtime provenance
Two serving-correctness fixes from review:
- serveMediaFile served a persisted mf embedded image even after EnableMediaFileCoverArt
  was turned off (the setting isn't in the config fingerprint, so found rows aren't
  reprocessed). Direct mf- URLs now honor the setting at serve time and fall back to
  disc/album art.
- The file-backed staleness check compared whole-second mtimes, so a same-second content
  replacement (two writes in one second, or timestamp-preserving tools) could serve
  different bytes under the old hash + immutable policy. RefMtime is now unix-nanoseconds
  (no schema change; int64 column), detecting sub-second changes where the filesystem
  records them.
2026-07-23 14:08:08 -04:00
Deluan
cfca4a2433 fix(artwork): serve a local playlist ExternalImageURL as a file-backed reference
A local ExternalImageURL was resolved through the external step and labelled
external, so placeBytes copied it into the content-addressed store and dropped its
path/mtime — replacing the file never tripped the staleness check. Classify local
references as file-backed (resolved in place, even on the request path) and keep
store-backed behaviour only for http(s) URLs.
2026-07-23 14:08:08 -04:00
Deluan
313998fd65 feat(artwork): state-backed serving path with provisional read-through 2026-07-23 14:08:08 -04:00
Deluan
5179691811 feat(artwork): resolve media_file embedded art in the worker, invalidate on rescan 2026-07-23 14:07:52 -04:00
Deluan
190c291e61 feat(artwork): worker fetches agent images directly with per-agent rate limits and breakers 2026-07-23 14:07:52 -04:00
Deluan
b172ce4296 refactor(artwork): reuse auth.WithAdminUser and dedupe image cap guards 2026-07-22 18:02:54 -04:00
Deluan
bba0eab3a5 fix(artwork): apply image limits to playlist tile decoding
decodeTile ran image.Decode on every sampled album's resolved bytes
before processItem's maxImageBytes/maxImagePixels guards applied,
letting an oversized or decompression-bomb tile fully decode
unbounded. Enforce both caps inside decodeTile itself.
2026-07-22 17:09:22 -04:00
Deluan
5482784bfc fix(artwork): treat playlist cover URL 404 as definitive miss
The playlist ExternalImageURL step used sources.go's fromURL, which maps any
non-200 to a generic error, so a stale URL returning 404/410 was classified
transient: infinite backoff plus it counted toward the circuit breaker,
blocking valid external work. Add a local fetch in resolve.go that maps
404/410 to model.ErrNotFound (definitive) while keeping other non-200s
transient. sources.go is left untouched.
2026-07-22 15:53:32 -04:00
Deluan
6afcb93a9b fix(artwork): retry higher-priority external art after fallback hit
With CoverArtPriority="external,cover.jpg", a transient external failure
followed by a folder hit dropped the external error: the worker recorded
found and deleted the queue row, so the configured higher-priority external
art was never retried. Carry extError onto the fallback resolution and add
an outcomeFoundStale that persists+serves the art but reschedules via
MarkFailed, giving the external source another chance. When external later
answers definitively-not-found, the hit is not stale and the row is deleted.
2026-07-22 15:53:32 -04:00
Deluan
87095fab08 refactor(artwork): deduplicate purge loop, backfill table, and extGate alias 2026-07-22 15:53:32 -04:00
Deluan
c57496d50d 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.
2026-07-22 15:53:32 -04:00
Deluan
454fd24833 fix(artwork): resolve full playlist source chain
resolvePlaylist only built the generated grid, dropping the uploaded-image, sidecar and ExternalImageURL sources the old reader_playlist.go chain serves. Port the full chain before the grid fallback: uploaded (upload), sidecar (folder), and ExternalImageURL routed through extGate with the same extError semantics as the other external steps. Also rewires the artist external step onto ArtistImageResult.
2026-07-22 15:53:32 -04:00
Deluan
608db503a7 fix(artwork): propagate playlist tile failures and dedupe external step 2026-07-22 15:53:32 -04:00
Deluan
967de74bf7 feat(artwork): add worker-side artwork resolvers 2026-07-22 15:53:32 -04:00