From f9b07170863aa7fd7b9533801e5e79b4401bf558 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 26 Jul 2026 21:51:47 -0400 Subject: [PATCH] refactor(artwork): move resizedItem next to the interface it implements resizedItem is the only implementation of artworkReader, which is declared in image_cache.go, and it is used by the worker's precache as well as the serving path -- so worker.go was reaching into serving.go for a cache type. representationTag stays in serving.go, where the HTTP validator belongs. Pure move. --- core/artwork/image_cache.go | 39 +++++++++++++++++++++++++++++++++++++ core/artwork/serving.go | 37 ----------------------------------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/core/artwork/image_cache.go b/core/artwork/image_cache.go index 3d58e691b..39938a755 100644 --- a/core/artwork/image_cache.go +++ b/core/artwork/image_cache.go @@ -1,11 +1,13 @@ package artwork import ( + "bytes" "context" "io" "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" + "github.com/navidrome/navidrome/core/ffmpeg" "github.com/navidrome/navidrome/utils/cache" "github.com/navidrome/navidrome/utils/singleton" ) @@ -31,3 +33,40 @@ func GetImageCache() cache.FileCache { } }) } + +// resizedItem is an artworkReader that resizes bytes opened by open() and caches the +// result under a hash-derived key. +type resizedItem struct { + hash string + size int + square bool + ffmpeg ffmpeg.FFmpeg + open func() (io.ReadCloser, error) +} + +// Key is the ETag namespaced for the cache, so the validator a client holds and the entry it +// validates can never drift apart. +func (r *resizedItem) Key() string { + return "h-" + representationTag(r.hash, r.size, r.square) +} + +func (r *resizedItem) Reader(ctx context.Context) (io.ReadCloser, error) { + orig, err := r.open() + if err != nil { + return nil, err + } + defer orig.Close() + data, err := readCapped(orig) + if err != nil { + return nil, err + } + resized, _, err := resizeImageData(ctx, r.ffmpeg, data, r.size, r.square) + if err != nil || resized == nil { + // Resize failed or image already within bounds: serve the original bytes. + return io.NopCloser(bytes.NewReader(data)), nil + } + if rc, ok := resized.(io.ReadCloser); ok { + return rc, nil + } + return io.NopCloser(resized), nil +} diff --git a/core/artwork/serving.go b/core/artwork/serving.go index c3eb926d8..a63ac77b3 100644 --- a/core/artwork/serving.go +++ b/core/artwork/serving.go @@ -385,40 +385,3 @@ func unixMtime(mtime int64) time.Time { } return time.Unix(0, mtime) // RefMtime is unix-nanoseconds } - -// resizedItem is an artworkReader that resizes bytes opened by open() and caches the -// result under a hash-derived key. -type resizedItem struct { - hash string - size int - square bool - ffmpeg ffmpeg.FFmpeg - open func() (io.ReadCloser, error) -} - -// Key is the ETag namespaced for the cache, so the validator a client holds and the entry it -// validates can never drift apart. -func (r *resizedItem) Key() string { - return "h-" + representationTag(r.hash, r.size, r.square) -} - -func (r *resizedItem) Reader(ctx context.Context) (io.ReadCloser, error) { - orig, err := r.open() - if err != nil { - return nil, err - } - defer orig.Close() - data, err := readCapped(orig) - if err != nil { - return nil, err - } - resized, _, err := resizeImageData(ctx, r.ffmpeg, data, r.size, r.square) - if err != nil || resized == nil { - // Resize failed or image already within bounds: serve the original bytes. - return io.NopCloser(bytes.NewReader(data)), nil - } - if rc, ok := resized.(io.ReadCloser); ok { - return rc, nil - } - return io.NopCloser(resized), nil -}