From 0e74cf0ab1a31c79e5950d6486d8dd50a21a18de Mon Sep 17 00:00:00 2001 From: Deluan Date: Fri, 17 Jul 2026 13:16:07 -0400 Subject: [PATCH] fix(artwork): only force blurhash recompute on original-size cache misses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resized cache keys vary per requested size, so a first request for a new thumbnail size (or an evicted resized entry) forced a recompute with an unchanged source — wasted work, and a transient failure during it could clear a valid stored hash. Resized readers re-fetch the original through Get, so the original-size call still carries the real change signal. --- core/artwork/artwork.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/artwork/artwork.go b/core/artwork/artwork.go index 9e909068f..cd0d958e4 100644 --- a/core/artwork/artwork.go +++ b/core/artwork/artwork.go @@ -83,9 +83,11 @@ func (a *artwork) Get(ctx context.Context, artID model.ArtworkID, size int, squa return nil, time.Time{}, err } if a.blurHashes != nil { - // A miss on an operational cache means a new/changed image even when no entity row moved; - // while warming up or disabled every serve misses, so only the LastUpdated signal applies. - force := !r.Cached && a.cache.Available(ctx) + // An original-size miss on an operational cache means a new/changed image even when no + // entity row moved. Resized misses don't qualify (their keys vary per size, and their + // readers re-fetch the original through Get, carrying the real signal); nor does cache + // warmup/disabled, where every serve misses — there the LastUpdated signal applies. + force := size == 0 && !square && !r.Cached && a.cache.Available(ctx) a.blurHashes.Enqueue(artID, artReader.LastUpdated(), force) } return r, artReader.LastUpdated(), nil