From a2bd48c1d235b929b20047d124382f83d9830668 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 5 Oct 2026 19:19:05 -0400 Subject: Backport pull request #18278 from jellyfin/release-12.z Compare local image dates with a one second tolerance Original-merge: 2a59779ae98d96be782078ddf414040d931831ea Merged-by: crobibero Backported-by: Cody Robibero --- MediaBrowser.Controller/Entities/BaseItem.cs | 5 ++-- .../Manager/ItemImageProvider.cs | 5 ++-- .../Manager/ItemImageProviderTests.cs | 31 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 70e7da8932..022f8f0fbf 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2560,8 +2560,9 @@ namespace MediaBrowser.Controller.Entities { var newDateModified = FileSystem.GetLastWriteTimeUtc(newImage); - // If date changed then we need to reset saved image dimensions - if (existing.DateModified != newDateModified && (existing.Width > 0 || existing.Height > 0)) + // If date changed then we need to reset saved image dimensions. Stores such as PostgreSQL keep + // only microseconds, so an exact comparison would treat every unchanged image as modified. + if (Math.Abs((existing.DateModified - newDateModified).TotalSeconds) > 1 && (existing.Width > 0 || existing.Height > 0)) { existing.Width = 0; existing.Height = 0; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index ce5468c5c4..3317e33e1c 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -463,8 +463,9 @@ namespace MediaBrowser.Providers.Manager { var newDateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo); - // If date changed then we need to reset saved image dimensions - if (currentImage.DateModified != newDateModified && (currentImage.Width > 0 || currentImage.Height > 0)) + // If date changed then we need to reset saved image dimensions. Stores such as PostgreSQL keep + // only microseconds, so an exact comparison would treat every unchanged image as modified. + if (Math.Abs((currentImage.DateModified - newDateModified).TotalSeconds) > 1 && (currentImage.Width > 0 || currentImage.Height > 0)) { currentImage.Width = 0; currentImage.Height = 0; diff --git a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs index 459973acba..e234e07fb0 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs @@ -176,6 +176,37 @@ namespace Jellyfin.Providers.Tests.Manager } } + [Theory] + [InlineData(ImageType.Primary, 1)] + [InlineData(ImageType.Backdrop, 2)] + public void MergeImages_StoredTimeTruncatedToMicroseconds_NoChange(ImageType imageType, int imageCount) + { + // Regression test for https://github.com/jellyfin/jellyfin/issues/18274 + var fileTime = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1234567); + var storedTime = fileTime.AddTicks(-(fileTime.Ticks % 10)); + + var fileSystem = new Mock(); + fileSystem.Setup(fs => fs.GetLastWriteTimeUtc(It.IsAny())) + .Returns(fileTime); + BaseItem.FileSystem = fileSystem.Object; + + var item = GetItemWithImages(imageType, imageCount, true); + foreach (var image in item.GetImages(imageType)) + { + image.DateModified = storedTime; + image.Height = 1; + image.Width = 1; + } + + var images = GetImages(imageType, imageCount, true); + + var itemImageProvider = GetItemImageProvider(null, fileSystem); + var changed = itemImageProvider.MergeImages(item, images, new ImageRefreshOptions(Mock.Of())); + + Assert.False(changed); + Assert.All(item.GetImages(imageType), image => Assert.Equal(1, image.Width)); + } + [Theory] [InlineData(ImageType.Primary, 0)] [InlineData(ImageType.Primary, 1)] -- cgit v1.2.3