From 8e36c823fcffb85bed670396ef18c49ec49ddf2d Mon Sep 17 00:00:00 2001 From: Mika Cohen Date: Thu, 23 Apr 2026 12:16:32 -0600 Subject: [PATCH] Only reuse healthy waiting tracked downloads --- .../TrackedDownloadServiceFixture.cs | 59 +++++++++++++++++++ .../TrackedDownloadService.cs | 9 ++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs index fa64daf05b..0ab88375a4 100644 --- a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs @@ -176,6 +176,65 @@ public void should_reprocess_when_waiting_download_identity_changes() .Verify(s => s.Map(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Exactly(2)); } + [Test] + public void should_reprocess_when_waiting_download_has_warning_status() + { + GivenTrackedDownloadCanBeMapped(); + + var client = CreateDownloadClient(); + var item = CreateDownloadItem(DownloadItemStatus.Queued); + var updatedItem = CreateDownloadItem(DownloadItemStatus.Queued); + updatedItem.RemainingSize = 250; + + var trackedDownload = Subject.TrackDownload(client, item); + trackedDownload.Warn("Temporary warning"); + + var refreshedTrackedDownload = Subject.TrackDownload(client, updatedItem); + + refreshedTrackedDownload.Should().NotBeSameAs(trackedDownload); + + Mocker.GetMock() + .Verify(s => s.FindByDownloadId(It.IsAny()), Times.Exactly(2)); + + Mocker.GetMock() + .Verify(s => s.Map(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Exactly(2)); + } + + [Test] + public void should_reprocess_when_waiting_download_is_not_mapped() + { + Mocker.GetMock() + .Setup(s => s.FindByDownloadId(It.IsAny())) + .Returns(new List()); + + Mocker.GetMock() + .Setup(s => s.Map(It.IsAny(), It.IsAny(), It.IsAny(), null)) + .Returns(new RemoteMovie + { + ParsedMovieInfo = new ParsedMovieInfo + { + MovieTitles = new List { "A Movie" }, + Year = 1998 + } + }); + + var client = CreateDownloadClient(); + var item = CreateDownloadItem(DownloadItemStatus.Queued); + var updatedItem = CreateDownloadItem(DownloadItemStatus.Queued); + updatedItem.RemainingSize = 250; + + var trackedDownload = Subject.TrackDownload(client, item); + var refreshedTrackedDownload = Subject.TrackDownload(client, updatedItem); + + refreshedTrackedDownload.Should().NotBeSameAs(trackedDownload); + + Mocker.GetMock() + .Verify(s => s.FindByDownloadId(It.IsAny()), Times.Exactly(2)); + + Mocker.GetMock() + .Verify(s => s.Map(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Exactly(2)); + } + [Test] public void should_track_downloads_using_the_source_title_if_it_cannot_be_found_using_the_download_title() { diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs index b009066c00..51d9754724 100644 --- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs +++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs @@ -229,7 +229,8 @@ private static bool CanReuseTrackedDownload(TrackedDownload existingItem, Downlo } return IsStableWaitingDownload(downloadItem) && - HasSameDownloadIdentity(existingItem.DownloadItem, downloadItem); + HasSameDownloadIdentity(existingItem.DownloadItem, downloadItem) && + HasHealthyWaitingCache(existingItem); } private static bool IsStableWaitingDownload(DownloadClientItem downloadItem) @@ -238,6 +239,12 @@ private static bool IsStableWaitingDownload(DownloadClientItem downloadItem) downloadItem.Status == DownloadItemStatus.Paused; } + private static bool HasHealthyWaitingCache(TrackedDownload existingItem) + { + return existingItem.Status == TrackedDownloadStatus.Ok && + existingItem.RemoteMovie?.Movie != null; + } + private static bool HasSameDownloadIdentity(DownloadClientItem existingItem, DownloadClientItem downloadItem) { return existingItem.DownloadId == downloadItem.DownloadId &&