navidrome/core/artwork/image_cache.go
Deluan f498dfde7d fix(album): make cover cache keys immune to future file mtimes
All cover cache keys used max(updated_at, cover_art_updated_at), so an album
whose updated_at is in the future (bad file mtimes) would mask a cover edit
entirely — id unchanged, reader cache key unchanged, UI URL unchanged — and
keep serving the old image.

Treat the keys as discriminators instead of dates: the album artwork id adds
the two timestamps, the reader cache keys (album/disc/mediafile) carry the
cover stamp as a separate component, and the UI cache-buster joins both
timestamps instead of picking the newest.
2026-07-17 23:03:20 -04:00

53 lines
1.1 KiB
Go

package artwork
import (
"context"
"fmt"
"io"
"time"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/utils/cache"
"github.com/navidrome/navidrome/utils/singleton"
)
type cacheKey struct {
artID model.ArtworkID
lastUpdate time.Time
}
func (k *cacheKey) Key() string {
return fmt.Sprintf(
"%s-%s.%d",
k.artID.Kind,
k.artID.ID,
k.lastUpdate.UnixMilli(),
)
}
// coverStamp renders the album's manual-cover timestamp for cache keys (0 when unset).
func coverStamp(t *time.Time) int64 {
if t == nil {
return 0
}
return t.UnixMilli()
}
type imageCache struct {
cache.FileCache
}
func GetImageCache() cache.FileCache {
return singleton.GetInstance(func() *imageCache {
return &imageCache{
FileCache: cache.NewFileCache("Image", conf.Server.ImageCacheSize, consts.ImageCacheDir, consts.DefaultImageCacheMaxItems,
func(ctx context.Context, arg cache.Item) (io.Reader, error) {
r, _, err := arg.(artworkReader).Reader(ctx)
return r, err
}),
}
})
}