From 36ed880e61ad45d89f1c5f3e04c18bebc3b1bf2c Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Fri, 7 Mar 2025 03:16:37 +0000 Subject: [PATCH] fix(scanner): always refresh folder image time when adding first image (#3764) * fix(scanner): Always refresh folder image time when adding first image Currently, the `images_updated_at` field is only set to the image modification time. However, in cases where a new image is added _and_ said image is older than the folder mod time, the field is not updated properly. In this the case where `images_updated_at` is null (no images were ever added) and a new images is found, use the folder modification time instead of image modification time. **Note**, this doesn't handle cases such as replacing a newer image with an older one. * simplify image update at * we don't want to set imagesUpdatedAt when there's no images in the folder Signed-off-by: Deluan --------- Signed-off-by: Deluan Co-authored-by: Deluan --- scanner/walk_dir_tree.go | 5 ++--- utils/time.go | 13 +++++++++++++ utils/time_test.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 utils/time.go create mode 100644 utils/time_test.go diff --git a/scanner/walk_dir_tree.go b/scanner/walk_dir_tree.go index 29c95fa1c..1b7bb36f1 100644 --- a/scanner/walk_dir_tree.go +++ b/scanner/walk_dir_tree.go @@ -15,6 +15,7 @@ import ( "github.com/navidrome/navidrome/core" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/utils" "github.com/navidrome/navidrome/utils/chrono" ignore "github.com/sabhiram/go-gitignore" ) @@ -214,9 +215,7 @@ func loadDir(ctx context.Context, job *scanJob, dirPath string, ignorePatterns [ folder.numPlaylists++ case model.IsImageFile(entry.Name()): folder.imageFiles[entry.Name()] = entry - if fileInfo.ModTime().After(folder.imagesUpdatedAt) { - folder.imagesUpdatedAt = fileInfo.ModTime() - } + folder.imagesUpdatedAt = utils.TimeNewest(folder.imagesUpdatedAt, fileInfo.ModTime(), folder.modTime) } } } diff --git a/utils/time.go b/utils/time.go new file mode 100644 index 000000000..c1e949589 --- /dev/null +++ b/utils/time.go @@ -0,0 +1,13 @@ +package utils + +import "time" + +func TimeNewest(times ...time.Time) time.Time { + newest := time.Time{} + for _, t := range times { + if t.After(newest) { + newest = t + } + } + return newest +} diff --git a/utils/time_test.go b/utils/time_test.go new file mode 100644 index 000000000..f89f0d2be --- /dev/null +++ b/utils/time_test.go @@ -0,0 +1,28 @@ +package utils_test + +import ( + "time" + + "github.com/navidrome/navidrome/utils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("TimeNewest", func() { + It("returns zero time when no times are provided", func() { + Expect(utils.TimeNewest()).To(Equal(time.Time{})) + }) + + It("returns the time when only one time is provided", func() { + t1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + Expect(utils.TimeNewest(t1)).To(Equal(t1)) + }) + + It("returns the newest time when multiple times are provided", func() { + t1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + t2 := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC) + t3 := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) + + Expect(utils.TimeNewest(t1, t2, t3)).To(Equal(t2)) + }) +})