Track fully imported downloads in separate history table

New: Improved detection of already imported downloads
Closes #3554
This commit is contained in:
Mark McDowall 2020-03-03 18:09:29 -08:00 committed by Mark McDowall
parent 576275b6da
commit 770b89c2b3
59 changed files with 688 additions and 258 deletions

View File

@ -32,7 +32,7 @@ namespace NzbDrone.Api.History
Post("/failed", x => MarkAsFailed()); Post("/failed", x => MarkAsFailed());
} }
protected HistoryResource MapToResource(Core.History.History model) protected HistoryResource MapToResource(EpisodeHistory model)
{ {
var resource = model.ToResource(); var resource = model.ToResource();
@ -50,12 +50,12 @@ namespace NzbDrone.Api.History
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource) private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
{ {
var episodeId = Request.Query.EpisodeId; var episodeId = Request.Query.EpisodeId;
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending); var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, EpisodeHistory>("date", SortDirection.Descending);
var filter = pagingResource.Filters.FirstOrDefault(); var filter = pagingResource.Filters.FirstOrDefault();
if (filter != null && filter.Key == "eventType") 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); pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
} }
@ -79,11 +79,11 @@ namespace NzbDrone.Api.History
} }
DateTime date = DateTime.Parse(queryDate.Value); DateTime date = DateTime.Parse(queryDate.Value);
HistoryEventType? eventType = null; EpisodeHistoryEventType? eventType = null;
if (queryEventType.HasValue) if (queryEventType.HasValue)
{ {
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); eventType = (EpisodeHistoryEventType)Convert.ToInt32(queryEventType.Value);
} }
return _historyService.Since(date, eventType).Select(MapToResource).ToList(); return _historyService.Since(date, eventType).Select(MapToResource).ToList();

View File

@ -20,7 +20,7 @@ namespace NzbDrone.Api.History
public string DownloadId { get; set; } public string DownloadId { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public HistoryEventType EventType { get; set; } public EpisodeHistoryEventType EventType { get; set; }
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
@ -30,7 +30,7 @@ namespace NzbDrone.Api.History
public static class HistoryResourceMapper 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; if (model == null) return null;

View File

@ -2,6 +2,7 @@
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; 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 quality = new QualityModel { Quality = Quality.Bluray720p, Revision = new Revision(version: 2 )};
var history = Builder<History.History>.CreateNew() var history = Builder<EpisodeHistory>.CreateNew()
.With(c => c.Id = 0) .With(c => c.Id = 0)
.With(c => c.Quality = quality) .With(c => c.Quality = quality)
.Build(); .Build();
Db.Insert(history); Db.Insert(history);
var loadedQuality = Db.Single<History.History>().Quality; var loadedQuality = Db.Single<EpisodeHistory>().Quality;
loadedQuality.Should().Be(quality); loadedQuality.Should().Be(quality);
} }
[Test] [Test]
public void embedded_list_of_document_with_json() public void embedded_list_of_document_with_json()
{ {
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<EpisodeHistory>.CreateListOfSize(2)
.All().With(c => c.Id = 0) .All().With(c => c.Id = 0)
.Build().ToList(); .Build().ToList();
@ -83,7 +84,7 @@ namespace NzbDrone.Core.Test.Datastore
Db.InsertMany(history); Db.InsertMany(history);
var returnedHistory = Db.All<History.History>(); var returnedHistory = Db.All<EpisodeHistory>();
returnedHistory[0].Quality.Quality.Should().Be(Quality.HDTV1080p); returnedHistory[0].Quality.Quality.Should().Be(Quality.HDTV1080p);
} }

View File

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private QualityModel _hdtv720p; private QualityModel _hdtv720p;
private QualityModel _hdtv1080p; private QualityModel _hdtv1080p;
private RemoteEpisode _remoteEpisode; private RemoteEpisode _remoteEpisode;
private List<History.History> _history; private List<EpisodeHistory> _history;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Build() .Build()
}; };
_history = new List<History.History>(); _history = new List<EpisodeHistory>();
Mocker.GetMock<IConfigService>() Mocker.GetMock<IConfigService>()
.SetupGet(s => s.EnableCompletedDownloadHandling) .SetupGet(s => s.EnableCompletedDownloadHandling)
@ -75,9 +75,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(false); .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, DownloadId = downloadId,
SourceTitle = sourceTitle, SourceTitle = sourceTitle,
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_be_accepted_if_episode_does_not_have_imported_event() 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(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
@ -122,8 +122,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
var downloadId = Guid.NewGuid().ToString().ToUpper(); var downloadId = Guid.NewGuid().ToString().ToUpper();
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed);
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.DownloadFolderImported); GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.DownloadFolderImported);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
@ -133,8 +133,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
var downloadId = Guid.NewGuid().ToString().ToUpper(); var downloadId = Guid.NewGuid().ToString().ToUpper();
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed);
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported);
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew() _remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent) .With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
@ -149,8 +149,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
var downloadId = Guid.NewGuid().ToString().ToUpper(); var downloadId = Guid.NewGuid().ToString().ToUpper();
GivenHistoryItem(null, TITLE, _hdtv720p, HistoryEventType.Grabbed); GivenHistoryItem(null, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed);
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported);
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew() _remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent) .With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
@ -165,8 +165,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
var downloadId = Guid.NewGuid().ToString().ToUpper(); var downloadId = Guid.NewGuid().ToString().ToUpper();
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed);
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported);
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew() _remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent) .With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
@ -181,8 +181,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
var downloadId = Guid.NewGuid().ToString().ToUpper(); var downloadId = Guid.NewGuid().ToString().ToUpper();
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed); GivenHistoryItem(downloadId, TITLE, _hdtv720p, EpisodeHistoryEventType.Grabbed);
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported); GivenHistoryItem(downloadId, TITLE, _hdtv1080p, EpisodeHistoryEventType.DownloadFolderImported);
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew() _remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent) .With(t => t.DownloadProtocol = DownloadProtocol.Torrent)

View File

@ -84,10 +84,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
.Returns(true); .Returns(true);
} }
private void GivenMostRecentForEpisode(int episodeId, string downloadId, Tuple<QualityModel, Language> quality, DateTime date, HistoryEventType eventType) private void GivenMostRecentForEpisode(int episodeId, string downloadId, Tuple<QualityModel, Language> quality, DateTime date, EpisodeHistoryEventType eventType)
{ {
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(episodeId)) Mocker.GetMock<IHistoryService>().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() private void GivenCdhDisabled()
@ -106,14 +106,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_true_if_latest_history_item_is_null() public void should_return_true_if_latest_history_item_is_null()
{ {
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(It.IsAny<int>())).Returns((History.History)null); Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForEpisode(It.IsAny<int>())).Returns((EpisodeHistory)null);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_return_true_if_latest_history_item_is_not_grabbed() 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(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
@ -127,46 +127,46 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_true_if_latest_history_item_is_older_than_twelve_hours() 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(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_upgradable_if_only_episode_is_upgradable() 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(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_be_upgradable_if_both_episodes_are_upgradable() public void should_be_upgradable_if_both_episodes_are_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_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, HistoryEventType.Grabbed); GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
} }
[Test] [Test]
public void should_not_be_upgradable_if_both_episodes_are_not_upgradable() public void should_not_be_upgradable_if_both_episodes_are_not_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_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, HistoryEventType.Grabbed); GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_first_episodes_is_upgradable() 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, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed);
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
} }
[Test] [Test]
public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() public void should_be_not_upgradable_if_only_second_episodes_is_upgradable()
{ {
GivenMostRecentForEpisode(FIRST_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, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EpisodeHistoryEventType.Grabbed);
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); _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)); _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English); _upgradableQuality = new Tuple<QualityModel, Language>(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(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
@ -190,7 +190,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
_parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish; _parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish;
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English); _upgradableQuality = new Tuple<QualityModel, Language>(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(); _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)); _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish); _upgradableQuality = new Tuple<QualityModel, Language>(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(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
@ -210,7 +210,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_return_false_if_latest_history_item_is_only_one_hour_old() 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(); _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() public void should_return_false_if_latest_history_has_a_download_id_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); 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(); _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)); _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 1));
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish); _upgradableQuality = new Tuple<QualityModel, Language>(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(); _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() public void should_return_false_if_only_episode_is_not_upgradable_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); 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(); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
} }
} }

View File

@ -59,7 +59,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
.Returns(new History.History()); .Returns(new EpisodeHistory());
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetSeries("Drone.S01E01.HDTV")) .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 _trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.MostRecentForDownloadId(It.Is<string>(i => i == "1234"))) .Setup(s => s.MostRecentForDownloadId(It.Is<string>(i => i == "1234")))
.Returns(new History.History() { SourceTitle = "Droned S01E01" }); .Returns(new EpisodeHistory() { SourceTitle = "Droned S01E01" });
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetSeries(It.IsAny<string>())) .Setup(s => s.GetSeries(It.IsAny<string>()))
@ -187,7 +187,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.IsAny<string>())) .Setup(s => s.FindByDownloadId(It.IsAny<string>()))
.Returns(new List<History.History>()); .Returns(new List<EpisodeHistory>());
Subject.Import(_trackedDownload); 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") new ImportResult(new ImportDecision(new LocalEpisode{Path = @"C:\TestPath\Droned.S01E01.mkv"}),"Test Failure")
}); });
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<EpisodeHistory>.CreateListOfSize(2)
.BuildList(); .BuildList();
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
@ -274,7 +274,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
new LocalEpisode {Path = @"C:\TestPath\Droned.S01E02.mkv", Episodes = new List<Episode> { episode2 } }),"Test Failure") new LocalEpisode {Path = @"C:\TestPath\Droned.S01E02.mkv", Episodes = new List<Episode> { episode2 } }),"Test Failure")
}); });
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<EpisodeHistory>.CreateListOfSize(2)
.BuildList(); .BuildList();
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
@ -282,7 +282,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
.Returns(history); .Returns(history);
Mocker.GetMock<ITrackedDownloadAlreadyImported>() Mocker.GetMock<ITrackedDownloadAlreadyImported>()
.Setup(s => s.IsImported(It.IsAny<TrackedDownload>(), It.IsAny<List<History.History>>())) .Setup(s => s.IsImported(It.IsAny<TrackedDownload>(), It.IsAny<List<EpisodeHistory>>()))
.Returns(true); .Returns(true);
Subject.Import(_trackedDownload); Subject.Import(_trackedDownload);

View File

@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
.Returns(new History.History()); .Returns(new EpisodeHistory());
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetSeries("Drone.S01E01.HDTV")) .Setup(s => s.GetSeries("Drone.S01E01.HDTV"))
@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
{ {
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId)) .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
.Returns((History.History)null); .Returns((EpisodeHistory)null);
} }
private void GivenSeriesMatch() private void GivenSeriesMatch()
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
_trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download _trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.MostRecentForDownloadId(It.Is<string>(i => i == "1234"))) .Setup(s => s.MostRecentForDownloadId(It.Is<string>(i => i == "1234")))
.Returns(new History.History() { SourceTitle = "Droned S01E01" }); .Returns(new EpisodeHistory() { SourceTitle = "Droned S01E01" });
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(s => s.GetSeries(It.IsAny<string>())) .Setup(s => s.GetSeries(It.IsAny<string>()))

View File

@ -62,7 +62,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
protected void VerifyIdentifiable(DownloadClientItem downloadClientItem) 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.DownloadId.Should().NotBeNullOrEmpty();
downloadClientItem.Title.Should().NotBeNullOrEmpty(); downloadClientItem.Title.Should().NotBeNullOrEmpty();
} }

View File

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
public class ProcessFailedFixture : CoreTest<FailedDownloadService> public class ProcessFailedFixture : CoreTest<FailedDownloadService>
{ {
private TrackedDownload _trackedDownload; private TrackedDownload _trackedDownload;
private List<History.History> _grabHistory; private List<EpisodeHistory> _grabHistory;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
.With(h => h.Title = "Drone.S01E01.HDTV") .With(h => h.Title = "Drone.S01E01.HDTV")
.Build(); .Build();
_grabHistory = Builder<History.History>.CreateListOfSize(2).BuildList(); _grabHistory = Builder<EpisodeHistory>.CreateListOfSize(2).BuildList();
var remoteEpisode = new RemoteEpisode var remoteEpisode = new RemoteEpisode
{ {
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed))
.Returns(_grabHistory); .Returns(_grabHistory);
} }

View File

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
public class ProcessFixture : CoreTest<FailedDownloadService> public class ProcessFixture : CoreTest<FailedDownloadService>
{ {
private TrackedDownload _trackedDownload; private TrackedDownload _trackedDownload;
private List<History.History> _grabHistory; private List<EpisodeHistory> _grabHistory;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
.With(h => h.Title = "Drone.S01E01.HDTV") .With(h => h.Title = "Drone.S01E01.HDTV")
.Build(); .Build();
_grabHistory = Builder<History.History>.CreateListOfSize(2).BuildList(); _grabHistory = Builder<EpisodeHistory>.CreateListOfSize(2).BuildList();
var remoteEpisode = new RemoteEpisode var remoteEpisode = new RemoteEpisode
{ {
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed))
.Returns(_grabHistory); .Returns(_grabHistory);
} }
@ -54,8 +54,8 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
private void GivenNoGrabbedHistory() private void GivenNoGrabbedHistory()
{ {
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed)) .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed))
.Returns(new List<History.History>()); .Returns(new List<EpisodeHistory>());
} }
[Test] [Test]

View File

@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
private List<Episode> _episodes; private List<Episode> _episodes;
private TrackedDownload _trackedDownload; private TrackedDownload _trackedDownload;
private List<History.History> _historyItems; private List<EpisodeHistory> _historyItems;
[SetUp] [SetUp]
public void Setup() public void Setup()
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
.With(t => t.RemoteEpisode = remoteEpisode) .With(t => t.RemoteEpisode = remoteEpisode)
.Build(); .Build();
_historyItems = new List<History.History>(); _historyItems = new List<EpisodeHistory>();
} }
public void GivenEpisodes(int count) public void GivenEpisodes(int count)
@ -39,12 +39,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
.BuildList()); .BuildList());
} }
public void GivenHistoryForEpisode(Episode episode, params HistoryEventType[] eventTypes) public void GivenHistoryForEpisode(Episode episode, params EpisodeHistoryEventType[] eventTypes)
{ {
foreach (var eventType in eventTypes) foreach (var eventType in eventTypes)
{ {
_historyItems.Add( _historyItems.Add(
Builder<History.History>.CreateNew() Builder<EpisodeHistory>.CreateNew()
.With(h => h.EpisodeId = episode.Id) .With(h => h.EpisodeId = episode.Id)
.With(h => h.EventType = eventType) .With(h => h.EventType = eventType)
.Build() .Build()
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenEpisodes(1); GivenEpisodes(1);
GivenHistoryForEpisode(_episodes[0], HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.Grabbed);
Subject.IsImported(_trackedDownload, _historyItems) Subject.IsImported(_trackedDownload, _historyItems)
.Should() .Should()
@ -79,8 +79,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenEpisodes(2); GivenEpisodes(2);
GivenHistoryForEpisode(_episodes[0], HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.Grabbed);
GivenHistoryForEpisode(_episodes[1], HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.Grabbed);
Subject.IsImported(_trackedDownload, _historyItems) Subject.IsImported(_trackedDownload, _historyItems)
.Should() .Should()
@ -92,8 +92,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenEpisodes(2); GivenEpisodes(2);
GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed);
GivenHistoryForEpisode(_episodes[1], HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.Grabbed);
Subject.IsImported(_trackedDownload, _historyItems) Subject.IsImported(_trackedDownload, _historyItems)
.Should() .Should()
@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenEpisodes(1); GivenEpisodes(1);
GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed);
Subject.IsImported(_trackedDownload, _historyItems) Subject.IsImported(_trackedDownload, _historyItems)
.Should() .Should()
@ -117,8 +117,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
GivenEpisodes(2); GivenEpisodes(2);
GivenHistoryForEpisode(_episodes[0], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[0], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed);
GivenHistoryForEpisode(_episodes[1], HistoryEventType.DownloadFolderImported, HistoryEventType.Grabbed); GivenHistoryForEpisode(_episodes[1], EpisodeHistoryEventType.DownloadFolderImported, EpisodeHistoryEventType.Grabbed);
Subject.IsImported(_trackedDownload, _historyItems) Subject.IsImported(_trackedDownload, _historyItems)
.Should() .Should()

View File

@ -21,8 +21,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.Is<string>(sr => sr == "35238"))) .Setup(s => s.FindByDownloadId(It.Is<string>(sr => sr == "35238")))
.Returns(new List<History.History>(){ .Returns(new List<EpisodeHistory>(){
new History.History(){ new EpisodeHistory(){
DownloadId = "35238", DownloadId = "35238",
SourceTitle = "TV Series S01", SourceTitle = "TV Series S01",
SeriesId = 5, SeriesId = 5,
@ -61,6 +61,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
Title = "The torrent release folder", Title = "The torrent release folder",
DownloadId = "35238", DownloadId = "35238",
DownloadClientInfo = new DownloadClientItemClientInfo
{
Protocol = client.Protocol,
Id = client.Id,
Name = client.Name
}
}; };
var trackedDownload = Subject.TrackDownload(client, item); var trackedDownload = Subject.TrackDownload(client, item);
@ -90,8 +96,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
Mocker.GetMock<IHistoryService>() Mocker.GetMock<IHistoryService>()
.Setup(s => s.FindByDownloadId(It.Is<string>(sr => sr == "35238"))) .Setup(s => s.FindByDownloadId(It.Is<string>(sr => sr == "35238")))
.Returns(new List<History.History>(){ .Returns(new List<EpisodeHistory>(){
new History.History(){ new EpisodeHistory(){
DownloadId = "35238", DownloadId = "35238",
SourceTitle = "TV Series Special", SourceTitle = "TV Series Special",
SeriesId = 5, SeriesId = 5,
@ -117,6 +123,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
{ {
Title = "The torrent release folder", Title = "The torrent release folder",
DownloadId = "35238", DownloadId = "35238",
DownloadClientInfo = new DownloadClientItemClientInfo
{
Protocol = client.Protocol,
Id = client.Id,
Name = client.Name
}
}; };
var trackedDownload = Subject.TrackDownload(client, item); var trackedDownload = Subject.TrackDownload(client, item);

View File

@ -8,13 +8,13 @@ using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Test.HistoryTests namespace NzbDrone.Core.Test.HistoryTests
{ {
[TestFixture] [TestFixture]
public class HistoryRepositoryFixture : DbTest<HistoryRepository, History.History> public class HistoryRepositoryFixture : DbTest<HistoryRepository, EpisodeHistory>
{ {
[Test] [Test]
public void should_read_write_dictionary() public void should_read_write_dictionary()
{ {
var history = Builder<History.History>.CreateNew() var history = Builder<EpisodeHistory>.CreateNew()
.With(c => c.Quality = new QualityModel()) .With(c => c.Quality = new QualityModel())
.BuildNew(); .BuildNew();
@ -30,16 +30,16 @@ namespace NzbDrone.Core.Test.HistoryTests
[Test] [Test]
public void should_get_download_history() public void should_get_download_history()
{ {
var historyBluray = Builder<History.History>.CreateNew() var historyBluray = Builder<EpisodeHistory>.CreateNew()
.With(c => c.Quality = new QualityModel(Quality.Bluray1080p)) .With(c => c.Quality = new QualityModel(Quality.Bluray1080p))
.With(c => c.SeriesId = 12) .With(c => c.SeriesId = 12)
.With(c => c.EventType = HistoryEventType.Grabbed) .With(c => c.EventType = EpisodeHistoryEventType.Grabbed)
.BuildNew(); .BuildNew();
var historyDvd = Builder<History.History>.CreateNew() var historyDvd = Builder<EpisodeHistory>.CreateNew()
.With(c => c.Quality = new QualityModel(Quality.DVD)) .With(c => c.Quality = new QualityModel(Quality.DVD))
.With(c => c.SeriesId = 12) .With(c => c.SeriesId = 12)
.With(c => c.EventType = HistoryEventType.Grabbed) .With(c => c.EventType = EpisodeHistoryEventType.Grabbed)
.BuildNew(); .BuildNew();
Subject.Insert(historyBluray); Subject.Insert(historyBluray);

View File

@ -13,6 +13,7 @@ using NzbDrone.Core.History;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Qualities; using NzbDrone.Core.Test.Qualities;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Languages; using NzbDrone.Core.Languages;
using NzbDrone.Core.Profiles.Languages; using NzbDrone.Core.Profiles.Languages;
@ -68,14 +69,19 @@ namespace NzbDrone.Core.Test.HistoryTests
var downloadClientItem = new DownloadClientItem var downloadClientItem = new DownloadClientItem
{ {
DownloadClient = "sab", DownloadClientInfo = new DownloadClientItemClientInfo
{
Protocol = DownloadProtocol.Usenet,
Id = 1,
Name = "sab"
},
DownloadId = "abcd" DownloadId = "abcd"
}; };
Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, new List<EpisodeFile>(), true, downloadClientItem)); Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, new List<EpisodeFile>(), true, downloadClientItem));
Mocker.GetMock<IHistoryRepository>() Mocker.GetMock<IHistoryRepository>()
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path)))); .Verify(v => v.Insert(It.Is<EpisodeHistory>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path))));
} }
} }
} }

View File

@ -1,6 +1,7 @@
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.History;
using NzbDrone.Core.Housekeeping.Housekeepers; using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -9,7 +10,7 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{ {
[TestFixture] [TestFixture]
public class CleanupOrphanedHistoryItemsFixture : DbTest<CleanupOrphanedHistoryItems, History.History> public class CleanupOrphanedHistoryItemsFixture : DbTest<CleanupOrphanedHistoryItems, EpisodeHistory>
{ {
private Series _series; private Series _series;
private Episode _episode; private Episode _episode;
@ -39,7 +40,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{ {
GivenEpisode(); GivenEpisode();
var history = Builder<History.History>.CreateNew() var history = Builder<EpisodeHistory>.CreateNew()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.EpisodeId = _episode.Id) .With(h => h.EpisodeId = _episode.Id)
.BuildNew(); .BuildNew();
@ -54,7 +55,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{ {
GivenSeries(); GivenSeries();
var history = Builder<History.History>.CreateNew() var history = Builder<EpisodeHistory>.CreateNew()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.SeriesId = _series.Id) .With(h => h.SeriesId = _series.Id)
.BuildNew(); .BuildNew();
@ -70,7 +71,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
GivenSeries(); GivenSeries();
GivenEpisode(); GivenEpisode();
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<EpisodeHistory>.CreateListOfSize(2)
.All() .All()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.EpisodeId = _episode.Id) .With(h => h.EpisodeId = _episode.Id)
@ -91,7 +92,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
GivenSeries(); GivenSeries();
GivenEpisode(); GivenEpisode();
var history = Builder<History.History>.CreateListOfSize(2) var history = Builder<EpisodeHistory>.CreateListOfSize(2)
.All() .All()
.With(h => h.Quality = new QualityModel()) .With(h => h.Quality = new QualityModel())
.With(h => h.SeriesId = _series.Id) .With(h => h.SeriesId = _series.Id)

View File

@ -7,6 +7,7 @@ using NzbDrone.Core.Queue;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NzbDrone.Core.Download;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@ -20,8 +21,11 @@ namespace NzbDrone.Core.Test.QueueTests
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
var downloadClientInfo = Builder<DownloadClientItemClientInfo>.CreateNew().Build();
var downloadItem = Builder<NzbDrone.Core.Download.DownloadClientItem>.CreateNew() var downloadItem = Builder<NzbDrone.Core.Download.DownloadClientItem>.CreateNew()
.With(v => v.RemainingTime = TimeSpan.FromSeconds(10)) .With(v => v.RemainingTime = TimeSpan.FromSeconds(10))
.With(v => v.DownloadClientInfo = downloadClientInfo)
.Build(); .Build();
var series = Builder<Series>.CreateNew() var series = Builder<Series>.CreateNew()

View File

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Analytics
{ {
get get
{ {
var lastRecord = _historyService.Paged(new PagingSpec<History.History>() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending }); var lastRecord = _historyService.Paged(new PagingSpec<EpisodeHistory>() { Page = 0, PageSize = 1, SortKey = "date", SortDirection = SortDirection.Descending });
var monthAgo = DateTime.UtcNow.AddMonths(-1); var monthAgo = DateTime.UtcNow.AddMonths(-1);
return lastRecord.Records.Any(v => v.Date > monthAgo); return lastRecord.Records.Any(v => v.Date > monthAgo);

View File

@ -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<int, int> EventTypeMap = new Dictionary<int, int>()
{
// 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<Dictionary<string, string>>(rawData);
var downloadHistoryEventType = EventTypeMap[eventType];
var protocol = data.ContainsKey("protocol") ? Convert.ToInt32(data["protocol"]) : (int?)null;
var downloadHistoryData = new Dictionary<string, string>();
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();
}
}
}
}
}
}
}

View File

@ -29,10 +29,12 @@ using NzbDrone.Core.Tv;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Authentication; using NzbDrone.Core.Authentication;
using NzbDrone.Core.CustomFilters; using NzbDrone.Core.CustomFilters;
using NzbDrone.Core.Download.History;
using NzbDrone.Core.Extras.Metadata; using NzbDrone.Core.Extras.Metadata;
using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Metadata.Files;
using NzbDrone.Core.Extras.Others; using NzbDrone.Core.Extras.Others;
using NzbDrone.Core.Extras.Subtitles; using NzbDrone.Core.Extras.Subtitles;
using NzbDrone.Core.History;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Languages; using NzbDrone.Core.Languages;
using NzbDrone.Core.Profiles.Languages; using NzbDrone.Core.Profiles.Languages;
@ -80,7 +82,7 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings"); Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");
Mapper.Entity<History.History>().RegisterModel("History") Mapper.Entity<EpisodeHistory>().RegisterModel("History")
.AutoMapChildModels(); .AutoMapChildModels();
Mapper.Entity<Series>().RegisterModel("Series") Mapper.Entity<Series>().RegisterModel("Series")
@ -134,6 +136,9 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<DownloadClientStatus>().RegisterModel("DownloadClientStatus"); Mapper.Entity<DownloadClientStatus>().RegisterModel("DownloadClientStatus");
Mapper.Entity<CustomFilter>().RegisterModel("CustomFilters"); Mapper.Entity<CustomFilter>().RegisterModel("CustomFilters");
Mapper.Entity<DownloadHistory>().RegisterModel("DownloadHistory")
.AutoMapChildModels();
} }
private static void RegisterMappers() private static void RegisterMappers()

View File

@ -47,7 +47,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
} }
var historyForEpisode = _historyService.FindByEpisodeId(episode.Id); 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) if (lastGrabbed == null)
{ {
@ -55,7 +55,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
} }
var imported = historyForEpisode.FirstOrDefault(h => var imported = historyForEpisode.FirstOrDefault(h =>
h.EventType == HistoryEventType.DownloadFolderImported && h.EventType == EpisodeHistoryEventType.DownloadFolderImported &&
h.DownloadId == lastGrabbed.DownloadId); h.DownloadId == lastGrabbed.DownloadId);
if (imported == null) if (imported == null)

View File

@ -49,7 +49,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
_logger.Debug("Checking current status of episode [{0}] in history", episode.Id); _logger.Debug("Checking current status of episode [{0}] in history", episode.Id);
var mostRecent = _historyService.MostRecentForEpisode(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)); var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));

View File

@ -88,7 +88,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
yield return new DownloadClientItem yield return new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = Definition.Name + "_" + item.DownloadId, DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "sonarr", Category = "sonarr",
Title = item.Title, Title = item.Title,

View File

@ -59,7 +59,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
yield return new DownloadClientItem yield return new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = Definition.Name + "_" + item.DownloadId, DownloadId = Definition.Name + "_" + item.DownloadId,
Category = "sonarr", Category = "sonarr",
Title = item.Title, Title = item.Title,

View File

@ -129,7 +129,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
item.Title = torrent.Name; item.Title = torrent.Name;
item.Category = Settings.TvCategory; item.Category = Settings.TvCategory;
item.DownloadClient = Definition.Name; item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath)); var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath));
item.OutputPath = outputPath + torrent.Name; item.OutputPath = outputPath + torrent.Name;

View File

@ -85,7 +85,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
var item = new DownloadClientItem() var item = new DownloadClientItem()
{ {
Category = Settings.TvCategory, Category = Settings.TvCategory,
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = CreateDownloadId(torrent.Id, serialNumber), DownloadId = CreateDownloadId(torrent.Id, serialNumber),
Title = torrent.Title, Title = torrent.Title,
TotalSize = torrent.Size, TotalSize = torrent.Size,

View File

@ -96,7 +96,7 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
var item = new DownloadClientItem() var item = new DownloadClientItem()
{ {
Category = Settings.TvCategory, Category = Settings.TvCategory,
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = CreateDownloadId(nzb.Id, serialNumber), DownloadId = CreateDownloadId(nzb.Id, serialNumber),
Title = nzb.Title, Title = nzb.Title,
TotalSize = nzb.Size, TotalSize = nzb.Size,

View File

@ -56,7 +56,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
var item = new DownloadClientItem var item = new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = torrent.InfoHash.ToUpper(), DownloadId = torrent.InfoHash.ToUpper(),
OutputPath = outputPath + torrent.Name, OutputPath = outputPath + torrent.Name,
RemainingSize = torrent.TotalSize - torrent.DownloadedBytes, RemainingSize = torrent.TotalSize - torrent.DownloadedBytes,

View File

@ -56,7 +56,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
{ {
var queueItem = new DownloadClientItem(); var queueItem = new DownloadClientItem();
queueItem.DownloadClient = Definition.Name; queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.DownloadId = vortexQueueItem.AddUUID ?? vortexQueueItem.Id.ToString(); queueItem.DownloadId = vortexQueueItem.AddUUID ?? vortexQueueItem.Id.ToString();
queueItem.Category = vortexQueueItem.GroupName; queueItem.Category = vortexQueueItem.GroupName;
queueItem.Title = vortexQueueItem.UiTitle; queueItem.Title = vortexQueueItem.UiTitle;

View File

@ -71,7 +71,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
queueItem.Title = item.NzbName; queueItem.Title = item.NzbName;
queueItem.TotalSize = totalSize; queueItem.TotalSize = totalSize;
queueItem.Category = item.Category; queueItem.Category = item.Category;
queueItem.DownloadClient = Definition.Name; queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.CanMoveFiles = true; queueItem.CanMoveFiles = true;
queueItem.CanBeRemoved = true; queueItem.CanBeRemoved = true;
@ -118,7 +118,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var historyItem = new DownloadClientItem(); var historyItem = new DownloadClientItem();
var itemDir = item.FinalDir.IsNullOrWhiteSpace() ? item.DestDir : item.FinalDir; 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.DownloadId = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString();
historyItem.Title = item.Name; historyItem.Title = item.Name;
historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo); historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo);

View File

@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
var historyItem = new DownloadClientItem var historyItem = new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = GetDownloadClientId(file), DownloadId = GetDownloadClientId(file),
Title = title, Title = title,

View File

@ -135,7 +135,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label, Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label,
Title = torrent.Name, Title = torrent.Name,
TotalSize = torrent.Size, TotalSize = torrent.Size,
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)), RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)),
RemainingTime = GetRemainingTime(torrent), RemainingTime = GetRemainingTime(torrent),
SeedRatio = torrent.Ratio, SeedRatio = torrent.Ratio,

View File

@ -62,7 +62,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
} }
var queueItem = new DownloadClientItem(); var queueItem = new DownloadClientItem();
queueItem.DownloadClient = Definition.Name; queueItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
queueItem.DownloadId = sabQueueItem.Id; queueItem.DownloadId = sabQueueItem.Id;
queueItem.Category = sabQueueItem.Category; queueItem.Category = sabQueueItem.Category;
queueItem.Title = sabQueueItem.Title; queueItem.Title = sabQueueItem.Title;
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var historyItem = new DownloadClientItem var historyItem = new DownloadClientItem
{ {
DownloadClient = Definition.Name, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
DownloadId = sabHistoryItem.Id, DownloadId = sabHistoryItem.Id,
Category = sabHistoryItem.Category, Category = sabHistoryItem.Category,
Title = sabHistoryItem.Title, Title = sabHistoryItem.Title,

View File

@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
item.Category = Settings.TvCategory; item.Category = Settings.TvCategory;
item.Title = torrent.Name; item.Title = torrent.Name;
item.DownloadClient = Definition.Name; item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.OutputPath = GetOutputPath(outputPath, torrent); item.OutputPath = GetOutputPath(outputPath, torrent);
item.TotalSize = torrent.TotalSize; item.TotalSize = torrent.TotalSize;

View File

@ -115,7 +115,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
} }
var item = new DownloadClientItem(); var item = new DownloadClientItem();
item.DownloadClient = Definition.Name; item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.Title = torrent.Name; item.Title = torrent.Name;
item.DownloadId = torrent.Hash; item.DownloadId = torrent.Hash;
item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path)); item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path));

View File

@ -118,7 +118,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
item.Title = torrent.Name; item.Title = torrent.Name;
item.TotalSize = torrent.Size; item.TotalSize = torrent.Size;
item.Category = torrent.Label; item.Category = torrent.Label;
item.DownloadClient = Definition.Name; item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this);
item.RemainingSize = torrent.Remaining; item.RemainingSize = torrent.Remaining;
item.SeedRatio = torrent.Ratio; item.SeedRatio = torrent.Ratio;

View File

@ -122,6 +122,11 @@ namespace NzbDrone.Core.Download
// file was imported. This will allow the decision engine to reject already imported // 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. // 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)) if (importResults.Any(c => c.Result == ImportResultType.Imported))
{ {
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId) var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)

View File

@ -1,13 +1,15 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Download namespace NzbDrone.Core.Download
{ {
[DebuggerDisplay("{DownloadClient}:{Title}")] [DebuggerDisplay("{DownloadClientName}:{Title}")]
public class DownloadClientItem public class DownloadClientItem
{ {
public string DownloadClient { get; set; } public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public string Category { get; set; } public string Category { get; set; }
public string Title { get; set; } public string Title { get; set; }
@ -16,16 +18,32 @@ namespace NzbDrone.Core.Download
public long RemainingSize { get; set; } public long RemainingSize { get; set; }
public TimeSpan? RemainingTime { get; set; } public TimeSpan? RemainingTime { get; set; }
public double? SeedRatio { get; set; } public double? SeedRatio { get; set; }
public OsPath OutputPath { get; set; } public OsPath OutputPath { get; set; }
public string Message { get; set; } public string Message { get; set; }
public DownloadItemStatus Status { get; set; } public DownloadItemStatus Status { get; set; }
public bool IsEncrypted { get; set; } public bool IsEncrypted { get; set; }
public bool CanMoveFiles { get; set; } public bool CanMoveFiles { get; set; }
public bool CanBeRemoved { get; set; } public bool CanBeRemoved { get; set; }
public bool Removed { 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<TSettings>(
DownloadClientBase<TSettings> downloadClient) where TSettings : IProviderConfig, new()
{
return new DownloadClientItemClientInfo
{
Protocol = downloadClient.Protocol,
Type = downloadClient.Name,
Id = downloadClient.Definition.Id,
Name = downloadClient.Definition.Name
};
}
}
} }

View File

@ -66,7 +66,7 @@ namespace NzbDrone.Core.Download
var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient);
try 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); downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadId, true);
trackedDownload.DownloadItem.Removed = true; trackedDownload.DownloadItem.Removed = true;
} }
@ -85,7 +85,7 @@ namespace NzbDrone.Core.Download
var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient); var downloadClient = _downloadClientProvider.Get(trackedDownload.DownloadClient);
try 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); downloadClient.MarkItemAsImported(trackedDownload.DownloadItem);
} }
catch (NotSupportedException e) catch (NotSupportedException e)

View File

@ -12,7 +12,7 @@ namespace NzbDrone.Core.Download
public Language Language { get; set; } public Language Language { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public string SourceTitle { get; set; } public string SourceTitle { get; set; }
public string DownloadClient { get; set; } public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public string Message { get; set; } public string Message { get; set; }
} }

View File

@ -5,7 +5,6 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.TPL; using NzbDrone.Common.TPL;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients; using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
@ -98,6 +97,8 @@ namespace NzbDrone.Core.Download
var episodeGrabbedEvent = new EpisodeGrabbedEvent(remoteEpisode); var episodeGrabbedEvent = new EpisodeGrabbedEvent(remoteEpisode);
episodeGrabbedEvent.DownloadClient = downloadClient.Name; episodeGrabbedEvent.DownloadClient = downloadClient.Name;
episodeGrabbedEvent.DownloadClientId = downloadClient.Definition.Id;
episodeGrabbedEvent.DownloadClientName = downloadClient.Definition.Name;
if (!string.IsNullOrWhiteSpace(downloadClientId)) if (!string.IsNullOrWhiteSpace(downloadClientId))
{ {

View File

@ -6,7 +6,9 @@ namespace NzbDrone.Core.Download
public class EpisodeGrabbedEvent : IEvent public class EpisodeGrabbedEvent : IEvent
{ {
public RemoteEpisode Episode { get; private set; } public RemoteEpisode Episode { get; private set; }
public int DownloadClientId { get; set; }
public string DownloadClient { get; set; } public string DownloadClient { get; set; }
public string DownloadClientName { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public EpisodeGrabbedEvent(RemoteEpisode episode) public EpisodeGrabbedEvent(RemoteEpisode episode)

View File

@ -18,12 +18,15 @@ namespace NzbDrone.Core.Download
public class FailedDownloadService : IFailedDownloadService public class FailedDownloadService : IFailedDownloadService
{ {
private readonly IHistoryService _historyService; private readonly IHistoryService _historyService;
private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
public FailedDownloadService(IHistoryService historyService, public FailedDownloadService(IHistoryService historyService,
ITrackedDownloadService trackedDownloadService,
IEventAggregator eventAggregator) IEventAggregator eventAggregator)
{ {
_historyService = historyService; _historyService = historyService;
_trackedDownloadService = trackedDownloadService;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
} }
@ -34,22 +37,24 @@ namespace NzbDrone.Core.Download
var downloadId = history.DownloadId; var downloadId = history.DownloadId;
if (downloadId.IsNullOrWhiteSpace()) if (downloadId.IsNullOrWhiteSpace())
{ {
PublishDownloadFailedEvent(new List<History.History> { history }, "Manually marked as failed"); PublishDownloadFailedEvent(new List<EpisodeHistory> { history }, "Manually marked as failed");
} }
else else
{ {
var grabbedHistory = _historyService.Find(downloadId, HistoryEventType.Grabbed).ToList(); var grabbedHistory = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed).ToList();
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed"); PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
} }
} }
public void MarkAsFailed(string downloadId) public void MarkAsFailed(string downloadId)
{ {
var history = _historyService.Find(downloadId, HistoryEventType.Grabbed); var history = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed);
if (history.Any()) 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) trackedDownload.DownloadItem.Status == DownloadItemStatus.Failed)
{ {
var grabbedItems = _historyService var grabbedItems = _historyService
.Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed) .Find(trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed)
.ToList(); .ToList();
if (grabbedItems.Empty()) if (grabbedItems.Empty())
@ -86,7 +91,7 @@ namespace NzbDrone.Core.Download
} }
var grabbedItems = _historyService var grabbedItems = _historyService
.Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed) .Find(trackedDownload.DownloadItem.DownloadId, EpisodeHistoryEventType.Grabbed)
.ToList(); .ToList();
if (grabbedItems.Empty()) if (grabbedItems.Empty())
@ -109,7 +114,7 @@ namespace NzbDrone.Core.Download
PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload); PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload);
} }
private void PublishDownloadFailedEvent(List<History.History> historyItems, string message, TrackedDownload trackedDownload = null) private void PublishDownloadFailedEvent(List<EpisodeHistory> historyItems, string message, TrackedDownload trackedDownload = null)
{ {
var historyItem = historyItems.First(); var historyItem = historyItems.First();
@ -119,7 +124,7 @@ namespace NzbDrone.Core.Download
EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(), EpisodeIds = historyItems.Select(h => h.EpisodeId).ToList(),
Quality = historyItem.Quality, Quality = historyItem.Quality,
SourceTitle = historyItem.SourceTitle, SourceTitle = historyItem.SourceTitle,
DownloadClient = historyItem.Data.GetValueOrDefault(History.History.DOWNLOAD_CLIENT), DownloadClient = historyItem.Data.GetValueOrDefault(EpisodeHistory.DOWNLOAD_CLIENT),
DownloadId = historyItem.DownloadId, DownloadId = historyItem.DownloadId,
Message = message, Message = message,
Data = historyItem.Data, Data = historyItem.Data,

View File

@ -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<string, string> Data { get; set; }
public DownloadHistory()
{
Data = new Dictionary<string, string>();
}
}
public enum DownloadHistoryEventType
{
DownloadGrabbed = 1,
DownloadImported = 2,
DownloadFailed = 3,
DownloadIgnored = 4,
FileImported = 5
}
}

View File

@ -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<DownloadHistory>
{
List<DownloadHistory> FindByDownloadId(string downloadId);
void DeleteBySeriesId(int seriesId);
}
public class DownloadHistoryRepository : BasicRepository<DownloadHistory>, IDownloadHistoryRepository
{
public DownloadHistoryRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public List<DownloadHistory> FindByDownloadId(string downloadId)
{
return Query.Where(h => h.DownloadId == downloadId)
.OrderByDescending(h => h.Date);
}
public void DeleteBySeriesId(int seriesId)
{
Delete(r => r.SeriesId == seriesId);
}
}
}

View File

@ -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<EpisodeGrabbedEvent>,
IHandle<EpisodeImportedEvent>,
IHandle<DownloadCompletedEvent>,
IHandle<DownloadFailedEvent>,
IHandle<DownloadIgnoredEvent>,
IHandle<SeriesDeletedEvent>
{
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);
}
}
}

View File

@ -8,7 +8,6 @@ namespace NzbDrone.Core.Download
public interface IDownloadClient : IProvider public interface IDownloadClient : IProvider
{ {
DownloadProtocol Protocol { get; } DownloadProtocol Protocol { get; }
string Download(RemoteEpisode remoteEpisode); string Download(RemoteEpisode remoteEpisode);
IEnumerable<DownloadClientItem> GetItems(); IEnumerable<DownloadClientItem> GetItems();
void RemoveItem(string downloadId, bool deleteData); void RemoveItem(string downloadId, bool deleteData);

View File

@ -41,7 +41,7 @@ namespace NzbDrone.Core.Download
Language = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Language, Language = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Language,
Quality = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Quality, Quality = trackedDownload.RemoteEpisode.ParsedEpisodeInfo.Quality,
SourceTitle = trackedDownload.DownloadItem.Title, SourceTitle = trackedDownload.DownloadItem.Title,
DownloadClient = trackedDownload.DownloadItem.DownloadClient, DownloadClientInfo = trackedDownload.DownloadItem.DownloadClientInfo,
DownloadId = trackedDownload.DownloadItem.DownloadId, DownloadId = trackedDownload.DownloadItem.DownloadId,
Message = "Manually ignored" Message = "Manually ignored"
}; };

View File

@ -7,12 +7,12 @@ namespace NzbDrone.Core.Download.TrackedDownloads
{ {
public interface ITrackedDownloadAlreadyImported public interface ITrackedDownloadAlreadyImported
{ {
bool IsImported(TrackedDownload trackedDownload, List<History.History> historyItems); bool IsImported(TrackedDownload trackedDownload, List<EpisodeHistory> historyItems);
} }
public class TrackedDownloadAlreadyImported : ITrackedDownloadAlreadyImported public class TrackedDownloadAlreadyImported : ITrackedDownloadAlreadyImported
{ {
public bool IsImported(TrackedDownload trackedDownload, List<History.History> historyItems) public bool IsImported(TrackedDownload trackedDownload, List<EpisodeHistory> historyItems)
{ {
if (historyItems.Empty()) if (historyItems.Empty())
{ {
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
return false; return false;
} }
return lastHistoryItem.EventType == HistoryEventType.DownloadFolderImported; return lastHistoryItem.EventType == EpisodeHistoryEventType.DownloadFolderImported;
}); });
return allEpisodesImportedInHistory; return allEpisodesImportedInHistory;

View File

@ -4,6 +4,7 @@ using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Download.History;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
@ -25,7 +26,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
private readonly IParsingService _parsingService; private readonly IParsingService _parsingService;
private readonly IHistoryService _historyService; private readonly IHistoryService _historyService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported; private readonly IDownloadHistoryService _downloadHistoryService;
private readonly Logger _logger; private readonly Logger _logger;
private readonly ICached<TrackedDownload> _cache; private readonly ICached<TrackedDownload> _cache;
@ -33,13 +34,13 @@ namespace NzbDrone.Core.Download.TrackedDownloads
ICacheManager cacheManager, ICacheManager cacheManager,
IHistoryService historyService, IHistoryService historyService,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported, IDownloadHistoryService downloadHistoryService,
Logger logger) Logger logger)
{ {
_parsingService = parsingService; _parsingService = parsingService;
_historyService = historyService; _historyService = historyService;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported; _downloadHistoryService = downloadHistoryService;
_cache = cacheManager.GetCache<TrackedDownload>(GetType()); _cache = cacheManager.GetCache<TrackedDownload>(GetType());
_logger = logger; _logger = logger;
} }
@ -105,34 +106,19 @@ namespace NzbDrone.Core.Download.TrackedDownloads
trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); 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()) if (historyItems.Any())
{ {
var firstHistoryItem = historyItems.First(); 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"]; trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
if (parsedEpisodeInfo == null || if (parsedEpisodeInfo == null ||
@ -146,7 +132,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
if (parsedEpisodeInfo != null) 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) existingItem.CanMoveFiles != downloadItem.CanMoveFiles)
{ {
_logger.Debug("Tracking '{0}:{1}': ClientState={2}{3} SonarrStage={4} Episode='{5}' OutputPath={6}.", _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.Status, downloadItem.CanBeRemoved ? "" :
downloadItem.CanMoveFiles ? " (busy)" : " (readonly)", downloadItem.CanMoveFiles ? " (busy)" : " (readonly)",
trackedDownload.State, 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) switch (eventType)
{ {
case HistoryEventType.DownloadFolderImported: case DownloadHistoryEventType.DownloadImported:
return TrackedDownloadState.Imported; return TrackedDownloadState.Imported;
case HistoryEventType.DownloadFailed: case DownloadHistoryEventType.DownloadFailed:
return TrackedDownloadState.Failed; return TrackedDownloadState.Failed;
case HistoryEventType.DownloadIgnored: case DownloadHistoryEventType.DownloadIgnored:
return TrackedDownloadState.Ignored; return TrackedDownloadState.Ignored;
default: default:
return TrackedDownloadState.Downloading; return TrackedDownloadState.Downloading;

View File

@ -7,11 +7,11 @@ using NzbDrone.Core.Languages;
namespace NzbDrone.Core.History namespace NzbDrone.Core.History
{ {
public class History : ModelBase public class EpisodeHistory : ModelBase
{ {
public const string DOWNLOAD_CLIENT = "downloadClient"; public const string DOWNLOAD_CLIENT = "downloadClient";
public History() public EpisodeHistory()
{ {
Data = new Dictionary<string, string>(); Data = new Dictionary<string, string>();
} }
@ -23,7 +23,7 @@ namespace NzbDrone.Core.History
public DateTime Date { get; set; } public DateTime Date { get; set; }
public Episode Episode { get; set; } public Episode Episode { get; set; }
public Series Series { get; set; } public Series Series { get; set; }
public HistoryEventType EventType { get; set; } public EpisodeHistoryEventType EventType { get; set; }
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
@ -31,7 +31,7 @@ namespace NzbDrone.Core.History
} }
public enum HistoryEventType public enum EpisodeHistoryEventType
{ {
Unknown = 0, Unknown = 0,
Grabbed = 1, Grabbed = 1,

View File

@ -9,20 +9,20 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.History namespace NzbDrone.Core.History
{ {
public interface IHistoryRepository : IBasicRepository<History> public interface IHistoryRepository : IBasicRepository<EpisodeHistory>
{ {
History MostRecentForEpisode(int episodeId); EpisodeHistory MostRecentForEpisode(int episodeId);
List<History> FindByEpisodeId(int episodeId); List<EpisodeHistory> FindByEpisodeId(int episodeId);
History MostRecentForDownloadId(string downloadId); EpisodeHistory MostRecentForDownloadId(string downloadId);
List<History> FindByDownloadId(string downloadId); List<EpisodeHistory> FindByDownloadId(string downloadId);
List<History> GetBySeries(int seriesId, HistoryEventType? eventType); List<EpisodeHistory> GetBySeries(int seriesId, EpisodeHistoryEventType? eventType);
List<History> GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType); List<EpisodeHistory> GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType);
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality); List<EpisodeHistory> FindDownloadHistory(int idSeriesId, QualityModel quality);
void DeleteForSeries(int seriesId); void DeleteForSeries(int seriesId);
List<History> Since(DateTime date, HistoryEventType? eventType); List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType);
} }
public class HistoryRepository : BasicRepository<History>, IHistoryRepository public class HistoryRepository : BasicRepository<EpisodeHistory>, IHistoryRepository
{ {
public HistoryRepository(IMainDatabase database, IEventAggregator eventAggregator) 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) return Query.Where(h => h.EpisodeId == episodeId)
.OrderByDescending(h => h.Date) .OrderByDescending(h => h.Date)
.FirstOrDefault(); .FirstOrDefault();
} }
public List<History> FindByEpisodeId(int episodeId) public List<EpisodeHistory> FindByEpisodeId(int episodeId)
{ {
return Query.Where(h => h.EpisodeId == episodeId) return Query.Where(h => h.EpisodeId == episodeId)
.OrderByDescending(h => h.Date) .OrderByDescending(h => h.Date)
.ToList(); .ToList();
} }
public History MostRecentForDownloadId(string downloadId) public EpisodeHistory MostRecentForDownloadId(string downloadId)
{ {
return Query.Where(h => h.DownloadId == downloadId) return Query.Where(h => h.DownloadId == downloadId)
.OrderByDescending(h => h.Date) .OrderByDescending(h => h.Date)
.FirstOrDefault(); .FirstOrDefault();
} }
public List<History> FindByDownloadId(string downloadId) public List<EpisodeHistory> FindByDownloadId(string downloadId)
{ {
return Query.Where(h => h.DownloadId == downloadId); return Query.Where(h => h.DownloadId == downloadId);
} }
public List<History> GetBySeries(int seriesId, HistoryEventType? eventType) public List<EpisodeHistory> GetBySeries(int seriesId, EpisodeHistoryEventType? eventType)
{ {
var query = Query.Where(h => h.SeriesId == seriesId); var query = Query.Where(h => h.SeriesId == seriesId);
@ -68,9 +68,9 @@ namespace NzbDrone.Core.History
return query.OrderByDescending(h => h.Date).ToList(); return query.OrderByDescending(h => h.Date).ToList();
} }
public List<History> GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType) public List<EpisodeHistory> GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType)
{ {
var query = Query.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id) var query = Query.Join<EpisodeHistory, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id)
.Where(h => h.SeriesId == seriesId) .Where(h => h.SeriesId == seriesId)
.AndWhere(h => h.Episode.SeasonNumber == seasonNumber); .AndWhere(h => h.Episode.SeasonNumber == seasonNumber);
@ -84,14 +84,14 @@ namespace NzbDrone.Core.History
return query; return query;
} }
public List<History> FindDownloadHistory(int idSeriesId, QualityModel quality) public List<EpisodeHistory> FindDownloadHistory(int idSeriesId, QualityModel quality)
{ {
return Query.Where(h => return Query.Where(h =>
h.SeriesId == idSeriesId && h.SeriesId == idSeriesId &&
h.Quality == quality && h.Quality == quality &&
(h.EventType == HistoryEventType.Grabbed || (h.EventType == EpisodeHistoryEventType.Grabbed ||
h.EventType == HistoryEventType.DownloadFailed || h.EventType == EpisodeHistoryEventType.DownloadFailed ||
h.EventType == HistoryEventType.DownloadFolderImported) h.EventType == EpisodeHistoryEventType.DownloadFolderImported)
).ToList(); ).ToList();
} }
@ -100,15 +100,15 @@ namespace NzbDrone.Core.History
Delete(c => c.SeriesId == seriesId); Delete(c => c.SeriesId == seriesId);
} }
protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec) protected override SortBuilder<EpisodeHistory> GetPagedQuery(QueryBuilder<EpisodeHistory> query, PagingSpec<EpisodeHistory> pagingSpec)
{ {
var baseQuery = query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) var baseQuery = query.Join<EpisodeHistory, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id); .Join<EpisodeHistory, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id);
return base.GetPagedQuery(baseQuery, pagingSpec); return base.GetPagedQuery(baseQuery, pagingSpec);
} }
public List<History> Since(DateTime date, HistoryEventType? eventType) public List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType)
{ {
var query = Query.Where(h => h.Date >= date); var query = Query.Where(h => h.Date >= date);

View File

@ -16,16 +16,17 @@ namespace NzbDrone.Core.History
{ {
public interface IHistoryService public interface IHistoryService
{ {
PagingSpec<History> Paged(PagingSpec<History> pagingSpec); PagingSpec<EpisodeHistory> Paged(PagingSpec<EpisodeHistory> pagingSpec);
History MostRecentForEpisode(int episodeId); EpisodeHistory MostRecentForEpisode(int episodeId);
List<History> FindByEpisodeId(int episodeId); List<EpisodeHistory> FindByEpisodeId(int episodeId);
History MostRecentForDownloadId(string downloadId); EpisodeHistory MostRecentForDownloadId(string downloadId);
History Get(int historyId); EpisodeHistory Get(int historyId);
List<History> GetBySeries(int seriesId, HistoryEventType? eventType); List<EpisodeHistory> GetBySeries(int seriesId, EpisodeHistoryEventType? eventType);
List<History> GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType); List<EpisodeHistory> GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType);
List<History> Find(string downloadId, HistoryEventType eventType); List<EpisodeHistory> Find(string downloadId, EpisodeHistoryEventType eventType);
List<History> FindByDownloadId(string downloadId); List<EpisodeHistory> FindByDownloadId(string downloadId);
List<History> Since(DateTime date, HistoryEventType? eventType); string FindDownloadId(EpisodeImportedEvent trackedDownload);
List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType);
} }
public class HistoryService : IHistoryService, public class HistoryService : IHistoryService,
@ -46,68 +47,66 @@ namespace NzbDrone.Core.History
_logger = logger; _logger = logger;
} }
public PagingSpec<History> Paged(PagingSpec<History> pagingSpec) public PagingSpec<EpisodeHistory> Paged(PagingSpec<EpisodeHistory> pagingSpec)
{ {
return _historyRepository.GetPaged(pagingSpec); return _historyRepository.GetPaged(pagingSpec);
} }
public History MostRecentForEpisode(int episodeId) public EpisodeHistory MostRecentForEpisode(int episodeId)
{ {
return _historyRepository.MostRecentForEpisode(episodeId); return _historyRepository.MostRecentForEpisode(episodeId);
} }
public List<History> FindByEpisodeId(int episodeId) public List<EpisodeHistory> FindByEpisodeId(int episodeId)
{ {
return _historyRepository.FindByEpisodeId(episodeId); return _historyRepository.FindByEpisodeId(episodeId);
} }
public History MostRecentForDownloadId(string downloadId) public EpisodeHistory MostRecentForDownloadId(string downloadId)
{ {
return _historyRepository.MostRecentForDownloadId(downloadId); return _historyRepository.MostRecentForDownloadId(downloadId);
} }
public History Get(int historyId) public EpisodeHistory Get(int historyId)
{ {
return _historyRepository.Get(historyId); return _historyRepository.Get(historyId);
} }
public List<History> GetBySeries(int seriesId, HistoryEventType? eventType) public List<EpisodeHistory> GetBySeries(int seriesId, EpisodeHistoryEventType? eventType)
{ {
return _historyRepository.GetBySeries(seriesId, eventType); return _historyRepository.GetBySeries(seriesId, eventType);
} }
public List<History> GetBySeason(int seriesId, int seasonNumber, HistoryEventType? eventType) public List<EpisodeHistory> GetBySeason(int seriesId, int seasonNumber, EpisodeHistoryEventType? eventType)
{ {
return _historyRepository.GetBySeason(seriesId, seasonNumber, eventType); return _historyRepository.GetBySeason(seriesId, seasonNumber, eventType);
} }
public List<History> Find(string downloadId, HistoryEventType eventType) public List<EpisodeHistory> Find(string downloadId, EpisodeHistoryEventType eventType)
{ {
return _historyRepository.FindByDownloadId(downloadId).Where(c => c.EventType == eventType).ToList(); return _historyRepository.FindByDownloadId(downloadId).Where(c => c.EventType == eventType).ToList();
} }
public List<History> FindByDownloadId(string downloadId) public List<EpisodeHistory> FindByDownloadId(string downloadId)
{ {
return _historyRepository.FindByDownloadId(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); _logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedEpisode.Path);
var episodeIds = trackedDownload.EpisodeInfo.Episodes.Select(c => c.Id).ToList(); var episodeIds = trackedDownload.EpisodeInfo.Episodes.Select(c => c.Id).ToList();
var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.EpisodeInfo.Series.Id, trackedDownload.ImportedEpisode.Quality); var allHistory = _historyRepository.FindDownloadHistory(trackedDownload.EpisodeInfo.Series.Id, trackedDownload.ImportedEpisode.Quality);
//Find download related items for these episodes
//Find download related items for these episdoes
var episodesHistory = allHistory.Where(h => episodeIds.Contains(h.EpisodeId)).ToList(); var episodesHistory = allHistory.Where(h => episodeIds.Contains(h.EpisodeId)).ToList();
var processedDownloadId = episodesHistory 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); .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; string downloadId = null;
@ -140,9 +139,9 @@ namespace NzbDrone.Core.History
{ {
foreach (var episode in message.Episode.Episodes) foreach (var episode in message.Episode.Episodes)
{ {
var history = new History var history = new EpisodeHistory
{ {
EventType = HistoryEventType.Grabbed, EventType = EpisodeHistoryEventType.Grabbed,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.Episode.ParsedEpisodeInfo.Quality, Quality = message.Episode.ParsedEpisodeInfo.Quality,
SourceTitle = message.Episode.Release.Title, 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("AgeMinutes", message.Episode.Release.AgeMinutes.ToString());
history.Data.Add("PublishedDate", message.Episode.Release.PublishDate.ToString("s") + "Z"); history.Data.Add("PublishedDate", message.Episode.Release.PublishDate.ToString("s") + "Z");
history.Data.Add("DownloadClient", message.DownloadClient); history.Data.Add("DownloadClient", message.DownloadClient);
history.Data.Add("DownloadClientName", message.DownloadClientName);
history.Data.Add("Size", message.Episode.Release.Size.ToString()); history.Data.Add("Size", message.Episode.Release.Size.ToString());
history.Data.Add("DownloadUrl", message.Episode.Release.DownloadUrl); history.Data.Add("DownloadUrl", message.Episode.Release.DownloadUrl);
history.Data.Add("Guid", message.Episode.Release.Guid); history.Data.Add("Guid", message.Episode.Release.Guid);
@ -199,9 +199,9 @@ namespace NzbDrone.Core.History
foreach (var episode in message.EpisodeInfo.Episodes) foreach (var episode in message.EpisodeInfo.Episodes)
{ {
var history = new History var history = new EpisodeHistory
{ {
EventType = HistoryEventType.DownloadFolderImported, EventType = EpisodeHistoryEventType.DownloadFolderImported,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.EpisodeInfo.Quality, Quality = message.EpisodeInfo.Quality,
SourceTitle = message.ImportedEpisode.SceneName ?? Path.GetFileNameWithoutExtension(message.EpisodeInfo.Path), 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("FileId", message.ImportedEpisode.Id.ToString());
history.Data.Add("DroppedPath", message.EpisodeInfo.Path); history.Data.Add("DroppedPath", message.EpisodeInfo.Path);
history.Data.Add("ImportedPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath)); 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); _historyRepository.Insert(history);
} }
@ -225,9 +226,9 @@ namespace NzbDrone.Core.History
{ {
foreach (var episodeId in message.EpisodeIds) foreach (var episodeId in message.EpisodeIds)
{ {
var history = new History var history = new EpisodeHistory
{ {
EventType = HistoryEventType.DownloadFailed, EventType = EpisodeHistoryEventType.DownloadFailed,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.Quality, Quality = message.Quality,
SourceTitle = message.SourceTitle, SourceTitle = message.SourceTitle,
@ -238,6 +239,7 @@ namespace NzbDrone.Core.History
}; };
history.Data.Add("DownloadClient", message.DownloadClient); history.Data.Add("DownloadClient", message.DownloadClient);
history.Data.Add("DownloadClientName", message.TrackedDownload?.DownloadItem.DownloadClientInfo.Name);
history.Data.Add("Message", message.Message); history.Data.Add("Message", message.Message);
_historyRepository.Insert(history); _historyRepository.Insert(history);
@ -259,9 +261,9 @@ namespace NzbDrone.Core.History
foreach (var episode in message.EpisodeFile.Episodes.Value) 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, Date = DateTime.UtcNow,
Quality = message.EpisodeFile.Quality, Quality = message.EpisodeFile.Quality,
SourceTitle = message.EpisodeFile.Path, SourceTitle = message.EpisodeFile.Path,
@ -284,9 +286,9 @@ namespace NzbDrone.Core.History
foreach (var episode in message.EpisodeFile.Episodes.Value) 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, Date = DateTime.UtcNow,
Quality = message.EpisodeFile.Quality, Quality = message.EpisodeFile.Quality,
SourceTitle = message.OriginalPath, SourceTitle = message.OriginalPath,
@ -305,13 +307,13 @@ namespace NzbDrone.Core.History
public void Handle(DownloadIgnoredEvent message) public void Handle(DownloadIgnoredEvent message)
{ {
var historyToAdd = new List<History>(); var historyToAdd = new List<EpisodeHistory>();
foreach (var episodeId in message.EpisodeIds) foreach (var episodeId in message.EpisodeIds)
{ {
var history = new History var history = new EpisodeHistory
{ {
EventType = HistoryEventType.DownloadIgnored, EventType = EpisodeHistoryEventType.DownloadIgnored,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.Quality, Quality = message.Quality,
SourceTitle = message.SourceTitle, SourceTitle = message.SourceTitle,
@ -321,7 +323,8 @@ namespace NzbDrone.Core.History
Language = message.Language 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); history.Data.Add("Message", message.Message);
historyToAdd.Add(history); historyToAdd.Add(history);
@ -335,7 +338,7 @@ namespace NzbDrone.Core.History
_historyRepository.DeleteForSeries(message.Series.Id); _historyRepository.DeleteForSeries(message.Series.Id);
} }
public List<History> Since(DateTime date, HistoryEventType? eventType) public List<EpisodeHistory> Since(DateTime date, EpisodeHistoryEventType? eventType)
{ {
return _historyRepository.Since(date, eventType); return _historyRepository.Since(date, eventType);
} }

View File

@ -39,8 +39,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
} }
var episodeHistory = _historyService.FindByEpisodeId(episode.Id); var episodeHistory = _historyService.FindByEpisodeId(episode.Id);
var lastImported = episodeHistory.FirstOrDefault(h => h.EventType == HistoryEventType.DownloadFolderImported); var lastImported = episodeHistory.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.DownloadFolderImported);
var lastGrabbed = episodeHistory.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed); var lastGrabbed = episodeHistory.FirstOrDefault(h => h.EventType == EpisodeHistoryEventType.Grabbed);
if (lastImported == null) if (lastImported == null)
{ {

View File

@ -10,7 +10,7 @@ namespace NzbDrone.Core.MediaFiles.Events
public Exception Exception { get; set; } public Exception Exception { get; set; }
public LocalEpisode EpisodeInfo { get; } public LocalEpisode EpisodeInfo { get; }
public bool NewDownload { get; } public bool NewDownload { get; }
public string DownloadClient { get; } public DownloadClientItemClientInfo DownloadClientInfo { get; }
public string DownloadId { get; } public string DownloadId { get; }
public EpisodeImportFailedEvent(Exception exception, LocalEpisode episodeInfo, bool newDownload, DownloadClientItem downloadClientItem) public EpisodeImportFailedEvent(Exception exception, LocalEpisode episodeInfo, bool newDownload, DownloadClientItem downloadClientItem)
@ -21,7 +21,7 @@ namespace NzbDrone.Core.MediaFiles.Events
if (downloadClientItem != null) if (downloadClientItem != null)
{ {
DownloadClient = downloadClientItem.DownloadClient; DownloadClientInfo = downloadClientItem.DownloadClientInfo;
DownloadId = downloadClientItem.DownloadId; DownloadId = downloadClientItem.DownloadId;
} }
} }

View File

@ -11,7 +11,7 @@ namespace NzbDrone.Core.MediaFiles.Events
public EpisodeFile ImportedEpisode { get; private set; } public EpisodeFile ImportedEpisode { get; private set; }
public List<EpisodeFile> OldFiles { get; private set; } public List<EpisodeFile> OldFiles { get; private set; }
public bool NewDownload { 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 string DownloadId { get; private set; }
public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, List<EpisodeFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem) public EpisodeImportedEvent(LocalEpisode episodeInfo, EpisodeFile importedEpisode, List<EpisodeFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem)
@ -23,7 +23,7 @@ namespace NzbDrone.Core.MediaFiles.Events
if (downloadClientItem != null) if (downloadClientItem != null)
{ {
DownloadClient = downloadClientItem.DownloadClient; DownloadClientInfo = downloadClientItem.DownloadClientInfo;
DownloadId = downloadClientItem.DownloadId; DownloadId = downloadClientItem.DownloadId;
} }
} }

View File

@ -143,7 +143,7 @@ namespace NzbDrone.Core.Notifications
EpisodeFile = message.ImportedEpisode, EpisodeFile = message.ImportedEpisode,
OldFiles = message.OldFiles, OldFiles = message.OldFiles,
SourcePath = message.EpisodeInfo.Path, SourcePath = message.EpisodeInfo.Path,
DownloadClient = message.DownloadClient, DownloadClient = message.DownloadClientInfo?.Name,
DownloadId = message.DownloadId DownloadId = message.DownloadId
}; };

View File

@ -77,7 +77,7 @@ namespace NzbDrone.Core.Queue
RemoteEpisode = trackedDownload.RemoteEpisode, RemoteEpisode = trackedDownload.RemoteEpisode,
DownloadId = trackedDownload.DownloadItem.DownloadId, DownloadId = trackedDownload.DownloadItem.DownloadId,
Protocol = trackedDownload.Protocol, Protocol = trackedDownload.Protocol,
DownloadClient = trackedDownload.DownloadItem.DownloadClient, DownloadClient = trackedDownload.DownloadItem.DownloadClientInfo.Name,
Indexer = trackedDownload.Indexer, Indexer = trackedDownload.Indexer,
OutputPath = trackedDownload.DownloadItem.OutputPath.ToString() OutputPath = trackedDownload.DownloadItem.OutputPath.ToString()
}; };

View File

@ -35,7 +35,7 @@ namespace Sonarr.Api.V3.History
Post("/failed", x => MarkAsFailed()); 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(); var resource = model.ToResource();
@ -60,7 +60,7 @@ namespace Sonarr.Api.V3.History
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource) private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
{ {
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending); var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, EpisodeHistory>("date", SortDirection.Descending);
var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeSeries = Request.GetBooleanQueryParameter("includeSeries");
var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode");
@ -70,7 +70,7 @@ namespace Sonarr.Api.V3.History
if (eventTypeFilter != null) if (eventTypeFilter != null)
{ {
var filterValue = (HistoryEventType)Convert.ToInt32(eventTypeFilter.Value); var filterValue = (EpisodeHistoryEventType)Convert.ToInt32(eventTypeFilter.Value);
pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue); pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
} }
@ -100,13 +100,13 @@ namespace Sonarr.Api.V3.History
} }
DateTime date = DateTime.Parse(queryDate.Value); DateTime date = DateTime.Parse(queryDate.Value);
HistoryEventType? eventType = null; EpisodeHistoryEventType? eventType = null;
var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeSeries = Request.GetBooleanQueryParameter("includeSeries");
var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode");
if (queryEventType.HasValue) 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(); 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); int seriesId = Convert.ToInt32(querySeriesId.Value);
HistoryEventType? eventType = null; EpisodeHistoryEventType? eventType = null;
var includeSeries = Request.GetBooleanQueryParameter("includeSeries"); var includeSeries = Request.GetBooleanQueryParameter("includeSeries");
var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode"); var includeEpisode = Request.GetBooleanQueryParameter("includeEpisode");
if (queryEventType.HasValue) if (queryEventType.HasValue)
{ {
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); eventType = (EpisodeHistoryEventType)Convert.ToInt32(queryEventType.Value);
} }
if (querySeasonNumber.HasValue) if (querySeasonNumber.HasValue)

View File

@ -21,7 +21,7 @@ namespace Sonarr.Api.V3.History
public DateTime Date { get; set; } public DateTime Date { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public HistoryEventType EventType { get; set; } public EpisodeHistoryEventType EventType { get; set; }
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
@ -31,7 +31,7 @@ namespace Sonarr.Api.V3.History
public static class HistoryResourceMapper 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; if (model == null) return null;