mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
fix(artwork): persist the image freshness signal to stop per-serve recomputes
When a cover file's mtime is newer than the entity row (common), persisting the row version made the freshness check fail on every serve, re-encoding and re-writing the same hash each time. The snapshot now stores the newest signal (row version or image mtime), and both freshness checks accept a snapshot at-or-after the row version.
This commit is contained in:
parent
b040345fb0
commit
43500c0ffe
@ -148,7 +148,9 @@ func (u *blurHashUpdater) process(ctx context.Context, artID model.ArtworkID, re
|
||||
sig = req.imageUpdatedAt
|
||||
}
|
||||
if !req.force {
|
||||
if stored != "" && storedAt != nil && storedAt.Equal(version) && !sig.After(*storedAt) {
|
||||
// Current when computed from this row version or later; the snapshot may exceed the row
|
||||
// version because file mtimes (which don't move rows) are folded into it on persist.
|
||||
if stored != "" && storedAt != nil && !storedAt.Before(version) && !sig.After(*storedAt) {
|
||||
return
|
||||
}
|
||||
if last, ok := u.lastNoResult(artID); ok && !sig.After(last) {
|
||||
@ -168,7 +170,7 @@ func (u *blurHashUpdater) process(ctx context.Context, artID model.ArtworkID, re
|
||||
u.setNoResult(artID, sig)
|
||||
return
|
||||
}
|
||||
if err := u.persist(ctx, artID, hash, version); err != nil {
|
||||
if err := u.persist(ctx, artID, hash, sig); err != nil {
|
||||
log.Warn(ctx, "BlurHash: error persisting", "artID", artID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -29,8 +29,9 @@ var _ = Describe("BlurHash", func() {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
g.Expect(len(updated.BlurHash)).To(BeNumerically(">", 6))
|
||||
g.Expect(updated.BlurHashUpdatedAt).ToNot(BeNil())
|
||||
// The snapshot must match the artwork version, or the DTO layer would treat it as stale.
|
||||
g.Expect(updated.BlurHashUpdatedAt.Equal(updated.ArtworkUpdatedAt())).To(BeTrue())
|
||||
// The snapshot must not be before the artwork version, or the DTO would treat it as
|
||||
// stale (it may exceed it: image file mtimes are folded in).
|
||||
g.Expect(updated.BlurHashUpdatedAt.Before(updated.ArtworkUpdatedAt())).To(BeFalse())
|
||||
}, "10s", "100ms").Should(Succeed())
|
||||
})
|
||||
|
||||
|
||||
@ -40,10 +40,11 @@ func blurHash(seed string) string {
|
||||
}
|
||||
|
||||
// primaryBlurHash returns the stored blurhash when it was computed from the entity's current
|
||||
// artwork version; otherwise a fake seeded by id+version, so the value still rotates on any
|
||||
// artwork change (Finamp keys its cover caches by this value; tags never reach its image URLs).
|
||||
// artwork version or later (the snapshot folds in image file mtimes, which can exceed row
|
||||
// timestamps); otherwise a fake seeded by id+version, so the value still rotates on any artwork
|
||||
// change (Finamp keys its cover caches by this value; tags never reach its image URLs).
|
||||
func primaryBlurHash(stored string, storedAt *time.Time, id string, version time.Time) string {
|
||||
if stored != "" && storedAt != nil && storedAt.Equal(version) {
|
||||
if stored != "" && storedAt != nil && !storedAt.Before(version) {
|
||||
return stored
|
||||
}
|
||||
return blurHash(fmt.Sprintf("%s-%x", id, version.UnixMilli()))
|
||||
|
||||
@ -34,6 +34,11 @@ var _ = Describe("primaryBlurHash", func() {
|
||||
Expect(primaryBlurHash("LEHV6nWB2yk8", &version, "id-1", version)).To(Equal("LEHV6nWB2yk8"))
|
||||
})
|
||||
|
||||
It("returns the stored hash when the snapshot is newer than the version (image mtime)", func() {
|
||||
newer := version.Add(time.Hour)
|
||||
Expect(primaryBlurHash("LEHV6nWB2yk8", &newer, "id-1", version)).To(Equal("LEHV6nWB2yk8"))
|
||||
})
|
||||
|
||||
It("falls back to a fake when there is no stored hash", func() {
|
||||
h := primaryBlurHash("", nil, "id-1", version)
|
||||
Expect(h).To(HaveLen(6))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user