From 96a23a2c1063148357e8d72ab025b01a4c973a17 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 6 Sep 2025 11:48:00 -0500 Subject: [PATCH] Fixed: Improve New Album Monitoring - Improve Debugging - Add Tests Towards #3778 --- .../MonitorNewAlbumServiceFixture.cs | 146 ++++++++++++++++++ .../Music/Services/MonitorNewAlbumService.cs | 36 ++++- 2 files changed, 180 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs b/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs index e0cee525b..4dd23a8a3 100644 --- a/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs @@ -21,14 +21,17 @@ public void Setup() .All() .With(e => e.Monitored = true) .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-7)) + .With(e => e.Title = "Test Album") // Future .TheFirst(1) .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(7)) + .With(e => e.Title = "Future Album") // Future/TBA .TheNext(1) .With(e => e.ReleaseDate = null) + .With(e => e.Title = "TBA Album") .Build() .ToList(); } @@ -61,5 +64,148 @@ public void should_only_monitor_new_with_new() Subject.ShouldMonitorNewAlbum(album, _albums, NewItemMonitorTypes.New).Should().BeFalse(); } } + + [Test] + public void should_not_monitor_album_with_null_release_date() + { + var albumWithNullDate = Builder.CreateNew() + .With(e => e.ReleaseDate = null) + .With(e => e.Title = "No Date Album") + .Build(); + + var existingAlbums = Builder.CreateListOfSize(2) + .All() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-30)) + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(albumWithNullDate, existingAlbums, NewItemMonitorTypes.New) + .Should().BeFalse(); + } + + [Test] + public void should_monitor_album_when_no_existing_albums_have_dates() + { + var newAlbumWithDate = Builder.CreateNew() + .With(e => e.ReleaseDate = DateTime.UtcNow) + .With(e => e.Title = "New Album With Date") + .Build(); + + var existingAlbumsWithoutDates = Builder.CreateListOfSize(3) + .All() + .With(e => e.ReleaseDate = null) + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(newAlbumWithDate, existingAlbumsWithoutDates, NewItemMonitorTypes.New) + .Should().BeTrue(); + } + + [Test] + public void should_monitor_album_newer_than_existing_albums() + { + var newerAlbum = Builder.CreateNew() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(1)) + .With(e => e.Title = "Newer Album") + .Build(); + + var existingAlbums = Builder.CreateListOfSize(3) + .All() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-30)) + .TheFirst(1) + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-1)) // Most recent existing + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(newerAlbum, existingAlbums, NewItemMonitorTypes.New) + .Should().BeTrue(); + } + + [Test] + public void should_not_monitor_album_older_than_existing_albums() + { + var olderAlbum = Builder.CreateNew() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-10)) + .With(e => e.Title = "Older Album") + .Build(); + + var existingAlbums = Builder.CreateListOfSize(3) + .All() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-30)) + .TheFirst(1) + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-1)) // Most recent existing + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(olderAlbum, existingAlbums, NewItemMonitorTypes.New) + .Should().BeFalse(); + } + + [Test] + public void should_monitor_album_with_same_date_as_existing_album() + { + var sameDate = DateTime.UtcNow.AddDays(-5); + var albumWithSameDate = Builder.CreateNew() + .With(e => e.ReleaseDate = sameDate) + .With(e => e.Title = "Same Date Album") + .Build(); + + var existingAlbums = Builder.CreateListOfSize(3) + .All() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-30)) + .TheFirst(1) + .With(e => e.ReleaseDate = sameDate) // Same date as new album + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(albumWithSameDate, existingAlbums, NewItemMonitorTypes.New) + .Should().BeTrue(); + } + + [Test] + public void should_ignore_existing_albums_with_null_dates_when_finding_newest() + { + var newAlbum = Builder.CreateNew() + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(1)) + .With(e => e.Title = "New Album") + .Build(); + + var existingAlbums = Builder.CreateListOfSize(4) + .All() + .With(e => e.ReleaseDate = null) // All null dates + .TheFirst(1) + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-5)) // Only one with actual date + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(newAlbum, existingAlbums, NewItemMonitorTypes.New) + .Should().BeTrue(); + } + + [Test] + public void should_throw_for_unknown_monitor_type() + { + var album = _albums.First(); + Assert.Throws(() => + Subject.ShouldMonitorNewAlbum(album, _albums, (NewItemMonitorTypes)999)); + } + + [Test] + public void should_monitor_album_with_null_date_when_all_existing_albums_also_have_null_dates() + { + var albumWithNullDate = Builder.CreateNew() + .With(e => e.ReleaseDate = null) + .With(e => e.Title = "No Date Album") + .Build(); + + var existingAlbumsWithoutDates = Builder.CreateListOfSize(3) + .All() + .With(e => e.ReleaseDate = null) + .Build() + .ToList(); + + Subject.ShouldMonitorNewAlbum(albumWithNullDate, existingAlbumsWithoutDates, NewItemMonitorTypes.New) + .Should().BeTrue(); + } } } diff --git a/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs b/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs index 3d92b0634..06b5a8031 100644 --- a/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs +++ b/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs @@ -23,19 +23,51 @@ public bool ShouldMonitorNewAlbum(Album addedAlbum, List existingAlbums, { if (monitorNewItems == NewItemMonitorTypes.None) { + _logger.Trace("Album '{0}' will not be monitored: Monitor setting is set to 'None'", addedAlbum.Title); return false; } if (monitorNewItems == NewItemMonitorTypes.All) { + _logger.Trace("Album '{0}' will be monitored: Monitor setting is set to 'All'", addedAlbum.Title); return true; } if (monitorNewItems == NewItemMonitorTypes.New) { - var newest = existingAlbums.MaxBy(x => x.ReleaseDate ?? DateTime.MinValue)?.ReleaseDate ?? DateTime.MinValue; + var newestExistingDate = existingAlbums + .Where(x => x.ReleaseDate.HasValue) + .MaxBy(x => x.ReleaseDate.Value)?.ReleaseDate; - return (addedAlbum.ReleaseDate ?? DateTime.MinValue) >= newest; + if (!addedAlbum.ReleaseDate.HasValue) + { + if (!newestExistingDate.HasValue) + { + _logger.Debug("Album '{0}' will be monitored: Both new and existing albums have no release dates", addedAlbum.Title); + return true; + } + else + { + _logger.Debug("Album '{0}' will not be monitored: Albums without release dates are skipped when existing albums have dates", addedAlbum.Title); + return false; + } + } + + if (!newestExistingDate.HasValue) + { + _logger.Debug("Album '{0}' will be monitored: No existing albums have release dates, so this is considered the first 'new' release", addedAlbum.Title); + return true; + } + + var shouldMonitor = addedAlbum.ReleaseDate.Value >= newestExistingDate.Value; + _logger.Trace("Album '{0}' ({1}) {2} be monitored: Release date is {3} the most recent existing album ({4})", + addedAlbum.Title, + addedAlbum.ReleaseDate.Value.ToString("yyyy-MM-dd"), + shouldMonitor ? "will" : "will not", + shouldMonitor ? "on or after" : "before", + newestExistingDate.Value.ToString("yyyy-MM-dd")); + + return shouldMonitor; } throw new NotImplementedException($"Unknown new item monitor type {monitorNewItems}");