diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs index 365711e6f..3412219c5 100644 --- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs @@ -34,11 +34,7 @@ namespace NzbDrone.Core.Test.Download .With(h => h.Title = "Drone.S01E01.HDTV") .Build(); - var remoteEpisode = new RemoteEpisode - { - Series = new Series(), - Episodes = new List { new Episode { Id = 1 } } - }; + var remoteEpisode = BuildRemoteEpisode(); _trackedDownload = Builder.CreateNew() .With(c => c.State = TrackedDownloadStage.Downloading) @@ -65,6 +61,16 @@ namespace NzbDrone.Core.Test.Download } + private RemoteEpisode BuildRemoteEpisode() + { + return new RemoteEpisode + { + Series = new Series(), + Episodes = new List { new Episode { Id = 1 } } + }; + } + + private void GivenNoGrabbedHistory() { Mocker.GetMock() @@ -82,6 +88,24 @@ namespace NzbDrone.Core.Test.Download }); } + + private void GivenABadlyNamedDownload() + { + _trackedDownload.DownloadItem.DownloadId = "1234"; + _trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download + Mocker.GetMock() + .Setup(s => s.MostRecentForDownloadId(It.Is(i => i == "1234"))) + .Returns(new History.History() { SourceTitle = "Droned S01E01" }); + + Mocker.GetMock() + .Setup(s => s.GetSeries(It.IsAny())) + .Returns((Series)null); + + Mocker.GetMock() + .Setup(s => s.GetSeries("Droned S01E01")) + .Returns(BuildRemoteEpisode().Series); + } + private void GivenSeriesMatch() { Mocker.GetMock() @@ -284,6 +308,47 @@ namespace NzbDrone.Core.Test.Download AssertNoCompletedDownload(); } + [Test] + public void should_mark_as_imported_if_the_download_can_be_tracked_using_the_source_seriesid() + { + GivenABadlyNamedDownload(); + + Mocker.GetMock() + .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(new List + { + new ImportResult(new ImportDecision(new LocalEpisode {Path = @"C:\TestPath\Droned.S01E01.mkv"})) + }); + + Mocker.GetMock() + .Setup(v => v.GetSeries(It.IsAny())) + .Returns(BuildRemoteEpisode().Series); + + Subject.Process(_trackedDownload); + + AssertCompletedDownload(); + } + + [Test] + public void should_not_mark_as_imported_if_the_download_cannot_be_tracked_using_the_source_title_as_it_was_initiated_externally() + { + GivenABadlyNamedDownload(); + + Mocker.GetMock() + .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(new List + { + new ImportResult(new ImportDecision(new LocalEpisode {Path = @"C:\TestPath\Droned.S01E01.mkv"})) + }); + + Mocker.GetMock() + .Setup(s => s.MostRecentForDownloadId(It.Is(i => i == "1234"))); + + Subject.Process(_trackedDownload); + + AssertNoCompletedDownload(); + } + [Test] public void should_not_import_when_there_is_a_title_mismatch() { diff --git a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs new file mode 100644 index 000000000..add4a367e --- /dev/null +++ b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.TrackedDownloads; +using NzbDrone.Core.History; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.MediaFiles.EpisodeImport; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; +using NzbDrone.Core.Indexers; +using System.Linq; + +namespace NzbDrone.Core.Test.Download +{ + [TestFixture] + public class TrackedDownloadServiceFixture : CoreTest + { + private void GivenAHistoryWithADownload() + { + Mocker.GetMock() + .Setup(s => s.FindByDownloadId(It.Is(sr => sr == "35238"))) + .Returns(new List(){ + new History.History(){ + DownloadId = "35238", + SourceTitle = "Tv Series S01", + SeriesId = 5, + EpisodeId = 4 + } + }); + } + + [Test] + public void should_track_downloads_using_the_source_title_if_it_cannot_be_found_using_the_download_title() + { + GivenAHistoryWithADownload(); + + var remoteEpisode = new RemoteEpisode + { + Series = new Series() { Id = 5 }, + Episodes = new List { new Episode { Id = 4 } }, + ParsedEpisodeInfo = new ParsedEpisodeInfo() + { + SeriesTitle = "tvseries", + SeasonNumber = 1 + } + }; + + Mocker.GetMock() + .Setup(s => s.Map(It.Is(i => i.SeasonNumber == 1 && i.SeriesTitle == "tvseries"), It.IsAny(), It.IsAny>())) + .Returns(remoteEpisode); + + var client = new DownloadClientDefinition() + { + Id = 1, + Protocol = DownloadProtocol.Torrent + }; + + var item = new DownloadClientItem() + { + Title = "The torrent release folder", + DownloadId = "35238", + }; + + var trackedDownload = Subject.TrackDownload(client, item); + + trackedDownload.RemoteEpisode.Series.Id.Should().Be(5); + trackedDownload.RemoteEpisode.Episodes.First().Id.Should().Be(4); + trackedDownload.RemoteEpisode.ParsedEpisodeInfo.SeasonNumber.Should().Be(1); + trackedDownload.RemoteEpisode.ParsedEpisodeInfo.SeriesTitle.Should().Be("tvseries"); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index b1b406d93..b5b7fce72 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -175,6 +175,7 @@ Always + diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index b26f4a820..b4910f9a0 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; +using NzbDrone.Core.Tv; namespace NzbDrone.Core.Download { @@ -27,12 +28,14 @@ namespace NzbDrone.Core.Download private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IParsingService _parsingService; private readonly Logger _logger; + private readonly ISeriesService _seriesService; public CompletedDownloadService(IConfigService configService, IEventAggregator eventAggregator, IHistoryService historyService, IDownloadedEpisodesImportService downloadedEpisodesImportService, IParsingService parsingService, + ISeriesService seriesService, Logger logger) { _configService = configService; @@ -41,6 +44,7 @@ namespace NzbDrone.Core.Download _downloadedEpisodesImportService = downloadedEpisodesImportService; _parsingService = parsingService; _logger = logger; + _seriesService = seriesService; } public void Process(TrackedDownload trackedDownload, bool ignoreWarnings = false) @@ -80,8 +84,16 @@ namespace NzbDrone.Core.Download if (series == null) { - trackedDownload.Warn("Series title mismatch, automatic import is not possible."); - return; + if (historyItem != null) + { + series = _seriesService.GetSeries(historyItem.SeriesId); + } + + if (series == null) + { + trackedDownload.Warn("Series title mismatch, automatic import is not possible."); + return; + } } } diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs index d8d9e802a..ff8ff4521 100644 --- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs +++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs @@ -5,6 +5,7 @@ using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; using NzbDrone.Core.History; using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download.TrackedDownloads { @@ -57,23 +58,35 @@ namespace NzbDrone.Core.Download.TrackedDownloads try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); - if (parsedEpisodeInfo == null) return null; + var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); - var remoteEpisode = _parsingService.Map(parsedEpisodeInfo); - - if (remoteEpisode.Series == null || !remoteEpisode.Episodes.Any()) + if (parsedEpisodeInfo != null) { - var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); - - if (historyItems.Empty()) - { - return null; - } - - remoteEpisode = _parsingService.Map(parsedEpisodeInfo, historyItems.First().SeriesId, historyItems.Select(h => h.EpisodeId)); + trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo); } - trackedDownload.RemoteEpisode = remoteEpisode; + if (historyItems.Any()) + { + var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First(); + trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType); + + if (parsedEpisodeInfo == null || + trackedDownload.RemoteEpisode == null || + trackedDownload.RemoteEpisode.Series == null || + trackedDownload.RemoteEpisode.Episodes.Empty()) + { + parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle); + if (parsedEpisodeInfo != null) + { + trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Select(h => h.EpisodeId)); + } + } + } + + if (trackedDownload.RemoteEpisode == null) + { + return null; + } } catch (Exception e) { @@ -81,15 +94,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads return null; } - var historyItem = _historyService.MostRecentForDownloadId(downloadItem.DownloadId); - - if (historyItem != null) - { - trackedDownload.State = GetStateFromHistory(historyItem.EventType); - } - _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); - return trackedDownload; }