diff --git a/src/NzbDrone.Api/History/HistoryModule.cs b/src/NzbDrone.Api/History/HistoryModule.cs index 540800808..c4831a648 100644 --- a/src/NzbDrone.Api/History/HistoryModule.cs +++ b/src/NzbDrone.Api/History/HistoryModule.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Api.History Post("/failed", x => MarkAsFailed()); } - protected HistoryResource MapToResource(Core.History.History model) + protected HistoryResource MapToResource(EpisodeHistory model) { var resource = model.ToResource(); @@ -50,12 +50,12 @@ namespace NzbDrone.Api.History private PagingResource GetHistory(PagingResource pagingResource) { var episodeId = Request.Query.EpisodeId; - var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); + var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); var filter = pagingResource.Filters.FirstOrDefault(); if (filter != null && filter.Key == "eventType") { - var filterValue = (HistoryEventType)Convert.ToInt32(filter.Value); + var filterValue = (EpisodeHistoryEventType)Convert.ToInt32(filter.Value); pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue); } @@ -79,11 +79,11 @@ namespace NzbDrone.Api.History } DateTime date = DateTime.Parse(queryDate.Value); - HistoryEventType? eventType = null; + EpisodeHistoryEventType? eventType = null; if (queryEventType.HasValue) { - eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); + eventType = (EpisodeHistoryEventType)Convert.ToInt32(queryEventType.Value); } return _historyService.Since(date, eventType).Select(MapToResource).ToList(); diff --git a/src/NzbDrone.Api/History/HistoryResource.cs b/src/NzbDrone.Api/History/HistoryResource.cs index e15bb7f7e..9b0fc22c9 100644 --- a/src/NzbDrone.Api/History/HistoryResource.cs +++ b/src/NzbDrone.Api/History/HistoryResource.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Api.History public string DownloadId { get; set; } public Language Language { get; set; } - public HistoryEventType EventType { get; set; } + public EpisodeHistoryEventType EventType { get; set; } public Dictionary Data { get; set; } @@ -30,7 +30,7 @@ namespace NzbDrone.Api.History public static class HistoryResourceMapper { - public static HistoryResource ToResource(this Core.History.History model) + public static HistoryResource ToResource(this EpisodeHistory model) { if (model == null) return null; diff --git a/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs b/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs index cb9d7ea86..bed951e0d 100644 --- a/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs +++ b/src/NzbDrone.Core.Test/Datastore/DatabaseRelationshipFixture.cs @@ -2,6 +2,7 @@ using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; +using NzbDrone.Core.History; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; @@ -59,21 +60,21 @@ namespace NzbDrone.Core.Test.Datastore { var quality = new QualityModel { Quality = Quality.Bluray720p, Revision = new Revision(version: 2 )}; - var history = Builder.CreateNew() + var history = Builder.CreateNew() .With(c => c.Id = 0) .With(c => c.Quality = quality) .Build(); Db.Insert(history); - var loadedQuality = Db.Single().Quality; + var loadedQuality = Db.Single().Quality; loadedQuality.Should().Be(quality); } [Test] public void embedded_list_of_document_with_json() { - var history = Builder.CreateListOfSize(2) + var history = Builder.CreateListOfSize(2) .All().With(c => c.Id = 0) .Build().ToList(); @@ -83,7 +84,7 @@ namespace NzbDrone.Core.Test.Datastore Db.InsertMany(history); - var returnedHistory = Db.All(); + var returnedHistory = Db.All(); returnedHistory[0].Quality.Quality.Should().Be(Quality.HDTV1080p); } diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/AlreadyImportedSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/AlreadyImportedSpecificationFixture.cs index 5e563e293..4ea248175 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/AlreadyImportedSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/AlreadyImportedSpecificationFixture.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests private QualityModel _hdtv720p; private QualityModel _hdtv1080p; private RemoteEpisode _remoteEpisode; - private List _history; + private List _history; [SetUp] public void Setup() @@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests .Build() }; - _history = new List(); + _history = new List(); Mocker.GetMock() .SetupGet(s => s.EnableCompletedDownloadHandling) @@ -75,9 +75,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests .Returns(false); } - private void GivenHistoryItem(string downloadId, string sourceTitle, QualityModel quality, HistoryEventType eventType) + private void GivenHistoryItem(string downloadId, string sourceTitle, QualityModel quality, EpisodeHistoryEventType eventType) { - _history.Add(new History.History + _history.Add(new EpisodeHistory { DownloadId = downloadId, SourceTitle = sourceTitle, @@ -112,7 +112,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests [Test] public void should_be_accepted_if_episode_does_not_have_imported_event() { - GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _hdtv720p, HistoryEventType.Grabbed); + GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); } @@ -122,8 +122,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { var downloadId = Guid.NewGuid().ToString().ToUpper(); - GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); - GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.DownloadFolderImported); + GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); + GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.DownloadFolderImported); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); } @@ -133,8 +133,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { var downloadId = Guid.NewGuid().ToString().ToUpper(); - GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); - GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); + GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); + GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported); _remoteEpisode.Release = Builder.CreateNew() .With(t => t.DownloadProtocol = DownloadProtocol.Torrent) @@ -149,8 +149,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { var downloadId = Guid.NewGuid().ToString().ToUpper(); - GivenHistoryItem(null, TITLE, _hdtv720p, HistoryEventType.Grabbed); - GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); + GivenHistoryItem(null, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); + GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported); _remoteEpisode.Release = Builder.CreateNew() .With(t => t.DownloadProtocol = DownloadProtocol.Torrent) @@ -165,8 +165,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { var downloadId = Guid.NewGuid().ToString().ToUpper(); - GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); - GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); + GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); + GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported); _remoteEpisode.Release = Builder.CreateNew() .With(t => t.DownloadProtocol = DownloadProtocol.Torrent) @@ -181,8 +181,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { var downloadId = Guid.NewGuid().ToString().ToUpper(); - GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); - GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); + GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed); + GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported); _remoteEpisode.Release = Builder.CreateNew() .With(t => t.DownloadProtocol = DownloadProtocol.Torrent) diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/HistorySpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/HistorySpecificationFixture.cs index 00fd23463..4bf22de35 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/HistorySpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/HistorySpecificationFixture.cs @@ -84,10 +84,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync .Returns(true); } - private void GivenMostRecentForEpisode(int episodeId, string downloadId, Tuple quality, DateTime date, HistoryEventType eventType) + private void GivenMostRecentForEpisode(int episodeId, string downloadId, Tuple quality, DateTime date, EpisodeHistoryEventType eventType) { Mocker.GetMock().Setup(s => s.MostRecentForEpisode(episodeId)) - .Returns(new History.History { DownloadId = downloadId, Quality = quality.Item1, Date = date, EventType = eventType, Language = quality.Item2 }); + .Returns(new EpisodeHistory { DownloadId = downloadId, Quality = quality.Item1, Date = date, EventType = eventType, Language = quality.Item2 }); } private void GivenCdhDisabled() @@ -106,14 +106,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync [Test] public void should_return_true_if_latest_history_item_is_null() { - Mocker.GetMock().Setup(s => s.MostRecentForEpisode(It.IsAny())).Returns((History.History)null); + Mocker.GetMock().Setup(s => s.MostRecentForEpisode(It.IsAny())).Returns((EpisodeHistory)null); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } [Test] public void should_return_true_if_latest_history_item_is_not_grabbed() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.DownloadFailed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.DownloadFailed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } @@ -127,46 +127,46 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync [Test] public void should_return_true_if_latest_history_item_is_older_than_twelve_hours() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-13), HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-13), EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } [Test] public void should_be_upgradable_if_only_episode_is_upgradable() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); } [Test] public void should_be_upgradable_if_both_episodes_are_upgradable() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); - GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } [Test] public void should_not_be_upgradable_if_both_episodes_are_not_upgradable() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); - GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } [Test] public void should_be_not_upgradable_if_only_first_episodes_is_upgradable() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } [Test] public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); - GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } @@ -177,7 +177,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _upgradableQuality = new Tuple(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } @@ -190,7 +190,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync _parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish; _upgradableQuality = new Tuple(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); } @@ -202,7 +202,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _upgradableQuality = new Tuple(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } @@ -210,7 +210,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync [Test] public void should_return_false_if_latest_history_item_is_only_one_hour_old() { - GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } @@ -218,7 +218,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync public void should_return_false_if_latest_history_has_a_download_id_and_cdh_is_disabled() { GivenCdhDisabled(); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } @@ -230,7 +230,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 1)); _upgradableQuality = new Tuple(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } @@ -239,7 +239,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync public void should_return_false_if_only_episode_is_not_upgradable_and_cdh_is_disabled() { GivenCdhDisabled(); - GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), EpisodeHistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } } diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs index 8e061eb47..5ca8e2e9d 100644 --- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs +++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests Mocker.GetMock() .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) - .Returns(new History.History()); + .Returns(new EpisodeHistory()); Mocker.GetMock() .Setup(s => s.GetSeries("Drone.S01E01.HDTV")) @@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests _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" }); + .Returns(new EpisodeHistory() { SourceTitle = "Droned S01E01" }); Mocker.GetMock() .Setup(s => s.GetSeries(It.IsAny())) @@ -187,7 +187,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.IsAny())) - .Returns(new List()); + .Returns(new List()); Subject.Import(_trackedDownload); @@ -213,7 +213,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests new ImportResult(new ImportDecision(new LocalEpisode{Path = @"C:\TestPath\Droned.S01E01.mkv"}),"Test Failure") }); - var history = Builder.CreateListOfSize(2) + var history = Builder.CreateListOfSize(2) .BuildList(); Mocker.GetMock() @@ -274,7 +274,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests new LocalEpisode {Path = @"C:\TestPath\Droned.S01E02.mkv", Episodes = new List { episode2 } }),"Test Failure") }); - var history = Builder.CreateListOfSize(2) + var history = Builder.CreateListOfSize(2) .BuildList(); Mocker.GetMock() @@ -282,7 +282,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests .Returns(history); Mocker.GetMock() - .Setup(s => s.IsImported(It.IsAny(), It.IsAny>())) + .Setup(s => s.IsImported(It.IsAny(), It.IsAny>())) .Returns(true); Subject.Import(_trackedDownload); diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs index 003fbb992..7946a890a 100644 --- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs +++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests Mocker.GetMock() .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) - .Returns(new History.History()); + .Returns(new EpisodeHistory()); Mocker.GetMock() .Setup(s => s.GetSeries("Drone.S01E01.HDTV")) @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests { Mocker.GetMock() .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) - .Returns((History.History)null); + .Returns((EpisodeHistory)null); } private void GivenSeriesMatch() @@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests _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" }); + .Returns(new EpisodeHistory() { SourceTitle = "Droned S01E01" }); Mocker.GetMock() .Setup(s => s.GetSeries(It.IsAny())) diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs index 762137861..0f048b75d 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadClientFixtureBase.cs @@ -62,7 +62,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests protected void VerifyIdentifiable(DownloadClientItem downloadClientItem) { - downloadClientItem.DownloadClient.Should().Be(Subject.Definition.Name); + downloadClientItem.DownloadClientInfo.Protocol.Should().Be(Subject.Protocol); + downloadClientItem.DownloadClientInfo.Id.Should().Be(Subject.Definition.Id); + downloadClientItem.DownloadClientInfo.Name.Should().Be(Subject.Definition.Name); downloadClientItem.DownloadId.Should().NotBeNullOrEmpty(); downloadClientItem.Title.Should().NotBeNullOrEmpty(); } diff --git a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFailedFixture.cs b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFailedFixture.cs index 8b2395435..29e9c998e 100644 --- a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFailedFixture.cs +++ b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFailedFixture.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests public class ProcessFailedFixture : CoreTest { private TrackedDownload _trackedDownload; - private List _grabHistory; + private List _grabHistory; [SetUp] public void Setup() @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests .With(h => h.Title = "Drone.S01E01.HDTV") .Build(); - _grabHistory = Builder.CreateListOfSize(2).BuildList(); + _grabHistory = Builder.CreateListOfSize(2).BuildList(); var remoteEpisode = new RemoteEpisode { @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests Mocker.GetMock() - .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) + .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed)) .Returns(_grabHistory); } diff --git a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFixture.cs b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFixture.cs index e54d16859..dc63d7b7e 100644 --- a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFixture.cs +++ b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceTests/ProcessFixture.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests public class ProcessFixture : CoreTest { private TrackedDownload _trackedDownload; - private List _grabHistory; + private List _grabHistory; [SetUp] public void Setup() @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests .With(h => h.Title = "Drone.S01E01.HDTV") .Build(); - _grabHistory = Builder.CreateListOfSize(2).BuildList(); + _grabHistory = Builder.CreateListOfSize(2).BuildList(); var remoteEpisode = new RemoteEpisode { @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests Mocker.GetMock() - .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) + .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed)) .Returns(_grabHistory); } @@ -54,8 +54,8 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests private void GivenNoGrabbedHistory() { Mocker.GetMock() - .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) - .Returns(new List()); + .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed)) + .Returns(new List()); } [Test] diff --git a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadAlreadyImportedFixture.cs b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadAlreadyImportedFixture.cs index aaad9640a..87c3cebad 100644 --- a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadAlreadyImportedFixture.cs +++ b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadAlreadyImportedFixture.cs @@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { private List _episodes; private TrackedDownload _trackedDownload; - private List _historyItems; + private List _historyItems; [SetUp] public void Setup() @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads .With(t => t.RemoteEpisode = remoteEpisode) .Build(); - _historyItems = new List(); + _historyItems = new List(); } public void GivenEpisodes(int count) @@ -39,12 +39,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads .BuildList()); } - public void GivenHistoryForEpisode(Episode episode, params HistoryEventType[] eventTypes) + public void GivenHistoryForEpisode(Episode episode, params EpisodeHistoryEventType[] eventTypes) { foreach (var eventType in eventTypes) { _historyItems.Add( - Builder.CreateNew() + Builder.CreateNew() .With(h => h.EpisodeId = episode.Id) .With(h => h.EventType = eventType) .Build() @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { GivenEpisodes(1); - GivenHistoryForEpisode(_episodes[0], HistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.Grabbed); Subject.IsImported(_trackedDownload, _historyItems) .Should() @@ -79,8 +79,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { GivenEpisodes(2); - GivenHistoryForEpisode(_episodes[0], HistoryEventType.Grabbed); - GivenHistoryForEpisode(_episodes[1], HistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.Grabbed); Subject.IsImported(_trackedDownload, _historyItems) .Should() @@ -92,8 +92,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { GivenEpisodes(2); - GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); - GivenHistoryForEpisode(_episodes[1], HistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.Grabbed); Subject.IsImported(_trackedDownload, _historyItems) .Should() @@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { GivenEpisodes(1); - GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed); Subject.IsImported(_trackedDownload, _historyItems) .Should() @@ -117,8 +117,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { GivenEpisodes(2); - GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); - GivenHistoryForEpisode(_episodes[1], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed); + GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed); Subject.IsImported(_trackedDownload, _historyItems) .Should() diff --git a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs index 0488e916e..70f9bc16c 100644 --- a/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/TrackedDownloads/TrackedDownloadServiceFixture.cs @@ -21,8 +21,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.Is(sr => sr == "35238"))) - .Returns(new List(){ - new History.History(){ + .Returns(new List(){ + new EpisodeHistory(){ DownloadId = "35238", SourceTitle = "TV Series S01", SeriesId = 5, @@ -61,6 +61,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { Title = "The torrent release folder", DownloadId = "35238", + DownloadClientInfo = new DownloadClientItemClientInfo + { + Protocol = client.Protocol, + Id = client.Id, + Name = client.Name + } }; var trackedDownload = Subject.TrackDownload(client, item); @@ -90,8 +96,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads Mocker.GetMock() .Setup(s => s.FindByDownloadId(It.Is(sr => sr == "35238"))) - .Returns(new List(){ - new History.History(){ + .Returns(new List(){ + new EpisodeHistory(){ DownloadId = "35238", SourceTitle = "TV Series Special", SeriesId = 5, @@ -117,6 +123,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads { Title = "The torrent release folder", DownloadId = "35238", + DownloadClientInfo = new DownloadClientItemClientInfo + { + Protocol = client.Protocol, + Id = client.Id, + Name = client.Name + } }; var trackedDownload = Subject.TrackDownload(client, item); diff --git a/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs b/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs index 649c3d499..89b0aea1b 100644 --- a/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs @@ -8,13 +8,13 @@ using NzbDrone.Core.Qualities; namespace NzbDrone.Core.Test.HistoryTests { [TestFixture] - public class HistoryRepositoryFixture : DbTest + public class HistoryRepositoryFixture : DbTest { [Test] public void should_read_write_dictionary() { - var history = Builder.CreateNew() + var history = Builder.CreateNew() .With(c => c.Quality = new QualityModel()) .BuildNew(); @@ -30,16 +30,16 @@ namespace NzbDrone.Core.Test.HistoryTests [Test] public void should_get_download_history() { - var historyBluray = Builder.CreateNew() + var historyBluray = Builder.CreateNew() .With(c => c.Quality = new QualityModel(Quality.Bluray1080p)) .With(c => c.SeriesId = 12) - .With(c => c.EventType = HistoryEventType.Grabbed) + .With(c => c.EventType = EpisodeHistoryEventType.Grabbed) .BuildNew(); - var historyDvd = Builder.CreateNew() + var historyDvd = Builder.CreateNew() .With(c => c.Quality = new QualityModel(Quality.DVD)) .With(c => c.SeriesId = 12) - .With(c => c.EventType = HistoryEventType.Grabbed) + .With(c => c.EventType = EpisodeHistoryEventType.Grabbed) .BuildNew(); Subject.Insert(historyBluray); diff --git a/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs b/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs index 0eebc8cd5..0c74874df 100644 --- a/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs +++ b/src/NzbDrone.Core.Test/HistoryTests/HistoryServiceFixture.cs @@ -13,6 +13,7 @@ using NzbDrone.Core.History; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Qualities; using NzbDrone.Core.Download; +using NzbDrone.Core.Indexers; using NzbDrone.Core.Tv; using NzbDrone.Core.Languages; using NzbDrone.Core.Profiles.Languages; @@ -68,14 +69,19 @@ namespace NzbDrone.Core.Test.HistoryTests var downloadClientItem = new DownloadClientItem { - DownloadClient = "sab", + DownloadClientInfo = new DownloadClientItemClientInfo + { + Protocol = DownloadProtocol.Usenet, + Id = 1, + Name = "sab" + }, DownloadId = "abcd" }; Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, new List(), true, downloadClientItem)); Mocker.GetMock() - .Verify(v => v.Insert(It.Is(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path)))); + .Verify(v => v.Insert(It.Is(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path)))); } } } diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs index 022248abd..3b9b9d8bb 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs @@ -1,6 +1,7 @@ using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; +using NzbDrone.Core.History; using NzbDrone.Core.Housekeeping.Housekeepers; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; @@ -9,7 +10,7 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Core.Test.Housekeeping.Housekeepers { [TestFixture] - public class CleanupOrphanedHistoryItemsFixture : DbTest + public class CleanupOrphanedHistoryItemsFixture : DbTest { private Series _series; private Episode _episode; @@ -39,7 +40,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers { GivenEpisode(); - var history = Builder.CreateNew() + var history = Builder.CreateNew() .With(h => h.Quality = new QualityModel()) .With(h => h.EpisodeId = _episode.Id) .BuildNew(); @@ -54,7 +55,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers { GivenSeries(); - var history = Builder.CreateNew() + var history = Builder.CreateNew() .With(h => h.Quality = new QualityModel()) .With(h => h.SeriesId = _series.Id) .BuildNew(); @@ -70,7 +71,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers GivenSeries(); GivenEpisode(); - var history = Builder.CreateListOfSize(2) + var history = Builder.CreateListOfSize(2) .All() .With(h => h.Quality = new QualityModel()) .With(h => h.EpisodeId = _episode.Id) @@ -91,7 +92,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers GivenSeries(); GivenEpisode(); - var history = Builder.CreateListOfSize(2) + var history = Builder.CreateListOfSize(2) .All() .With(h => h.Quality = new QualityModel()) .With(h => h.SeriesId = _series.Id) diff --git a/src/NzbDrone.Core.Test/QueueTests/QueueServiceFixture.cs b/src/NzbDrone.Core.Test/QueueTests/QueueServiceFixture.cs index 81ca1e28d..f1ac1293b 100644 --- a/src/NzbDrone.Core.Test/QueueTests/QueueServiceFixture.cs +++ b/src/NzbDrone.Core.Test/QueueTests/QueueServiceFixture.cs @@ -7,6 +7,7 @@ using NzbDrone.Core.Queue; using NzbDrone.Core.Test.Framework; using FizzWare.NBuilder; using FluentAssertions; +using NzbDrone.Core.Download; using NzbDrone.Core.Tv; using NzbDrone.Core.Parser.Model; @@ -20,8 +21,11 @@ namespace NzbDrone.Core.Test.QueueTests [SetUp] public void SetUp() { + var downloadClientInfo = Builder.CreateNew().Build(); + var downloadItem = Builder.CreateNew() .With(v => v.RemainingTime = TimeSpan.FromSeconds(10)) + .With(v => v.DownloadClientInfo = downloadClientInfo) .Build(); var series = Builder.CreateNew() diff --git a/src/NzbDrone.Core/Analytics/AnalyticsService.cs b/src/NzbDrone.Core/Analytics/AnalyticsService.cs index bd1281999..e8735aece 100644 --- a/src/NzbDrone.Core/Analytics/AnalyticsService.cs +++ b/src/NzbDrone.Core/Analytics/AnalyticsService.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Analytics { get { - var lastRecord = _historyService.Paged(new PagingSpec() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending }); + var lastRecord = _historyService.Paged(new PagingSpec() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending }); var monthAgo = DateTime.UtcNow.AddMonths(-1); return lastRecord.Records.Any(v => v.Date > monthAgo); diff --git a/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs b/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs new file mode 100644 index 000000000..9294f5aa3 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/139_add_download_history.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Data; +using FluentMigrator; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(139)] + public class add_download_history : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Create.TableForModel("DownloadHistory") + .WithColumn("EventType").AsInt32().NotNullable() + .WithColumn("SeriesId").AsInt32().NotNullable() + .WithColumn("DownloadId").AsString().NotNullable() + .WithColumn("SourceTitle").AsString().NotNullable() + .WithColumn("Date").AsDateTime().NotNullable() + .WithColumn("Protocol").AsInt32().Nullable() + .WithColumn("IndexerId").AsInt32().Nullable() + .WithColumn("DownloadClientId").AsInt32().Nullable() + .WithColumn("Release").AsString().Nullable() + .WithColumn("Data").AsString().Nullable(); + + Create.Index().OnTable("DownloadHistory").OnColumn("EventType"); + Create.Index().OnTable("DownloadHistory").OnColumn("SeriesId"); + Create.Index().OnTable("DownloadHistory").OnColumn("DownloadId"); + + Execute.WithConnection(InitialImportedDownloadHistory); + } + + private static readonly Dictionary EventTypeMap = new Dictionary() + { + // EpisodeHistoryType.Grabbed -> DownloadHistoryType.Grabbed + {1, 1}, + // EpisodeHistoryType.DownloadFolderImported -> DownloadHistoryType.DownloadImported + {3, 2}, + // EpisodeHistoryType.DownloadFailed -> DownloadHistoryType.DownloadFailed + {4, 3}, + // EpisodeHistoryType.DownloadIgnored -> DownloadHistoryType.DownloadIgnored + {7, 4} + }; + + private void InitialImportedDownloadHistory(IDbConnection conn, IDbTransaction tran) + { + using (var cmd = conn.CreateCommand()) + { + cmd.Transaction = tran; + cmd.CommandText = "SELECT SeriesId, DownloadId, EventType, SourceTitle, Date, Data FROM History WHERE DownloadId IS NOT NULL AND EventType IN (1, 3, 4, 7) GROUP BY EventType, DownloadId"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var seriesId = reader.GetInt32(0); + var downloadId = reader.GetString(1); + var eventType = reader.GetInt32(2); + var sourceTitle = reader.GetString(3); + var date = reader.GetDateTime(4); + var rawData = reader.GetString(5); + var data = Json.Deserialize>(rawData); + + var downloadHistoryEventType = EventTypeMap[eventType]; + var protocol = data.ContainsKey("protocol") ? Convert.ToInt32(data["protocol"]) : (int?)null; + var downloadHistoryData = new Dictionary(); + + if (data.ContainsKey("indexer")) + { + downloadHistoryData.Add("indexer", data["indexer"]); + } + + if (data.ContainsKey("downloadClient")) + { + downloadHistoryData.Add("downloadClient", data["downloadClient"]); + } + + using (var updateCmd = conn.CreateCommand()) + { + updateCmd.Transaction = tran; + updateCmd.CommandText = @"INSERT INTO DownloadHistory (EventType, SeriesId, DownloadId, SourceTitle, Date, Protocol, Data) VALUES (?, ?, ?, ?, ?, ?, ?)"; + updateCmd.AddParameter(downloadHistoryEventType); + updateCmd.AddParameter(seriesId); + updateCmd.AddParameter(downloadId); + updateCmd.AddParameter(sourceTitle); + updateCmd.AddParameter(date); + updateCmd.AddParameter(protocol); + updateCmd.AddParameter(downloadHistoryData.ToJson()); + + updateCmd.ExecuteNonQuery(); + } + } + } + } + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 58ef55be6..df9c97602 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -29,10 +29,12 @@ using NzbDrone.Core.Tv; using NzbDrone.Common.Disk; using NzbDrone.Core.Authentication; using NzbDrone.Core.CustomFilters; +using NzbDrone.Core.Download.History; using NzbDrone.Core.Extras.Metadata; using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Others; using NzbDrone.Core.Extras.Subtitles; +using NzbDrone.Core.History; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Languages; using NzbDrone.Core.Profiles.Languages; @@ -80,7 +82,7 @@ namespace NzbDrone.Core.Datastore Mapper.Entity().RegisterModel("SceneMappings"); - Mapper.Entity().RegisterModel("History") + Mapper.Entity().RegisterModel("History") .AutoMapChildModels(); Mapper.Entity().RegisterModel("Series") @@ -134,6 +136,9 @@ namespace NzbDrone.Core.Datastore Mapper.Entity().RegisterModel("DownloadClientStatus"); Mapper.Entity().RegisterModel("CustomFilters"); + + Mapper.Entity().RegisterModel("DownloadHistory") + .AutoMapChildModels(); } private static void RegisterMappers() diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/AlreadyImportedSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/AlreadyImportedSpecification.cs index 53cbd9abe..2dcdeefee 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/AlreadyImportedSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/AlreadyImportedSpecification.cs @@ -47,7 +47,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications } var historyForEpisode = _historyService.FindByEpisodeId(episode.Id); - var lastGrabbed = historyForEpisode.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed); + var lastGrabbed = historyForEpisode.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.Grabbed); if (lastGrabbed == null) { @@ -55,7 +55,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications } var imported = historyForEpisode.FirstOrDefault(h => - h.EventType == HistoryEventType.DownloadFolderImported && + h.EventType == EpisodeHistoryEventType.DownloadFolderImported && h.DownloadId == lastGrabbed.DownloadId); if (imported == null) diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs index 51ee3cb5b..a8e186ff9 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs @@ -49,7 +49,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync _logger.Debug("Checking current status of episode [{0}] in history", episode.Id); var mostRecent = _historyService.MostRecentForEpisode(episode.Id); - if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed) + if (mostRecent != null && mostRecent.EventType == EpisodeHistoryEventType.Grabbed) { var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12)); diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs index 2bb9346a3..1d6395751 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs @@ -88,7 +88,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole { yield return new DownloadClientItem { - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = Definition.Name + "_" + item.DownloadId, Category = "sonarr", Title = item.Title, diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs index 561b4901b..0d89b48a6 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/UsenetBlackhole.cs @@ -59,7 +59,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole { yield return new DownloadClientItem { - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = Definition.Name + "_" + item.DownloadId, Category = "sonarr", Title = item.Title, diff --git a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs index 6eeeb7ccb..5907680a2 100644 --- a/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs +++ b/src/NzbDrone.Core/Download/Clients/Deluge/Deluge.cs @@ -129,7 +129,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge item.Title = torrent.Name; item.Category = Settings.TvCategory; - item.DownloadClient = Definition.Name; + item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath)); item.OutputPath = outputPath + torrent.Name; diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs index 15508af90..5840288bc 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/TorrentDownloadStation.cs @@ -85,7 +85,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation var item = new DownloadClientItem() { Category = Settings.TvCategory, - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = CreateDownloadId(torrent.Id, serialNumber), Title = torrent.Title, TotalSize = torrent.Size, diff --git a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs index fda9c339d..14ebc67a4 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadStation/UsenetDownloadStation.cs @@ -96,7 +96,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation var item = new DownloadClientItem() { Category = Settings.TvCategory, - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = CreateDownloadId(nzb.Id, serialNumber), Title = nzb.Title, TotalSize = nzb.Size, diff --git a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs index 700320779..1fb789fc9 100644 --- a/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs +++ b/src/NzbDrone.Core/Download/Clients/Hadouken/Hadouken.cs @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken var item = new DownloadClientItem { - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = torrent.InfoHash.ToUpper(), OutputPath = outputPath + torrent.Name, RemainingSize = torrent.TotalSize - torrent.DownloadedBytes, diff --git a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs index 0d38a29a0..7faeae119 100644 --- a/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs +++ b/src/NzbDrone.Core/Download/Clients/NzbVortex/NzbVortex.cs @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex { var queueItem = new DownloadClientItem(); - queueItem.DownloadClient = Definition.Name; + queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); queueItem.DownloadId = vortexQueueItem.AddUUID ?? vortexQueueItem.Id.ToString(); queueItem.Category = vortexQueueItem.GroupName; queueItem.Title = vortexQueueItem.UiTitle; diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs index 92a8a5dad..eec32ca19 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs @@ -71,7 +71,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget queueItem.Title = item.NzbName; queueItem.TotalSize = totalSize; queueItem.Category = item.Category; - queueItem.DownloadClient = Definition.Name; + queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); queueItem.CanMoveFiles = true; queueItem.CanBeRemoved = true; @@ -118,7 +118,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget var historyItem = new DownloadClientItem(); var itemDir = item.FinalDir.IsNullOrWhiteSpace() ? item.DestDir : item.FinalDir; - historyItem.DownloadClient = Definition.Name; + historyItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); historyItem.DownloadId = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString(); historyItem.Title = item.Name; historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo); diff --git a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs index 00695b11f..38c6a54aa 100644 --- a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs +++ b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic var historyItem = new DownloadClientItem { - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = GetDownloadClientId(file), Title = title, diff --git a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs index 232ee897f..18ad75777 100644 --- a/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/QBittorrent/QBittorrent.cs @@ -135,7 +135,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label, Title = torrent.Name, TotalSize = torrent.Size, - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)), RemainingTime = GetRemainingTime(torrent), SeedRatio = torrent.Ratio, diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs index c7c7932fc..d5a7d2cbb 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs @@ -62,7 +62,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd } var queueItem = new DownloadClientItem(); - queueItem.DownloadClient = Definition.Name; + queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); queueItem.DownloadId = sabQueueItem.Id; queueItem.Category = sabQueueItem.Category; queueItem.Title = sabQueueItem.Title; @@ -117,7 +117,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd var historyItem = new DownloadClientItem { - DownloadClient = Definition.Name, + DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = sabHistoryItem.Id, Category = sabHistoryItem.Category, Title = sabHistoryItem.Title, diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs index c1fd61180..3227e9404 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs @@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission item.Category = Settings.TvCategory; item.Title = torrent.Name; - item.DownloadClient = Definition.Name; + item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); item.OutputPath = GetOutputPath(outputPath, torrent); item.TotalSize = torrent.TotalSize; diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs index f14d89f2d..d77f9d705 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs @@ -115,7 +115,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent } var item = new DownloadClientItem(); - item.DownloadClient = Definition.Name; + item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); item.Title = torrent.Name; item.DownloadId = torrent.Hash; item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path)); diff --git a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs index 5540d8f63..13f6cc6fd 100644 --- a/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/uTorrent/UTorrent.cs @@ -118,7 +118,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent item.Title = torrent.Name; item.TotalSize = torrent.Size; item.Category = torrent.Label; - item.DownloadClient = Definition.Name; + item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); item.RemainingSize = torrent.Remaining; item.SeedRatio = torrent.Ratio; diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs index 07171cefb..9bd762388 100644 --- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs +++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs @@ -122,6 +122,11 @@ namespace NzbDrone.Core.Download // file was imported. This will allow the decision engine to reject already imported // episode files and still mark the download complete when all files are imported. + // EDGE CASE: This process relies on EpisodeIds being consistent between executions, if a series is updated + // and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete. + // Since imports should be relatively fast and these types of data changes are infrequent this should be quite + // safe, but commenting for future benefit. + if (importResults.Any(c => c.Result == ImportResultType.Imported)) { var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId) diff --git a/src/NzbDrone.Core/Download/DownloadClientItem.cs b/src/NzbDrone.Core/Download/DownloadClientItem.cs index 3348be4a9..efc36bbe0 100644 --- a/src/NzbDrone.Core/Download/DownloadClientItem.cs +++ b/src/NzbDrone.Core/Download/DownloadClientItem.cs @@ -1,13 +1,15 @@ using System; using System.Diagnostics; using NzbDrone.Common.Disk; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Download { - [DebuggerDisplay("{DownloadClient}:{Title}")] + [DebuggerDisplay("{DownloadClientName}:{Title}")] public class DownloadClientItem { - public string DownloadClient { get; set; } + public DownloadClientItemClientInfo DownloadClientInfo { get; set; } public string DownloadId { get; set; } public string Category { get; set; } public string Title { get; set; } @@ -16,16 +18,32 @@ namespace NzbDrone.Core.Download public long RemainingSize { get; set; } public TimeSpan? RemainingTime { get; set; } public double? SeedRatio { get; set; } - public OsPath OutputPath { get; set; } public string Message { get; set; } - public DownloadItemStatus Status { get; set; } public bool IsEncrypted { get; set; } - public bool CanMoveFiles { get; set; } public bool CanBeRemoved { get; set; } - public bool Removed { get; set; } } + + public class DownloadClientItemClientInfo + { + public DownloadProtocol Protocol { get; set; } + public string Type { get; set; } + public int Id { get; set; } + public string Name { get; set; } + + public static DownloadClientItemClientInfo FromDownloadClient( + DownloadClientBase downloadClient) where TSettings : IProviderConfig, new() + { + return new DownloadClientItemClientInfo + { + Protocol = downloadClient.Protocol, + Type = downloadClient.Name, + Id = downloadClient.Definition.Id, + Name = downloadClient.Definition.Name + }; + } + } } diff --git a/src/NzbDrone.Core/Download/DownloadEventHub.cs b/src/NzbDrone.Core/Download/DownloadEventHub.cs index 8d0f50bc1..0e0f64962 100644 --- a/src/NzbDrone.Core/Download/DownloadEventHub.cs +++ b/src/NzbDrone.Core/Download/DownloadEventHub.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Download var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); try { - _logger.Debug("[{0}] Removing download from {1} history", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClient); + _logger.Debug("[{0}] Removing download from {1} history", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClientInfo.Name); downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadId, true); trackedDownload.DownloadItem.Removed = true; } @@ -85,7 +85,7 @@ namespace NzbDrone.Core.Download var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); try { - _logger.Debug("[{0}] Marking download as imported from {1}", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClient); + _logger.Debug("[{0}] Marking download as imported from {1}", trackedDownload.DownloadItem.Title, trackedDownload.DownloadItem.DownloadClientInfo.Name); downloadClient.MarkItemAsImported(trackedDownload.DownloadItem); } catch (NotSupportedException e) diff --git a/src/NzbDrone.Core/Download/DownloadIgnoredEvent.cs b/src/NzbDrone.Core/Download/DownloadIgnoredEvent.cs index 7637caaf3..e2e85348d 100644 --- a/src/NzbDrone.Core/Download/DownloadIgnoredEvent.cs +++ b/src/NzbDrone.Core/Download/DownloadIgnoredEvent.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Download public Language Language { get; set; } public QualityModel Quality { get; set; } public string SourceTitle { get; set; } - public string DownloadClient { get; set; } + public DownloadClientItemClientInfo DownloadClientInfo { get; set; } public string DownloadId { get; set; } public string Message { get; set; } } diff --git a/src/NzbDrone.Core/Download/DownloadService.cs b/src/NzbDrone.Core/Download/DownloadService.cs index 0997b42c5..2f03337e4 100644 --- a/src/NzbDrone.Core/Download/DownloadService.cs +++ b/src/NzbDrone.Core/Download/DownloadService.cs @@ -5,7 +5,6 @@ using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.TPL; -using NzbDrone.Core.Configuration; using NzbDrone.Core.Download.Clients; using NzbDrone.Core.Exceptions; using NzbDrone.Core.Indexers; @@ -98,6 +97,8 @@ namespace NzbDrone.Core.Download var episodeGrabbedEvent = new EpisodeGrabbedEvent(remoteEpisode); episodeGrabbedEvent.DownloadClient = downloadClient.Name; + episodeGrabbedEvent.DownloadClientId = downloadClient.Definition.Id; + episodeGrabbedEvent.DownloadClientName = downloadClient.Definition.Name; if (!string.IsNullOrWhiteSpace(downloadClientId)) { diff --git a/src/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs b/src/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs index b7861b8d7..27d030844 100644 --- a/src/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs +++ b/src/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs @@ -6,7 +6,9 @@ namespace NzbDrone.Core.Download public class EpisodeGrabbedEvent : IEvent { public RemoteEpisode Episode { get; private set; } + public int DownloadClientId { get; set; } public string DownloadClient { get; set; } + public string DownloadClientName { get; set; } public string DownloadId { get; set; } public EpisodeGrabbedEvent(RemoteEpisode episode) diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index c04abeae6..e15a6b758 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -18,12 +18,15 @@ namespace NzbDrone.Core.Download public class FailedDownloadService : IFailedDownloadService { private readonly IHistoryService _historyService; + private readonly ITrackedDownloadService _trackedDownloadService; private readonly IEventAggregator _eventAggregator; public FailedDownloadService(IHistoryService historyService, + ITrackedDownloadService trackedDownloadService, IEventAggregator eventAggregator) { _historyService = historyService; + _trackedDownloadService = trackedDownloadService; _eventAggregator = eventAggregator; } @@ -34,22 +37,24 @@ namespace NzbDrone.Core.Download var downloadId = history.DownloadId; if (downloadId.IsNullOrWhiteSpace()) { - PublishDownloadFailedEvent(new List { history }, "Manually marked as failed"); + PublishDownloadFailedEvent(new List { history }, "Manually marked as failed"); } else { - var grabbedHistory = _historyService.Find(downloadId, HistoryEventType.Grabbed).ToList(); + var grabbedHistory = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed).ToList(); PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed"); } } public void MarkAsFailed(string downloadId) { - var history = _historyService.Find(downloadId, HistoryEventType.Grabbed); + var history = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed); if (history.Any()) { - PublishDownloadFailedEvent(history, "Manually marked as failed"); + var trackedDownload = _trackedDownloadService.Find(downloadId); + + PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload); } } @@ -65,7 +70,7 @@ namespace NzbDrone.Core.Download trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed) { var grabbedItems = _historyService - .Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed) + .Find(trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed) .ToList(); if (grabbedItems.Empty()) @@ -86,7 +91,7 @@ namespace NzbDrone.Core.Download } var grabbedItems = _historyService - .Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed) + .Find(trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed) .ToList(); if (grabbedItems.Empty()) @@ -109,7 +114,7 @@ namespace NzbDrone.Core.Download PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload); } - private void PublishDownloadFailedEvent(List historyItems, string message, TrackedDownload trackedDownload = null) + private void PublishDownloadFailedEvent(List historyItems, string message, TrackedDownload trackedDownload = null) { var historyItem = historyItems.First(); @@ -119,7 +124,7 @@ namespace NzbDrone.Core.Download EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(), Quality = historyItem.Quality, SourceTitle = historyItem.SourceTitle, - DownloadClient = historyItem.Data.GetValueOrDefault(History.History.DOWNLOAD_CLIENT), + DownloadClient = historyItem.Data.GetValueOrDefault(EpisodeHistory.DOWNLOAD_CLIENT), DownloadId = historyItem.DownloadId, Message = message, Data = historyItem.Data, diff --git a/src/NzbDrone.Core/Download/History/DownloadHistory.cs b/src/NzbDrone.Core/Download/History/DownloadHistory.cs new file mode 100644 index 000000000..8eb38576b --- /dev/null +++ b/src/NzbDrone.Core/Download/History/DownloadHistory.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.Download.History +{ + public class DownloadHistory : ModelBase + { + public DownloadHistoryEventType EventType { get; set; } + public int SeriesId { get; set; } + public string DownloadId { get; set; } + public string SourceTitle { get; set; } + public DateTime Date { get; set; } + public DownloadProtocol Protocol { get; set; } + public int IndexerId { get; set; } + public int DownloadClientId { get; set; } + public ReleaseInfo Release { get; set; } + public Dictionary Data { get; set; } + public DownloadHistory() + { + Data = new Dictionary(); + } + } + + public enum DownloadHistoryEventType + { + DownloadGrabbed = 1, + DownloadImported = 2, + DownloadFailed = 3, + DownloadIgnored = 4, + FileImported = 5 + } +} diff --git a/src/NzbDrone.Core/Download/History/DownloadHistoryRepository.cs b/src/NzbDrone.Core/Download/History/DownloadHistoryRepository.cs new file mode 100644 index 000000000..136a37cc4 --- /dev/null +++ b/src/NzbDrone.Core/Download/History/DownloadHistoryRepository.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Messaging.Events; + +namespace NzbDrone.Core.Download.History +{ + public interface IDownloadHistoryRepository : IBasicRepository + { + List FindByDownloadId(string downloadId); + void DeleteBySeriesId(int seriesId); + } + + public class DownloadHistoryRepository : BasicRepository, IDownloadHistoryRepository + { + public DownloadHistoryRepository(IMainDatabase database, IEventAggregator eventAggregator) + : base(database, eventAggregator) + { + } + + public List FindByDownloadId(string downloadId) + { + return Query.Where(h => h.DownloadId == downloadId) + .OrderByDescending(h => h.Date); + } + + public void DeleteBySeriesId(int seriesId) + { + Delete(r => r.SeriesId == seriesId); + } + } +} diff --git a/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs b/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs new file mode 100644 index 000000000..6d7b6218f --- /dev/null +++ b/src/NzbDrone.Core/Download/History/DownloadHistoryService.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.IO; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.History; +using NzbDrone.Core.MediaFiles.Events; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Tv.Events; + +namespace NzbDrone.Core.Download.History +{ + public interface IDownloadHistoryService + { + bool DownloadAlreadyImported(string downloadId); + DownloadHistory GetLatestDownloadHistoryItem(string downloadId); + } + + public class DownloadHistoryService : IDownloadHistoryService, + IHandle, + IHandle, + IHandle, + IHandle, + IHandle, + IHandle + + { + private readonly IDownloadHistoryRepository _repository; + private readonly IHistoryService _historyService; + + public DownloadHistoryService(IDownloadHistoryRepository repository, IHistoryService historyService) + { + _repository = repository; + _historyService = historyService; + } + + public bool DownloadAlreadyImported(string downloadId) + { + var events = _repository.FindByDownloadId(downloadId); + + // Events are ordered by date descending, if a grabbed event comes before an imported event then it was never imported + // or grabbed again after importing and should be reprocessed. + foreach (var e in events) + { + if (e.EventType == DownloadHistoryEventType.DownloadGrabbed) + { + return false; + } + + if (e.EventType == DownloadHistoryEventType.DownloadImported) + { + return true; + } + } + + return false; + } + + public DownloadHistory GetLatestDownloadHistoryItem(string downloadId) + { + var events = _repository.FindByDownloadId(downloadId); + + // Events are ordered by date descending. We'll return the most recent expected event. + foreach (var e in events) + { + if (e.EventType == DownloadHistoryEventType.DownloadGrabbed) + { + return e; + } + + if (e.EventType == DownloadHistoryEventType.DownloadImported) + { + return e; + } + + if (e.EventType == DownloadHistoryEventType.DownloadFailed) + { + return e; + } + } + + return null; + } + + public void Handle(EpisodeGrabbedEvent message) + { + var history = new DownloadHistory + { + EventType = DownloadHistoryEventType.DownloadGrabbed, + SeriesId = message.Episode.Series.Id, + DownloadId = message.DownloadId, + SourceTitle = message.Episode.Release.Title, + Date = DateTime.UtcNow, + Protocol = message.Episode.Release.DownloadProtocol, + IndexerId = message.Episode.Release.IndexerId, + DownloadClientId = message.DownloadClientId, + Release = message.Episode.Release + }; + + history.Data.Add("Indexer", message.Episode.Release.Indexer); + history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("DownloadClientName", message.DownloadClientName); + history.Data.Add("PreferredWordScore", message.Episode.PreferredWordScore.ToString()); + + _repository.Insert(history); + } + + public void Handle(EpisodeImportedEvent message) + { + if (!message.NewDownload) + { + return; + } + + var downloadId = message.DownloadId; + + // Try to find the downloadId if the user used manual import (from wanted: missing) or the + // API to import and downloadId wasn't provided. + + if (downloadId.IsNullOrWhiteSpace()) + { + downloadId = _historyService.FindDownloadId(message); + } + + if (downloadId.IsNullOrWhiteSpace()) + { + return; + } + + var history = new DownloadHistory + { + EventType = DownloadHistoryEventType.FileImported, + SeriesId = message.EpisodeInfo.Series.Id, + DownloadId = downloadId, + SourceTitle = message.EpisodeInfo.Path, + Date = DateTime.UtcNow, + Protocol = message.DownloadClientInfo.Protocol, + DownloadClientId = message.DownloadClientInfo.Id + }; + + history.Data.Add("DownloadClient", message.DownloadClientInfo.Type); + history.Data.Add("DownloadClientName", message.DownloadClientInfo.Name); + history.Data.Add("SourcePath", message.EpisodeInfo.Path); + history.Data.Add("DestinationPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath)); + + _repository.Insert(history); + } + + public void Handle(DownloadCompletedEvent message) + { + var history = new DownloadHistory + { + EventType = DownloadHistoryEventType.DownloadImported, + SeriesId = message.TrackedDownload.RemoteEpisode.Series.Id, + DownloadId = message.TrackedDownload.DownloadItem.DownloadId, + SourceTitle = message.TrackedDownload.DownloadItem.OutputPath.ToString(), + Date = DateTime.UtcNow, + Protocol = message.TrackedDownload.Protocol, + DownloadClientId = message.TrackedDownload.DownloadClient + }; + + history.Data.Add("DownloadClient", message.TrackedDownload.DownloadItem.DownloadClientInfo.Type); + history.Data.Add("DownloadClientName", message.TrackedDownload.DownloadItem.DownloadClientInfo.Name); + + _repository.Insert(history); + } + + public void Handle(DownloadFailedEvent message) + { + // Don't track failed download for an unknown download + if (message.TrackedDownload == null) + { + return; + } + + var history = new DownloadHistory + { + EventType = DownloadHistoryEventType.DownloadFailed, + SeriesId = message.SeriesId, + DownloadId = message.DownloadId, + SourceTitle = message.SourceTitle, + Date = DateTime.UtcNow, + Protocol = message.TrackedDownload.Protocol, + DownloadClientId = message.TrackedDownload.DownloadClient + }; + + history.Data.Add("DownloadClient", message.TrackedDownload.DownloadItem.DownloadClientInfo.Type); + history.Data.Add("DownloadClientName", message.TrackedDownload.DownloadItem.DownloadClientInfo.Name); + + _repository.Insert(history); + } + + public void Handle(DownloadIgnoredEvent message) + { + var history = new DownloadHistory + { + EventType = DownloadHistoryEventType.DownloadIgnored, + SeriesId = message.SeriesId, + DownloadId = message.DownloadId, + SourceTitle = message.SourceTitle, + Date = DateTime.UtcNow, + Protocol = message.DownloadClientInfo.Protocol, + DownloadClientId = message.DownloadClientInfo.Id + }; + + history.Data.Add("DownloadClient", message.DownloadClientInfo.Type); + history.Data.Add("DownloadClientName", message.DownloadClientInfo.Name); + + _repository.Insert(history); + } + + public void Handle(SeriesDeletedEvent message) + { + _repository.DeleteBySeriesId(message.Series.Id); + } + } +} diff --git a/src/NzbDrone.Core/Download/IDownloadClient.cs b/src/NzbDrone.Core/Download/IDownloadClient.cs index e5b75b3c2..f396b7c34 100644 --- a/src/NzbDrone.Core/Download/IDownloadClient.cs +++ b/src/NzbDrone.Core/Download/IDownloadClient.cs @@ -8,7 +8,6 @@ namespace NzbDrone.Core.Download public interface IDownloadClient : IProvider { DownloadProtocol Protocol { get; } - string Download(RemoteEpisode remoteEpisode); IEnumerable GetItems(); void RemoveItem(string downloadId, bool deleteData); diff --git a/src/NzbDrone.Core/Download/IgnoredDownloadService.cs b/src/NzbDrone.Core/Download/IgnoredDownloadService.cs index 76bc1c69c..b06b1637b 100644 --- a/src/NzbDrone.Core/Download/IgnoredDownloadService.cs +++ b/src/NzbDrone.Core/Download/IgnoredDownloadService.cs @@ -41,7 +41,7 @@ namespace NzbDrone.Core.Download Language = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Language, Quality = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Quality, SourceTitle = trackedDownload.DownloadItem.Title, - DownloadClient = trackedDownload.DownloadItem.DownloadClient, + DownloadClientInfo = trackedDownload.DownloadItem.DownloadClientInfo, DownloadId = trackedDownload.DownloadItem.DownloadId, Message = "Manually ignored" }; diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadAlreadyImported.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadAlreadyImported.cs index 6375d064e..c5bc47107 100644 --- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadAlreadyImported.cs +++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadAlreadyImported.cs @@ -7,12 +7,12 @@ namespace NzbDrone.Core.Download.TrackedDownloads { public interface ITrackedDownloadAlreadyImported { - bool IsImported(TrackedDownload trackedDownload, List historyItems); + bool IsImported(TrackedDownload trackedDownload, List historyItems); } public class TrackedDownloadAlreadyImported : ITrackedDownloadAlreadyImported { - public bool IsImported(TrackedDownload trackedDownload, List historyItems) + public bool IsImported(TrackedDownload trackedDownload, List historyItems) { if (historyItems.Empty()) { @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads return false; } - return lastHistoryItem.EventType == HistoryEventType.DownloadFolderImported; + return lastHistoryItem.EventType == EpisodeHistoryEventType.DownloadFolderImported; }); return allEpisodesImportedInHistory; diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs index 92d6a60fa..5065c5f68 100644 --- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs +++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs @@ -4,6 +4,7 @@ using System.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Download.History; using NzbDrone.Core.History; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser; @@ -25,7 +26,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads private readonly IParsingService _parsingService; private readonly IHistoryService _historyService; private readonly IEventAggregator _eventAggregator; - private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported; + private readonly IDownloadHistoryService _downloadHistoryService; private readonly Logger _logger; private readonly ICached _cache; @@ -33,13 +34,13 @@ namespace NzbDrone.Core.Download.TrackedDownloads ICacheManager cacheManager, IHistoryService historyService, IEventAggregator eventAggregator, - ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported, + IDownloadHistoryService downloadHistoryService, Logger logger) { _parsingService = parsingService; _historyService = historyService; _eventAggregator = eventAggregator; - _trackedDownloadAlreadyImported = trackedDownloadAlreadyImported; + _downloadHistoryService = downloadHistoryService; _cache = cacheManager.GetCache(GetType()); _logger = logger; } @@ -105,34 +106,19 @@ namespace NzbDrone.Core.Download.TrackedDownloads trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } + var downloadHistory = _downloadHistoryService.GetLatestDownloadHistoryItem(downloadItem.DownloadId); + + if (downloadHistory != null) + { + var state = GetStateFromHistory(downloadHistory.EventType); + trackedDownload.State = state; + } + if (historyItems.Any()) { var firstHistoryItem = historyItems.First(); - var state = GetStateFromHistory(firstHistoryItem.EventType); + var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EpisodeHistoryEventType.Grabbed); - trackedDownload.State = state; - - // TODO: Restore check to confirm all files were imported - // This will treat partially imported downloads as imported (as it was before), which means a partially imported download after a - // restart will get marked as imported without importing the restart of the files. - - // One potential issue here is if the latest is imported, but other episodes are ignored or never imported. - // It's unlikely that will happen, but could happen if additional episodes are added to season after it's already imported. - -// if (state == TrackedDownloadState.Imported) -// { -// trackedDownload.State = TrackedDownloadState.Imported; -// -// var allImported = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems); -// -// trackedDownload.State = allImported ? TrackedDownloadState.Imported : TrackedDownloadState.Downloading; -// } -// else -// { -// trackedDownload.State = state; -// } - - var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == HistoryEventType.Grabbed); trackedDownload.Indexer = grabbedEvent?.Data["indexer"]; if (parsedEpisodeInfo == null || @@ -146,7 +132,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads if (parsedEpisodeInfo != null) { - trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); + trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == EpisodeHistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } @@ -192,7 +178,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads existingItem.CanMoveFiles != downloadItem.CanMoveFiles) { _logger.Debug("Tracking '{0}:{1}': ClientState={2}{3} SonarrStage={4} Episode='{5}' OutputPath={6}.", - downloadItem.DownloadClient, downloadItem.Title, + downloadItem.DownloadClientInfo.Name, downloadItem.Title, downloadItem.Status, downloadItem.CanBeRemoved ? "" : downloadItem.CanMoveFiles ? " (busy)" : " (readonly)", trackedDownload.State, @@ -201,15 +187,15 @@ namespace NzbDrone.Core.Download.TrackedDownloads } } - private static TrackedDownloadState GetStateFromHistory(HistoryEventType eventType) + private static TrackedDownloadState GetStateFromHistory(DownloadHistoryEventType eventType) { switch (eventType) { - case HistoryEventType.DownloadFolderImported: + case DownloadHistoryEventType.DownloadImported: return TrackedDownloadState.Imported; - case HistoryEventType.DownloadFailed: + case DownloadHistoryEventType.DownloadFailed: return TrackedDownloadState.Failed; - case HistoryEventType.DownloadIgnored: + case DownloadHistoryEventType.DownloadIgnored: return TrackedDownloadState.Ignored; default: return TrackedDownloadState.Downloading; diff --git a/src/NzbDrone.Core/History/History.cs b/src/NzbDrone.Core/History/EpisodeHistory.cs similarity index 85% rename from src/NzbDrone.Core/History/History.cs rename to src/NzbDrone.Core/History/EpisodeHistory.cs index 3cd630130..933e05d7e 100644 --- a/src/NzbDrone.Core/History/History.cs +++ b/src/NzbDrone.Core/History/EpisodeHistory.cs @@ -7,11 +7,11 @@ using NzbDrone.Core.Languages; namespace NzbDrone.Core.History { - public class History : ModelBase + public class EpisodeHistory : ModelBase { public const string DOWNLOAD_CLIENT = "downloadClient"; - public History() + public EpisodeHistory() { Data = new Dictionary(); } @@ -23,7 +23,7 @@ namespace NzbDrone.Core.History public DateTime Date { get; set; } public Episode Episode { get; set; } public Series Series { get; set; } - public HistoryEventType EventType { get; set; } + public EpisodeHistoryEventType EventType { get; set; } public Dictionary Data { get; set; } public Language Language { get; set; } @@ -31,7 +31,7 @@ namespace NzbDrone.Core.History } - public enum HistoryEventType + public enum EpisodeHistoryEventType { Unknown = 0, Grabbed = 1, diff --git a/src/NzbDrone.Core/History/HistoryRepository.cs b/src/NzbDrone.Core/History/HistoryRepository.cs index a7ca651e6..11b6c9153 100644 --- a/src/NzbDrone.Core/History/HistoryRepository.cs +++ b/src/NzbDrone.Core/History/HistoryRepository.cs @@ -9,20 +9,20 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Core.History { - public interface IHistoryRepository : IBasicRepository + public interface IHistoryRepository : IBasicRepository { - History MostRecentForEpisode(int episodeId); - List FindByEpisodeId(int episodeId); - History MostRecentForDownloadId(string downloadId); - List FindByDownloadId(string downloadId); - List GetBySeries(int seriesId, HistoryEventType? eventType); - List GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType); - List FindDownloadHistory(int idSeriesId, QualityModel quality); + EpisodeHistory MostRecentForEpisode(int episodeId); + List FindByEpisodeId(int episodeId); + EpisodeHistory MostRecentForDownloadId(string downloadId); + List FindByDownloadId(string downloadId); + List GetBySeries(int seriesId, EpisodeHistoryEventType? eventType); + List GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType); + List FindDownloadHistory(int idSeriesId, QualityModel quality); void DeleteForSeries(int seriesId); - List Since(DateTime date, HistoryEventType? eventType); + List Since(DateTime date, EpisodeHistoryEventType? eventType); } - public class HistoryRepository : BasicRepository, IHistoryRepository + public class HistoryRepository : BasicRepository, IHistoryRepository { public HistoryRepository(IMainDatabase database, IEventAggregator eventAggregator) @@ -30,33 +30,33 @@ namespace NzbDrone.Core.History { } - public History MostRecentForEpisode(int episodeId) + public EpisodeHistory MostRecentForEpisode(int episodeId) { return Query.Where(h => h.EpisodeId == episodeId) .OrderByDescending(h => h.Date) .FirstOrDefault(); } - public List FindByEpisodeId(int episodeId) + public List FindByEpisodeId(int episodeId) { return Query.Where(h => h.EpisodeId == episodeId) .OrderByDescending(h => h.Date) .ToList(); } - public History MostRecentForDownloadId(string downloadId) + public EpisodeHistory MostRecentForDownloadId(string downloadId) { return Query.Where(h => h.DownloadId == downloadId) .OrderByDescending(h => h.Date) .FirstOrDefault(); } - public List FindByDownloadId(string downloadId) + public List FindByDownloadId(string downloadId) { return Query.Where(h => h.DownloadId == downloadId); } - public List GetBySeries(int seriesId, HistoryEventType? eventType) + public List GetBySeries(int seriesId, EpisodeHistoryEventType? eventType) { var query = Query.Where(h => h.SeriesId == seriesId); @@ -68,9 +68,9 @@ namespace NzbDrone.Core.History return query.OrderByDescending(h => h.Date).ToList(); } - public List GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType) + public List GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType) { - var query = Query.Join(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id) + var query = Query.Join(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id) .Where(h => h.SeriesId == seriesId) .AndWhere(h => h.Episode.SeasonNumber == seasonNumber); @@ -84,14 +84,14 @@ namespace NzbDrone.Core.History return query; } - public List FindDownloadHistory(int idSeriesId, QualityModel quality) + public List FindDownloadHistory(int idSeriesId, QualityModel quality) { return Query.Where(h => h.SeriesId == idSeriesId && h.Quality == quality && - (h.EventType == HistoryEventType.Grabbed || - h.EventType == HistoryEventType.DownloadFailed || - h.EventType == HistoryEventType.DownloadFolderImported) + (h.EventType == EpisodeHistoryEventType.Grabbed || + h.EventType == EpisodeHistoryEventType.DownloadFailed || + h.EventType == EpisodeHistoryEventType.DownloadFolderImported) ).ToList(); } @@ -100,15 +100,15 @@ namespace NzbDrone.Core.History Delete(c => c.SeriesId == seriesId); } - protected override SortBuilder GetPagedQuery(QueryBuilder query, PagingSpec pagingSpec) + protected override SortBuilder GetPagedQuery(QueryBuilder query, PagingSpec pagingSpec) { - var baseQuery = query.Join(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) - .Join(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id); + var baseQuery = query.Join(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) + .Join(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id); return base.GetPagedQuery(baseQuery, pagingSpec); } - public List Since(DateTime date, HistoryEventType? eventType) + public List Since(DateTime date, EpisodeHistoryEventType? eventType) { var query = Query.Where(h => h.Date >= date); diff --git a/src/NzbDrone.Core/History/HistoryService.cs b/src/NzbDrone.Core/History/HistoryService.cs index dd80a139e..933fb309f 100644 --- a/src/NzbDrone.Core/History/HistoryService.cs +++ b/src/NzbDrone.Core/History/HistoryService.cs @@ -16,16 +16,17 @@ namespace NzbDrone.Core.History { public interface IHistoryService { - PagingSpec Paged(PagingSpec pagingSpec); - History MostRecentForEpisode(int episodeId); - List FindByEpisodeId(int episodeId); - History MostRecentForDownloadId(string downloadId); - History Get(int historyId); - List GetBySeries(int seriesId, HistoryEventType? eventType); - List GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType); - List Find(string downloadId, HistoryEventType eventType); - List FindByDownloadId(string downloadId); - List Since(DateTime date, HistoryEventType? eventType); + PagingSpec Paged(PagingSpec pagingSpec); + EpisodeHistory MostRecentForEpisode(int episodeId); + List FindByEpisodeId(int episodeId); + EpisodeHistory MostRecentForDownloadId(string downloadId); + EpisodeHistory Get(int historyId); + List GetBySeries(int seriesId, EpisodeHistoryEventType? eventType); + List GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType); + List Find(string downloadId, EpisodeHistoryEventType eventType); + List FindByDownloadId(string downloadId); + string FindDownloadId(EpisodeImportedEvent trackedDownload); + List Since(DateTime date, EpisodeHistoryEventType? eventType); } public class HistoryService : IHistoryService, @@ -46,68 +47,66 @@ namespace NzbDrone.Core.History _logger = logger; } - public PagingSpec Paged(PagingSpec pagingSpec) + public PagingSpec Paged(PagingSpec pagingSpec) { return _historyRepository.GetPaged(pagingSpec); } - public History MostRecentForEpisode(int episodeId) + public EpisodeHistory MostRecentForEpisode(int episodeId) { return _historyRepository.MostRecentForEpisode(episodeId); } - public List FindByEpisodeId(int episodeId) + public List FindByEpisodeId(int episodeId) { return _historyRepository.FindByEpisodeId(episodeId); } - public History MostRecentForDownloadId(string downloadId) + public EpisodeHistory MostRecentForDownloadId(string downloadId) { return _historyRepository.MostRecentForDownloadId(downloadId); } - public History Get(int historyId) + public EpisodeHistory Get(int historyId) { return _historyRepository.Get(historyId); } - public List GetBySeries(int seriesId, HistoryEventType? eventType) + public List GetBySeries(int seriesId, EpisodeHistoryEventType? eventType) { return _historyRepository.GetBySeries(seriesId, eventType); } - public List GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType) + public List GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType) { return _historyRepository.GetBySeason(seriesId, seasonNumber, eventType); } - public List Find(string downloadId, HistoryEventType eventType) + public List Find(string downloadId, EpisodeHistoryEventType eventType) { return _historyRepository.FindByDownloadId(downloadId).Where(c => c.EventType == eventType).ToList(); } - public List FindByDownloadId(string downloadId) + public List FindByDownloadId(string downloadId) { return _historyRepository.FindByDownloadId(downloadId); } - private string FindDownloadId(EpisodeImportedEvent trackedDownload) + public string FindDownloadId(EpisodeImportedEvent trackedDownload) { _logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedEpisode.Path); var episodeIds = trackedDownload.EpisodeInfo.Episodes.Select(c => c.Id).ToList(); - var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.EpisodeInfo.Series.Id, trackedDownload.ImportedEpisode.Quality); - - //Find download related items for these episdoes + //Find download related items for these episodes var episodesHistory = allHistory.Where(h => episodeIds.Contains(h.EpisodeId)).ToList(); var processedDownloadId = episodesHistory - .Where(c => c.EventType != HistoryEventType.Grabbed && c.DownloadId != null) + .Where(c => c.EventType != EpisodeHistoryEventType.Grabbed && c.DownloadId != null) .Select(c => c.DownloadId); - var stillDownloading = episodesHistory.Where(c => c.EventType == HistoryEventType.Grabbed && !processedDownloadId.Contains(c.DownloadId)).ToList(); + var stillDownloading = episodesHistory.Where(c => c.EventType == EpisodeHistoryEventType.Grabbed && !processedDownloadId.Contains(c.DownloadId)).ToList(); string downloadId = null; @@ -140,9 +139,9 @@ namespace NzbDrone.Core.History { foreach (var episode in message.Episode.Episodes) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.Grabbed, + EventType = EpisodeHistoryEventType.Grabbed, Date = DateTime.UtcNow, Quality = message.Episode.ParsedEpisodeInfo.Quality, SourceTitle = message.Episode.Release.Title, @@ -160,6 +159,7 @@ namespace NzbDrone.Core.History history.Data.Add("AgeMinutes", message.Episode.Release.AgeMinutes.ToString()); history.Data.Add("PublishedDate", message.Episode.Release.PublishDate.ToString("s") + "Z"); history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("DownloadClientName", message.DownloadClientName); history.Data.Add("Size", message.Episode.Release.Size.ToString()); history.Data.Add("DownloadUrl", message.Episode.Release.DownloadUrl); history.Data.Add("Guid", message.Episode.Release.Guid); @@ -199,9 +199,9 @@ namespace NzbDrone.Core.History foreach (var episode in message.EpisodeInfo.Episodes) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.DownloadFolderImported, + EventType = EpisodeHistoryEventType.DownloadFolderImported, Date = DateTime.UtcNow, Quality = message.EpisodeInfo.Quality, SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path), @@ -215,7 +215,8 @@ namespace NzbDrone.Core.History //history.Data.Add("FileId", message.ImportedEpisode.Id.ToString()); history.Data.Add("DroppedPath", message.EpisodeInfo.Path); history.Data.Add("ImportedPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath)); - history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("DownloadClient", message.DownloadClientInfo?.Type); + history.Data.Add("DownloadClientName", message.DownloadClientInfo?.Name); _historyRepository.Insert(history); } @@ -225,9 +226,9 @@ namespace NzbDrone.Core.History { foreach (var episodeId in message.EpisodeIds) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.DownloadFailed, + EventType = EpisodeHistoryEventType.DownloadFailed, Date = DateTime.UtcNow, Quality = message.Quality, SourceTitle = message.SourceTitle, @@ -238,6 +239,7 @@ namespace NzbDrone.Core.History }; history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("DownloadClientName", message.TrackedDownload?.DownloadItem.DownloadClientInfo.Name); history.Data.Add("Message", message.Message); _historyRepository.Insert(history); @@ -259,9 +261,9 @@ namespace NzbDrone.Core.History foreach (var episode in message.EpisodeFile.Episodes.Value) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.EpisodeFileDeleted, + EventType = EpisodeHistoryEventType.EpisodeFileDeleted, Date = DateTime.UtcNow, Quality = message.EpisodeFile.Quality, SourceTitle = message.EpisodeFile.Path, @@ -284,9 +286,9 @@ namespace NzbDrone.Core.History foreach (var episode in message.EpisodeFile.Episodes.Value) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.EpisodeFileRenamed, + EventType = EpisodeHistoryEventType.EpisodeFileRenamed, Date = DateTime.UtcNow, Quality = message.EpisodeFile.Quality, SourceTitle = message.OriginalPath, @@ -305,13 +307,13 @@ namespace NzbDrone.Core.History public void Handle(DownloadIgnoredEvent message) { - var historyToAdd = new List(); + var historyToAdd = new List(); foreach (var episodeId in message.EpisodeIds) { - var history = new History + var history = new EpisodeHistory { - EventType = HistoryEventType.DownloadIgnored, + EventType = EpisodeHistoryEventType.DownloadIgnored, Date = DateTime.UtcNow, Quality = message.Quality, SourceTitle = message.SourceTitle, @@ -321,7 +323,8 @@ namespace NzbDrone.Core.History Language = message.Language }; - history.Data.Add("DownloadClient", message.DownloadClient); + history.Data.Add("DownloadClient", message.DownloadClientInfo.Type); + history.Data.Add("DownloadClientName", message.DownloadClientInfo.Name); history.Data.Add("Message", message.Message); historyToAdd.Add(history); @@ -335,7 +338,7 @@ namespace NzbDrone.Core.History _historyRepository.DeleteForSeries(message.Series.Id); } - public List Since(DateTime date, HistoryEventType? eventType) + public List Since(DateTime date, EpisodeHistoryEventType? eventType) { return _historyRepository.Since(date, eventType); } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/AlreadyImportedSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/AlreadyImportedSpecification.cs index 0641e8cab..3333174e0 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/AlreadyImportedSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/AlreadyImportedSpecification.cs @@ -39,8 +39,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications } var episodeHistory = _historyService.FindByEpisodeId(episode.Id); - var lastImported = episodeHistory.FirstOrDefault(h => h.EventType == HistoryEventType.DownloadFolderImported); - var lastGrabbed = episodeHistory.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed); + var lastImported = episodeHistory.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.DownloadFolderImported); + var lastGrabbed = episodeHistory.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.Grabbed); if (lastImported == null) { diff --git a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportFailedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportFailedEvent.cs index 7a85ff891..06d2e4baf 100644 --- a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportFailedEvent.cs +++ b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportFailedEvent.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.MediaFiles.Events public Exception Exception { get; set; } public LocalEpisode EpisodeInfo { get; } public bool NewDownload { get; } - public string DownloadClient { get; } + public DownloadClientItemClientInfo DownloadClientInfo { get; } public string DownloadId { get; } public EpisodeImportFailedEvent(Exception exception, LocalEpisode episodeInfo, bool newDownload, DownloadClientItem downloadClientItem) @@ -21,7 +21,7 @@ namespace NzbDrone.Core.MediaFiles.Events if (downloadClientItem != null) { - DownloadClient = downloadClientItem.DownloadClient; + DownloadClientInfo = downloadClientItem.DownloadClientInfo; DownloadId = downloadClientItem.DownloadId; } } diff --git a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs index 7c870666b..c4de50f9a 100644 --- a/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs +++ b/src/NzbDrone.Core/MediaFiles/Events/EpisodeImportedEvent.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.MediaFiles.Events public EpisodeFile ImportedEpisode { get; private set; } public List OldFiles { get; private set; } public bool NewDownload { get; private set; } - public string DownloadClient { get; private set; } + public DownloadClientItemClientInfo DownloadClientInfo { get; set; } public string DownloadId { get; private set; } public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, List oldFiles, bool newDownload, DownloadClientItem downloadClientItem) @@ -23,7 +23,7 @@ namespace NzbDrone.Core.MediaFiles.Events if (downloadClientItem != null) { - DownloadClient = downloadClientItem.DownloadClient; + DownloadClientInfo = downloadClientItem.DownloadClientInfo; DownloadId = downloadClientItem.DownloadId; } } diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 3e6cfc354..64d44261a 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -143,7 +143,7 @@ namespace NzbDrone.Core.Notifications EpisodeFile = message.ImportedEpisode, OldFiles = message.OldFiles, SourcePath = message.EpisodeInfo.Path, - DownloadClient = message.DownloadClient, + DownloadClient = message.DownloadClientInfo?.Name, DownloadId = message.DownloadId }; diff --git a/src/NzbDrone.Core/Queue/QueueService.cs b/src/NzbDrone.Core/Queue/QueueService.cs index 66edf83dc..5b3342e2a 100644 --- a/src/NzbDrone.Core/Queue/QueueService.cs +++ b/src/NzbDrone.Core/Queue/QueueService.cs @@ -77,7 +77,7 @@ namespace NzbDrone.Core.Queue RemoteEpisode = trackedDownload.RemoteEpisode, DownloadId = trackedDownload.DownloadItem.DownloadId, Protocol = trackedDownload.Protocol, - DownloadClient = trackedDownload.DownloadItem.DownloadClient, + DownloadClient = trackedDownload.DownloadItem.DownloadClientInfo.Name, Indexer = trackedDownload.Indexer, OutputPath = trackedDownload.DownloadItem.OutputPath.ToString() }; diff --git a/src/Sonarr.Api.V3/History/HistoryModule.cs b/src/Sonarr.Api.V3/History/HistoryModule.cs index 6c8495806..59e5b5389 100644 --- a/src/Sonarr.Api.V3/History/HistoryModule.cs +++ b/src/Sonarr.Api.V3/History/HistoryModule.cs @@ -35,7 +35,7 @@ namespace Sonarr.Api.V3.History Post("/failed", x => MarkAsFailed()); } - protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeSeries, bool includeEpisode) + protected HistoryResource MapToResource(EpisodeHistory model, bool includeSeries, bool includeEpisode) { var resource = model.ToResource(); @@ -60,7 +60,7 @@ namespace Sonarr.Api.V3.History private PagingResource GetHistory(PagingResource pagingResource) { - var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); + var pagingSpec = pagingResource.MapToPagingSpec("date", SortDirection.Descending); var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); @@ -70,7 +70,7 @@ namespace Sonarr.Api.V3.History if (eventTypeFilter != null) { - var filterValue = (HistoryEventType)Convert.ToInt32(eventTypeFilter.Value); + var filterValue = (EpisodeHistoryEventType)Convert.ToInt32(eventTypeFilter.Value); pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue); } @@ -100,13 +100,13 @@ namespace Sonarr.Api.V3.History } DateTime date = DateTime.Parse(queryDate.Value); - HistoryEventType? eventType = null; + EpisodeHistoryEventType? eventType = null; var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); if (queryEventType.HasValue) { - eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); + eventType = (EpisodeHistoryEventType)Convert.ToInt32(queryEventType.Value); } return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeSeries, includeEpisode)).ToList(); @@ -124,13 +124,13 @@ namespace Sonarr.Api.V3.History } int seriesId = Convert.ToInt32(querySeriesId.Value); - HistoryEventType? eventType = null; + EpisodeHistoryEventType? eventType = null; var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); if (queryEventType.HasValue) { - eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); + eventType = (EpisodeHistoryEventType)Convert.ToInt32(queryEventType.Value); } if (querySeasonNumber.HasValue) diff --git a/src/Sonarr.Api.V3/History/HistoryResource.cs b/src/Sonarr.Api.V3/History/HistoryResource.cs index 3bfae7090..467ab4b20 100644 --- a/src/Sonarr.Api.V3/History/HistoryResource.cs +++ b/src/Sonarr.Api.V3/History/HistoryResource.cs @@ -21,7 +21,7 @@ namespace Sonarr.Api.V3.History public DateTime Date { get; set; } public string DownloadId { get; set; } - public HistoryEventType EventType { get; set; } + public EpisodeHistoryEventType EventType { get; set; } public Dictionary Data { get; set; } @@ -31,7 +31,7 @@ namespace Sonarr.Api.V3.History public static class HistoryResourceMapper { - public static HistoryResource ToResource(this NzbDrone.Core.History.History model) + public static HistoryResource ToResource(this EpisodeHistory model) { if (model == null) return null;