mirror of https://github.com/lidarr/Lidarr
Track fully imported downloads in separate history table
This commit is contained in:
parent
1d0df366fb
commit
1eb0d3b11a
|
@ -30,7 +30,7 @@ namespace Lidarr.Api.V1.History
|
||||||
_failedDownloadService = failedDownloadService;
|
_failedDownloadService = failedDownloadService;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeArtist, bool includeAlbum, bool includeTrack)
|
protected HistoryResource MapToResource(EntityHistory model, bool includeArtist, bool includeAlbum, bool includeTrack)
|
||||||
{
|
{
|
||||||
var resource = model.ToResource();
|
var resource = model.ToResource();
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ namespace Lidarr.Api.V1.History
|
||||||
public PagingResource<HistoryResource> GetHistory(bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
public PagingResource<HistoryResource> GetHistory(bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
var pagingResource = Request.ReadPagingResourceFromRequest<HistoryResource>();
|
var pagingResource = Request.ReadPagingResourceFromRequest<HistoryResource>();
|
||||||
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending);
|
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, EntityHistory>("date", SortDirection.Descending);
|
||||||
|
|
||||||
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
||||||
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
||||||
|
@ -69,7 +69,7 @@ namespace Lidarr.Api.V1.History
|
||||||
|
|
||||||
if (eventTypeFilter != null)
|
if (eventTypeFilter != null)
|
||||||
{
|
{
|
||||||
var filterValue = (HistoryEventType)Convert.ToInt32(eventTypeFilter.Value);
|
var filterValue = (EntityHistoryEventType)Convert.ToInt32(eventTypeFilter.Value);
|
||||||
pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
|
pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +89,13 @@ namespace Lidarr.Api.V1.History
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("since")]
|
[HttpGet("since")]
|
||||||
public List<HistoryResource> GetHistorySince(DateTime date, HistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
public List<HistoryResource> GetHistorySince(DateTime date, EntityHistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("artist")]
|
[HttpGet("artist")]
|
||||||
public List<HistoryResource> GetArtistHistory(int artistId, int? albumId = null, HistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
public List<HistoryResource> GetArtistHistory(int artistId, int? albumId = null, EntityHistoryEventType? eventType = null, bool includeArtist = false, bool includeAlbum = false, bool includeTrack = false)
|
||||||
{
|
{
|
||||||
if (albumId.HasValue)
|
if (albumId.HasValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Lidarr.Api.V1.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 EntityHistoryEventType EventType { get; set; }
|
||||||
|
|
||||||
public Dictionary<string, string> Data { get; set; }
|
public Dictionary<string, string> Data { get; set; }
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace Lidarr.Api.V1.History
|
||||||
|
|
||||||
public static class HistoryResourceMapper
|
public static class HistoryResourceMapper
|
||||||
{
|
{
|
||||||
public static HistoryResource ToResource(this NzbDrone.Core.History.History model)
|
public static HistoryResource ToResource(this EntityHistory model)
|
||||||
{
|
{
|
||||||
if (model == null)
|
if (model == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
@ -58,21 +59,21 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
{
|
{
|
||||||
var quality = new QualityModel { Quality = Quality.MP3_320, Revision = new Revision(version: 2) };
|
var quality = new QualityModel { Quality = Quality.MP3_320, Revision = new Revision(version: 2) };
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateNew()
|
var history = Builder<EntityHistory>.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<EntityHistory>().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<EntityHistory>.CreateListOfSize(2)
|
||||||
.All().With(c => c.Id = 0)
|
.All().With(c => c.Id = 0)
|
||||||
.Build().ToList();
|
.Build().ToList();
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
|
|
||||||
Db.InsertMany(history);
|
Db.InsertMany(history);
|
||||||
|
|
||||||
var returnedHistory = Db.All<History.History>();
|
var returnedHistory = Db.All<EntityHistory>();
|
||||||
|
|
||||||
returnedHistory[0].Quality.Quality.Should().Be(Quality.MP3_320);
|
returnedHistory[0].Quality.Quality.Should().Be(Quality.MP3_320);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
private QualityModel _mp3;
|
private QualityModel _mp3;
|
||||||
private QualityModel _flac;
|
private QualityModel _flac;
|
||||||
private RemoteAlbum _remoteAlbum;
|
private RemoteAlbum _remoteAlbum;
|
||||||
private List<History.History> _history;
|
private List<EntityHistory> _history;
|
||||||
private TrackFile _firstFile;
|
private TrackFile _firstFile;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
.Build()
|
.Build()
|
||||||
};
|
};
|
||||||
|
|
||||||
_history = new List<History.History>();
|
_history = new List<EntityHistory>();
|
||||||
|
|
||||||
Mocker.GetMock<IConfigService>()
|
Mocker.GetMock<IConfigService>()
|
||||||
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||||
|
@ -80,9 +80,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, EntityHistoryEventType eventType)
|
||||||
{
|
{
|
||||||
_history.Add(new History.History
|
_history.Add(new EntityHistory
|
||||||
{
|
{
|
||||||
DownloadId = downloadId,
|
DownloadId = downloadId,
|
||||||
SourceTitle = sourceTitle,
|
SourceTitle = sourceTitle,
|
||||||
|
@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[Test]
|
[Test]
|
||||||
public void should_be_accepted_if_album_does_not_have_imported_event()
|
public void should_be_accepted_if_album_does_not_have_imported_event()
|
||||||
{
|
{
|
||||||
GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
|
Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
GivenHistoryItem(downloadId, TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(downloadId, TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryItem(downloadId, TITLE, _mp3, HistoryEventType.DownloadImported);
|
GivenHistoryItem(downloadId, TITLE, _mp3, EntityHistoryEventType.DownloadImported);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
|
Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
@ -140,8 +140,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
GivenHistoryItem(downloadId, TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(downloadId, TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryItem(downloadId, TITLE, _flac, HistoryEventType.DownloadImported);
|
GivenHistoryItem(downloadId, TITLE, _flac, EntityHistoryEventType.DownloadImported);
|
||||||
|
|
||||||
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
@ -156,8 +156,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
GivenHistoryItem(downloadId, TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(downloadId, TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryItem(downloadId, TITLE, _flac, HistoryEventType.DownloadImported);
|
GivenHistoryItem(downloadId, TITLE, _flac, EntityHistoryEventType.DownloadImported);
|
||||||
|
|
||||||
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
@ -170,8 +170,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[Test]
|
[Test]
|
||||||
public void should_be_accepted_if_release_torrent_hash_is_null_and_downloadId_is_null()
|
public void should_be_accepted_if_release_torrent_hash_is_null_and_downloadId_is_null()
|
||||||
{
|
{
|
||||||
GivenHistoryItem(null, TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(null, TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryItem(null, TITLE, _flac, HistoryEventType.DownloadImported);
|
GivenHistoryItem(null, TITLE, _flac, EntityHistoryEventType.DownloadImported);
|
||||||
|
|
||||||
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
@ -186,8 +186,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
GivenHistoryItem(downloadId, TITLE, _mp3, HistoryEventType.Grabbed);
|
GivenHistoryItem(downloadId, TITLE, _mp3, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryItem(downloadId, TITLE, _flac, HistoryEventType.DownloadImported);
|
GivenHistoryItem(downloadId, TITLE, _flac, EntityHistoryEventType.DownloadImported);
|
||||||
|
|
||||||
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
_remoteAlbum.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
|
|
@ -76,10 +76,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenMostRecentForAlbum(int albumId, string downloadId, QualityModel quality, DateTime date, HistoryEventType eventType)
|
private void GivenMostRecentForAlbum(int albumId, string downloadId, QualityModel quality, DateTime date, EntityHistoryEventType eventType)
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForAlbum(albumId))
|
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForAlbum(albumId))
|
||||||
.Returns(new History.History { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType });
|
.Returns(new EntityHistory { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenCdhDisabled()
|
private void GivenCdhDisabled()
|
||||||
|
@ -98,14 +98,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[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.MostRecentForAlbum(It.IsAny<int>())).Returns((History.History)null);
|
Mocker.GetMock<IHistoryService>().Setup(s => s.MostRecentForAlbum(It.IsAny<int>())).Returns((EntityHistory)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()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.DownloadFailed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EntityHistoryEventType.DownloadFailed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,46 +118,46 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[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()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-12).AddMilliseconds(-1), HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-12).AddMilliseconds(-1), EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_be_upgradable_if_only_album_is_upgradable()
|
public void should_be_upgradable_if_only_album_is_upgradable()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
|
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_be_upgradable_if_both_albums_are_upgradable()
|
public void should_be_upgradable_if_both_albums_are_upgradable()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.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_albums_are_not_upgradable()
|
public void should_not_be_upgradable_if_both_albums_are_not_upgradable()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EntityHistoryEventType.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_albums_is_upgradable()
|
public void should_be_not_upgradable_if_only_first_albums_is_upgradable()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EntityHistoryEventType.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_albums_is_upgradable()
|
public void should_be_not_upgradable_if_only_second_albums_is_upgradable()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(SECOND_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
|
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
|
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[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()
|
||||||
{
|
{
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-1), EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
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();
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
_upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_parseResultSingle.ParsedAlbumInfo.Quality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
_upgradableQuality = new QualityModel(Quality.MP3_320, new Revision(version: 1));
|
||||||
|
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _upgradableQuality, DateTime.UtcNow.AddDays(-100), EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
public void should_return_false_if_only_album_is_not_upgradable_and_cdh_is_disabled()
|
public void should_return_false_if_only_album_is_not_upgradable_and_cdh_is_disabled()
|
||||||
{
|
{
|
||||||
GivenCdhDisabled();
|
GivenCdhDisabled();
|
||||||
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), HistoryEventType.Grabbed);
|
GivenMostRecentForAlbum(FIRST_ALBUM_ID, "test", _notupgradableQuality, DateTime.UtcNow.AddDays(-100), EntityHistoryEventType.Grabbed);
|
||||||
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
_upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,16 @@ 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 EntityHistory());
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetArtist("Drone.S01E01.HDTV"))
|
.Setup(s => s.GetArtist("Drone.S01E01.HDTV"))
|
||||||
.Returns(remoteAlbum.Artist);
|
.Returns(remoteAlbum.Artist);
|
||||||
|
|
||||||
|
Mocker.GetMock<IHistoryService>()
|
||||||
|
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
||||||
|
.Returns(new List<EntityHistory>());
|
||||||
|
|
||||||
Mocker.GetMock<IProvideImportItemService>()
|
Mocker.GetMock<IProvideImportItemService>()
|
||||||
.Setup(s => s.ProvideImportItem(It.IsAny<DownloadClientItem>(), It.IsAny<DownloadClientItem>()))
|
.Setup(s => s.ProvideImportItem(It.IsAny<DownloadClientItem>(), It.IsAny<DownloadClientItem>()))
|
||||||
.Returns<DownloadClientItem, DownloadClientItem>((i, p) => i);
|
.Returns<DownloadClientItem, DownloadClientItem>((i, p) => i);
|
||||||
|
@ -93,7 +97,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 EntityHistory() { SourceTitle = "Droned S01E01" });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetArtist(It.IsAny<string>()))
|
.Setup(s => s.GetArtist(It.IsAny<string>()))
|
||||||
|
@ -158,18 +162,6 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
AssertNotImported();
|
AssertNotImported();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_not_mark_as_failed_if_nothing_found_to_import()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IDownloadedTracksImportService>()
|
|
||||||
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Artist>(), It.IsAny<DownloadClientItem>()))
|
|
||||||
.Returns(new List<ImportResult>());
|
|
||||||
|
|
||||||
Subject.Import(_trackedDownload);
|
|
||||||
|
|
||||||
_trackedDownload.State.Should().Be(TrackedDownloadState.ImportPending);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_mark_as_imported_if_all_files_were_skipped()
|
public void should_not_mark_as_imported_if_all_files_were_skipped()
|
||||||
{
|
{
|
||||||
|
@ -206,6 +198,10 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Mocker.GetMock<IHistoryService>()
|
||||||
|
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
||||||
|
.Returns(new List<EntityHistory>());
|
||||||
|
|
||||||
Subject.Import(_trackedDownload);
|
Subject.Import(_trackedDownload);
|
||||||
|
|
||||||
AssertImported();
|
AssertImported();
|
||||||
|
@ -232,7 +228,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv".AsOsAgnostic() }), "Test Failure")
|
||||||
});
|
});
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(2)
|
var history = Builder<EntityHistory>.CreateListOfSize(2)
|
||||||
.BuildList();
|
.BuildList();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
|
@ -275,7 +271,7 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv" }), "Test Failure")
|
new ImportResult(new ImportDecision<LocalTrack>(new LocalTrack { Path = @"C:\TestPath\Droned.S01E01.mkv" }), "Test Failure")
|
||||||
});
|
});
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(2)
|
var history = Builder<EntityHistory>.CreateListOfSize(2)
|
||||||
.BuildList();
|
.BuildList();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
|
@ -283,7 +279,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<EntityHistory>>()))
|
||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
|
||||||
Subject.Import(_trackedDownload);
|
Subject.Import(_trackedDownload);
|
||||||
|
@ -347,15 +343,18 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||||
new LocalTrack { Path = @"C:\TestPath\Droned.S01E02.mkv", Tracks = new List<Track> { track2 } }), "Test Failure")
|
new LocalTrack { Path = @"C:\TestPath\Droned.S01E02.mkv", Tracks = new List<Track> { track2 } }), "Test Failure")
|
||||||
});
|
});
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(2)
|
var history = Builder<EntityHistory>.CreateListOfSize(2)
|
||||||
.BuildList();
|
.All()
|
||||||
|
.With(x => x.EventType = EntityHistoryEventType.TrackFileImported)
|
||||||
|
.With(x => x.ArtistId = 1)
|
||||||
|
.BuildList();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
||||||
.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<EntityHistory>>()))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
Subject.Import(_trackedDownload);
|
Subject.Import(_trackedDownload);
|
||||||
|
|
|
@ -51,7 +51,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 EntityHistory());
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetArtist("Drone.S01E01.HDTV"))
|
.Setup(s => s.GetArtist("Drone.S01E01.HDTV"))
|
||||||
|
@ -71,7 +71,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((EntityHistory)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenArtistMatch()
|
private void GivenArtistMatch()
|
||||||
|
@ -87,7 +87,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 EntityHistory() { SourceTitle = "Droned S01E01" });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetArtist(It.IsAny<string>()))
|
.Setup(s => s.GetArtist(It.IsAny<string>()))
|
||||||
|
|
|
@ -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<EntityHistory> _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<EntityHistory>.CreateListOfSize(2).BuildList();
|
||||||
|
|
||||||
var remoteAlbum = new RemoteAlbum
|
var remoteAlbum = new RemoteAlbum
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed))
|
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed))
|
||||||
.Returns(_grabHistory);
|
.Returns(_grabHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<EntityHistory> _grabHistory;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
|
||||||
.With(h => h.Title = "Drone.DroneTheAlbum.FLAC")
|
.With(h => h.Title = "Drone.DroneTheAlbum.FLAC")
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_grabHistory = Builder<History.History>.CreateListOfSize(2).BuildList();
|
_grabHistory = Builder<EntityHistory>.CreateListOfSize(2).BuildList();
|
||||||
|
|
||||||
var remoteAlbum = new RemoteAlbum
|
var remoteAlbum = new RemoteAlbum
|
||||||
{
|
{
|
||||||
|
@ -45,15 +45,15 @@ namespace NzbDrone.Core.Test.Download.FailedDownloadServiceTests
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed))
|
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed))
|
||||||
.Returns(_grabHistory);
|
.Returns(_grabHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
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, EntityHistoryEventType.Grabbed))
|
||||||
.Returns(new List<History.History>());
|
.Returns(new List<EntityHistory>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
@ -15,7 +16,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
private List<Album> _albums;
|
private List<Album> _albums;
|
||||||
private TrackedDownload _trackedDownload;
|
private TrackedDownload _trackedDownload;
|
||||||
private List<History.History> _historyItems;
|
private List<EntityHistory> _historyItems;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
@ -26,11 +27,14 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
.With(r => r.Albums = _albums)
|
.With(r => r.Albums = _albums)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
var downloadItem = Builder<DownloadClientItem>.CreateNew().Build();
|
||||||
|
|
||||||
_trackedDownload = Builder<TrackedDownload>.CreateNew()
|
_trackedDownload = Builder<TrackedDownload>.CreateNew()
|
||||||
.With(t => t.RemoteAlbum = remoteAlbum)
|
.With(t => t.RemoteAlbum = remoteAlbum)
|
||||||
|
.With(t => t.DownloadItem = downloadItem)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_historyItems = new List<History.History>();
|
_historyItems = new List<EntityHistory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GivenEpisodes(int count)
|
public void GivenEpisodes(int count)
|
||||||
|
@ -39,12 +43,12 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
.BuildList());
|
.BuildList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GivenHistoryForEpisode(Album episode, params HistoryEventType[] eventTypes)
|
public void GivenHistoryForEpisode(Album episode, params EntityHistoryEventType[] eventTypes)
|
||||||
{
|
{
|
||||||
foreach (var eventType in eventTypes)
|
foreach (var eventType in eventTypes)
|
||||||
{
|
{
|
||||||
_historyItems.Add(
|
_historyItems.Add(
|
||||||
Builder<History.History>.CreateNew()
|
Builder<EntityHistory>.CreateNew()
|
||||||
.With(h => h.AlbumId = episode.Id)
|
.With(h => h.AlbumId = episode.Id)
|
||||||
.With(h => h.EventType = eventType)
|
.With(h => h.EventType = eventType)
|
||||||
.Build());
|
.Build());
|
||||||
|
@ -66,7 +70,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
GivenEpisodes(1);
|
GivenEpisodes(1);
|
||||||
|
|
||||||
GivenHistoryForEpisode(_albums[0], HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[0], EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsImported(_trackedDownload, _historyItems)
|
Subject.IsImported(_trackedDownload, _historyItems)
|
||||||
.Should()
|
.Should()
|
||||||
|
@ -78,8 +82,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
GivenEpisodes(2);
|
GivenEpisodes(2);
|
||||||
|
|
||||||
GivenHistoryForEpisode(_albums[0], HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[0], EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryForEpisode(_albums[1], HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[1], EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsImported(_trackedDownload, _historyItems)
|
Subject.IsImported(_trackedDownload, _historyItems)
|
||||||
.Should()
|
.Should()
|
||||||
|
@ -91,8 +95,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
GivenEpisodes(2);
|
GivenEpisodes(2);
|
||||||
|
|
||||||
GivenHistoryForEpisode(_albums[0], HistoryEventType.DownloadImported, HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[0], EntityHistoryEventType.DownloadImported, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryForEpisode(_albums[1], HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[1], EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsImported(_trackedDownload, _historyItems)
|
Subject.IsImported(_trackedDownload, _historyItems)
|
||||||
.Should()
|
.Should()
|
||||||
|
@ -104,7 +108,7 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
GivenEpisodes(1);
|
GivenEpisodes(1);
|
||||||
|
|
||||||
GivenHistoryForEpisode(_albums[0], HistoryEventType.DownloadImported, HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[0], EntityHistoryEventType.DownloadImported, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsImported(_trackedDownload, _historyItems)
|
Subject.IsImported(_trackedDownload, _historyItems)
|
||||||
.Should()
|
.Should()
|
||||||
|
@ -116,8 +120,8 @@ namespace NzbDrone.Core.Test.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
GivenEpisodes(2);
|
GivenEpisodes(2);
|
||||||
|
|
||||||
GivenHistoryForEpisode(_albums[0], HistoryEventType.DownloadImported, HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[0], EntityHistoryEventType.DownloadImported, EntityHistoryEventType.Grabbed);
|
||||||
GivenHistoryForEpisode(_albums[1], HistoryEventType.DownloadImported, HistoryEventType.Grabbed);
|
GivenHistoryForEpisode(_albums[1], EntityHistoryEventType.DownloadImported, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
Subject.IsImported(_trackedDownload, _historyItems)
|
Subject.IsImported(_trackedDownload, _historyItems)
|
||||||
.Should()
|
.Should()
|
||||||
|
|
|
@ -22,9 +22,9 @@ 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<EntityHistory>()
|
||||||
{
|
{
|
||||||
new History.History()
|
new EntityHistory()
|
||||||
{
|
{
|
||||||
DownloadId = "35238",
|
DownloadId = "35238",
|
||||||
SourceTitle = "Audio Artist - Audio Album [2018 - FLAC]",
|
SourceTitle = "Audio Artist - Audio Album [2018 - FLAC]",
|
||||||
|
|
|
@ -71,6 +71,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||||
.Setup(s => s.GetDownloadClients())
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||||
|
|
||||||
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
|
.Setup(s => s.Get(It.IsAny<int>()))
|
||||||
|
.Returns(_downloadClient.Object);
|
||||||
|
|
||||||
Mocker.GetMock<IConfigService>()
|
Mocker.GetMock<IConfigService>()
|
||||||
.Setup(s => s.EnableCompletedDownloadHandling)
|
.Setup(s => s.EnableCompletedDownloadHandling)
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
|
@ -8,12 +8,12 @@ using NzbDrone.Core.Test.Framework;
|
||||||
namespace NzbDrone.Core.Test.HistoryTests
|
namespace NzbDrone.Core.Test.HistoryTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class HistoryRepositoryFixture : DbTest<HistoryRepository, History.History>
|
public class HistoryRepositoryFixture : DbTest<EntityHistoryRepository, EntityHistory>
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void should_read_write_dictionary()
|
public void should_read_write_dictionary()
|
||||||
{
|
{
|
||||||
var history = Builder<History.History>.CreateNew()
|
var history = Builder<EntityHistory>.CreateNew()
|
||||||
.With(c => c.Quality = new QualityModel())
|
.With(c => c.Quality = new QualityModel())
|
||||||
.BuildNew();
|
.BuildNew();
|
||||||
|
|
||||||
|
@ -28,16 +28,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<EntityHistory>.CreateNew()
|
||||||
.With(c => c.Quality = new QualityModel(Quality.MP3_320))
|
.With(c => c.Quality = new QualityModel(Quality.MP3_320))
|
||||||
.With(c => c.ArtistId = 12)
|
.With(c => c.ArtistId = 12)
|
||||||
.With(c => c.EventType = HistoryEventType.Grabbed)
|
.With(c => c.EventType = EntityHistoryEventType.Grabbed)
|
||||||
.BuildNew();
|
.BuildNew();
|
||||||
|
|
||||||
var historyDvd = Builder<History.History>.CreateNew()
|
var historyDvd = Builder<EntityHistory>.CreateNew()
|
||||||
.With(c => c.Quality = new QualityModel(Quality.MP3_192))
|
.With(c => c.Quality = new QualityModel(Quality.MP3_192))
|
||||||
.With(c => c.ArtistId = 12)
|
.With(c => c.ArtistId = 12)
|
||||||
.With(c => c.EventType = HistoryEventType.Grabbed)
|
.With(c => c.EventType = EntityHistoryEventType.Grabbed)
|
||||||
.BuildNew();
|
.BuildNew();
|
||||||
|
|
||||||
Subject.Insert(historyBluray);
|
Subject.Insert(historyBluray);
|
||||||
|
|
|
@ -18,7 +18,7 @@ using NzbDrone.Core.Test.Qualities;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.HistoryTests
|
namespace NzbDrone.Core.Test.HistoryTests
|
||||||
{
|
{
|
||||||
public class HistoryServiceFixture : CoreTest<HistoryService>
|
public class HistoryServiceFixture : CoreTest<EntityHistoryService>
|
||||||
{
|
{
|
||||||
private QualityProfile _profile;
|
private QualityProfile _profile;
|
||||||
private QualityProfile _profileCustom;
|
private QualityProfile _profileCustom;
|
||||||
|
@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.HistoryTests
|
||||||
Subject.Handle(new TrackImportedEvent(localTrack, trackFile, new List<TrackFile>(), true, downloadClientItem));
|
Subject.Handle(new TrackImportedEvent(localTrack, trackFile, new List<TrackFile>(), true, downloadClientItem));
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryRepository>()
|
Mocker.GetMock<IHistoryRepository>()
|
||||||
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localTrack.Path))));
|
.Verify(v => v.Insert(It.Is<EntityHistory>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localTrack.Path))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
|
@ -9,7 +10,7 @@ using NzbDrone.Core.Test.Framework;
|
||||||
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, EntityHistory>
|
||||||
{
|
{
|
||||||
private Artist _artist;
|
private Artist _artist;
|
||||||
private Album _album;
|
private Album _album;
|
||||||
|
@ -39,7 +40,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
{
|
{
|
||||||
GivenAlbum();
|
GivenAlbum();
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateNew()
|
var history = Builder<EntityHistory>.CreateNew()
|
||||||
.With(h => h.Quality = new QualityModel())
|
.With(h => h.Quality = new QualityModel())
|
||||||
.With(h => h.AlbumId = _album.Id)
|
.With(h => h.AlbumId = _album.Id)
|
||||||
.BuildNew();
|
.BuildNew();
|
||||||
|
@ -54,7 +55,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
{
|
{
|
||||||
GivenArtist();
|
GivenArtist();
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateNew()
|
var history = Builder<EntityHistory>.CreateNew()
|
||||||
.With(h => h.Quality = new QualityModel())
|
.With(h => h.Quality = new QualityModel())
|
||||||
.With(h => h.ArtistId = _artist.Id)
|
.With(h => h.ArtistId = _artist.Id)
|
||||||
.BuildNew();
|
.BuildNew();
|
||||||
|
@ -70,7 +71,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
GivenArtist();
|
GivenArtist();
|
||||||
GivenAlbum();
|
GivenAlbum();
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(2)
|
var history = Builder<EntityHistory>.CreateListOfSize(2)
|
||||||
.All()
|
.All()
|
||||||
.With(h => h.Quality = new QualityModel())
|
.With(h => h.Quality = new QualityModel())
|
||||||
.With(h => h.AlbumId = _album.Id)
|
.With(h => h.AlbumId = _album.Id)
|
||||||
|
@ -91,7 +92,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
GivenArtist();
|
GivenArtist();
|
||||||
GivenAlbum();
|
GivenAlbum();
|
||||||
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(2)
|
var history = Builder<EntityHistory>.CreateListOfSize(2)
|
||||||
.All()
|
.All()
|
||||||
.With(h => h.Quality = new QualityModel())
|
.With(h => h.Quality = new QualityModel())
|
||||||
.With(h => h.ArtistId = _artist.Id)
|
.With(h => h.ArtistId = _artist.Id)
|
||||||
|
|
|
@ -79,8 +79,8 @@ namespace NzbDrone.Core.Test.MusicTests
|
||||||
.Returns(new List<TrackFile>());
|
.Returns(new List<TrackFile>());
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(x => x.GetByAlbum(It.IsAny<int>(), It.IsAny<HistoryEventType?>()))
|
.Setup(x => x.GetByAlbum(It.IsAny<int>(), It.IsAny<EntityHistoryEventType?>()))
|
||||||
.Returns(new List<History.History>());
|
.Returns(new List<EntityHistory>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenNewAlbumInfo(Album album)
|
private void GivenNewAlbumInfo(Album album)
|
||||||
|
|
|
@ -64,8 +64,8 @@ namespace NzbDrone.Core.Test.MusicTests
|
||||||
.Returns(new List<TrackFile>());
|
.Returns(new List<TrackFile>());
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(x => x.GetByArtist(It.IsAny<int>(), It.IsAny<HistoryEventType?>()))
|
.Setup(x => x.GetByArtist(It.IsAny<int>(), It.IsAny<EntityHistoryEventType?>()))
|
||||||
.Returns(new List<History.History>());
|
.Returns(new List<EntityHistory>());
|
||||||
|
|
||||||
Mocker.GetMock<IImportListExclusionService>()
|
Mocker.GetMock<IImportListExclusionService>()
|
||||||
.Setup(x => x.FindByForeignId(It.IsAny<List<string>>()))
|
.Setup(x => x.FindByForeignId(It.IsAny<List<string>>()))
|
||||||
|
|
|
@ -51,12 +51,12 @@ namespace NzbDrone.Core.Test.QueueTests
|
||||||
.Build()
|
.Build()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var historyItem = Builder<History.History>.CreateNew()
|
var historyItem = Builder<EntityHistory>.CreateNew()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(c => c.Find(It.IsAny<string>(), HistoryEventType.Grabbed)).Returns(
|
.Setup(c => c.Find(It.IsAny<string>(), EntityHistoryEventType.Grabbed)).Returns(
|
||||||
new List<History.History> { historyItem });
|
new List<EntityHistory> { historyItem });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -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<EntityHistory>() { 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);
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
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(052)]
|
||||||
|
public class download_history : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Create.TableForModel("DownloadHistory")
|
||||||
|
.WithColumn("EventType").AsInt32().NotNullable()
|
||||||
|
.WithColumn("ArtistId").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("ArtistId");
|
||||||
|
Create.Index().OnTable("DownloadHistory").OnColumn("DownloadId");
|
||||||
|
|
||||||
|
Execute.WithConnection(InitialImportedDownloadHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, int> EventTypeMap = new Dictionary<int, int>()
|
||||||
|
{
|
||||||
|
// EntityHistoryType.Grabbed -> DownloadHistoryType.Grabbed
|
||||||
|
{ 1, 1 },
|
||||||
|
|
||||||
|
// EntityHistoryType.DownloadFolderImported -> DownloadHistoryType.DownloadImported
|
||||||
|
{ 8, 2 },
|
||||||
|
|
||||||
|
// EntityHistoryType.DownloadFailed -> DownloadHistoryType.DownloadFailed
|
||||||
|
{ 4, 3 },
|
||||||
|
|
||||||
|
// EntityHistoryType.DownloadIgnored -> DownloadHistoryType.DownloadIgnored
|
||||||
|
{ 10, 4 },
|
||||||
|
|
||||||
|
// EntityHistoryType.DownloadImportIncomplete -> DownloadHistoryType.DownloadImportIncomplete
|
||||||
|
{ 7, 6 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private void InitialImportedDownloadHistory(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
using (var cmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
cmd.Transaction = tran;
|
||||||
|
cmd.CommandText = "SELECT ArtistId, DownloadId, EventType, SourceTitle, Date, Data FROM History WHERE DownloadId IS NOT NULL AND EventType IN (1, 8, 4, 10, 7) GROUP BY EventType, DownloadId";
|
||||||
|
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
var artistId = 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, ArtistId, DownloadId, SourceTitle, Date, Protocol, Data) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
updateCmd.AddParameter(downloadHistoryEventType);
|
||||||
|
updateCmd.AddParameter(artistId);
|
||||||
|
updateCmd.AddParameter(downloadId);
|
||||||
|
updateCmd.AddParameter(sourceTitle);
|
||||||
|
updateCmd.AddParameter(date);
|
||||||
|
updateCmd.AddParameter(protocol);
|
||||||
|
updateCmd.AddParameter(downloadHistoryData.ToJson());
|
||||||
|
|
||||||
|
updateCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,11 +9,13 @@ using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.CustomFilters;
|
using NzbDrone.Core.CustomFilters;
|
||||||
using NzbDrone.Core.Datastore.Converters;
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Download.History;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
using NzbDrone.Core.Extras.Lyrics;
|
using NzbDrone.Core.Extras.Lyrics;
|
||||||
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.History;
|
||||||
using NzbDrone.Core.ImportLists;
|
using NzbDrone.Core.ImportLists;
|
||||||
using NzbDrone.Core.ImportLists.Exclusions;
|
using NzbDrone.Core.ImportLists.Exclusions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
|
@ -93,7 +95,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
.Ignore(d => d.Protocol)
|
.Ignore(d => d.Protocol)
|
||||||
.Ignore(d => d.Tags);
|
.Ignore(d => d.Tags);
|
||||||
|
|
||||||
Mapper.Entity<History.History>("History").RegisterModel();
|
Mapper.Entity<EntityHistory>("History").RegisterModel();
|
||||||
|
|
||||||
Mapper.Entity<Artist>("Artists")
|
Mapper.Entity<Artist>("Artists")
|
||||||
.Ignore(s => s.RootFolderPath)
|
.Ignore(s => s.RootFolderPath)
|
||||||
|
@ -188,6 +190,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
|
|
||||||
Mapper.Entity<CustomFilter>("CustomFilters").RegisterModel();
|
Mapper.Entity<CustomFilter>("CustomFilters").RegisterModel();
|
||||||
Mapper.Entity<ImportListExclusion>("ImportListExclusions").RegisterModel();
|
Mapper.Entity<ImportListExclusion>("ImportListExclusions").RegisterModel();
|
||||||
|
Mapper.Entity<DownloadHistory>("DownloadHistory").RegisterModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterMappers()
|
private static void RegisterMappers()
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
}
|
}
|
||||||
|
|
||||||
var historyForAlbum = _historyService.GetByAlbum(album.Id, null);
|
var historyForAlbum = _historyService.GetByAlbum(album.Id, null);
|
||||||
var lastGrabbed = historyForAlbum.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed);
|
var lastGrabbed = historyForAlbum.FirstOrDefault(h => h.EventType == EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
if (lastGrabbed == null)
|
if (lastGrabbed == null)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +61,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
}
|
}
|
||||||
|
|
||||||
var imported = historyForAlbum.FirstOrDefault(h =>
|
var imported = historyForAlbum.FirstOrDefault(h =>
|
||||||
h.EventType == HistoryEventType.DownloadImported &&
|
h.EventType == EntityHistoryEventType.DownloadImported &&
|
||||||
h.DownloadId == lastGrabbed.DownloadId);
|
h.DownloadId == lastGrabbed.DownloadId);
|
||||||
|
|
||||||
if (imported == null)
|
if (imported == null)
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||||
_logger.Debug("Checking current status of album [{0}] in history", album.Id);
|
_logger.Debug("Checking current status of album [{0}] in history", album.Id);
|
||||||
var mostRecent = _historyService.MostRecentForAlbum(album.Id);
|
var mostRecent = _historyService.MostRecentForAlbum(album.Id);
|
||||||
|
|
||||||
if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed)
|
if (mostRecent != null && mostRecent.EventType == EntityHistoryEventType.Grabbed)
|
||||||
{
|
{
|
||||||
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
|
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using NzbDrone.Common.Messaging;
|
using NzbDrone.Common.Messaging;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
|
@ -6,7 +6,9 @@ namespace NzbDrone.Core.Download
|
||||||
public class AlbumGrabbedEvent : IEvent
|
public class AlbumGrabbedEvent : IEvent
|
||||||
{
|
{
|
||||||
public RemoteAlbum Album { get; private set; }
|
public RemoteAlbum Album { 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 AlbumGrabbedEvent(RemoteAlbum album)
|
public AlbumGrabbedEvent(RemoteAlbum album)
|
||||||
|
|
|
@ -17,8 +17,10 @@ namespace NzbDrone.Core.Download.Clients.Flood
|
||||||
public class Flood : TorrentClientBase<FloodSettings>
|
public class Flood : TorrentClientBase<FloodSettings>
|
||||||
{
|
{
|
||||||
private readonly IFloodProxy _proxy;
|
private readonly IFloodProxy _proxy;
|
||||||
|
private readonly IDownloadSeedConfigProvider _downloadSeedConfigProvider;
|
||||||
|
|
||||||
public Flood(IFloodProxy proxy,
|
public Flood(IFloodProxy proxy,
|
||||||
|
IDownloadSeedConfigProvider downloadSeedConfigProvider,
|
||||||
ITorrentFileInfoReader torrentFileInfoReader,
|
ITorrentFileInfoReader torrentFileInfoReader,
|
||||||
IHttpClient httpClient,
|
IHttpClient httpClient,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
|
@ -28,6 +30,7 @@ namespace NzbDrone.Core.Download.Clients.Flood
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
|
_downloadSeedConfigProvider = downloadSeedConfigProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> HandleTags(RemoteAlbum remoteAlbum, FloodSettings settings)
|
private static IEnumerable<string> HandleTags(RemoteAlbum remoteAlbum, FloodSettings settings)
|
||||||
|
@ -137,6 +140,29 @@ namespace NzbDrone.Core.Download.Clients.Flood
|
||||||
item.Status = DownloadItemStatus.Paused;
|
item.Status = DownloadItemStatus.Paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.Status == DownloadItemStatus.Completed)
|
||||||
|
{
|
||||||
|
// Grab cached seedConfig
|
||||||
|
var seedConfig = _downloadSeedConfigProvider.GetSeedConfiguration(item.DownloadId);
|
||||||
|
|
||||||
|
if (seedConfig != null)
|
||||||
|
{
|
||||||
|
if (item.SeedRatio >= seedConfig.Ratio)
|
||||||
|
{
|
||||||
|
// Check if seed ratio reached
|
||||||
|
item.CanMoveFiles = item.CanBeRemoved = true;
|
||||||
|
}
|
||||||
|
else if (properties.DateFinished != null && properties.DateFinished > 0)
|
||||||
|
{
|
||||||
|
// Check if seed time reached
|
||||||
|
if ((DateTimeOffset.Now - DateTimeOffset.FromUnixTimeSeconds((long)properties.DateFinished)) >= seedConfig.SeedTime)
|
||||||
|
{
|
||||||
|
item.CanMoveFiles = item.CanBeRemoved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
items.Add(item);
|
items.Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Threading;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
|
@ -22,6 +23,8 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
{
|
{
|
||||||
private readonly IRTorrentProxy _proxy;
|
private readonly IRTorrentProxy _proxy;
|
||||||
private readonly IRTorrentDirectoryValidator _rTorrentDirectoryValidator;
|
private readonly IRTorrentDirectoryValidator _rTorrentDirectoryValidator;
|
||||||
|
private readonly IDownloadSeedConfigProvider _downloadSeedConfigProvider;
|
||||||
|
private readonly string _imported_view = string.Concat(BuildInfo.AppName.ToLower(), "_imported");
|
||||||
|
|
||||||
public RTorrent(IRTorrentProxy proxy,
|
public RTorrent(IRTorrentProxy proxy,
|
||||||
ITorrentFileInfoReader torrentFileInfoReader,
|
ITorrentFileInfoReader torrentFileInfoReader,
|
||||||
|
@ -29,12 +32,14 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IRemotePathMappingService remotePathMappingService,
|
IRemotePathMappingService remotePathMappingService,
|
||||||
|
IDownloadSeedConfigProvider downloadSeedConfigProvider,
|
||||||
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
|
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
|
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;
|
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;
|
||||||
|
_downloadSeedConfigProvider = downloadSeedConfigProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MarkItemAsImported(DownloadClientItem downloadClientItem)
|
public override void MarkItemAsImported(DownloadClientItem downloadClientItem)
|
||||||
|
@ -55,6 +60,16 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
downloadClientItem.Title);
|
downloadClientItem.Title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set post-import view
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_proxy.PushTorrentUniqueView(downloadClientItem.DownloadId.ToLower(), _imported_view, Settings);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "Failed to set torrent post-import view \"{0}\" for {1} in rTorrent.", _imported_view, downloadClientItem.Title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string AddFromMagnetLink(RemoteAlbum remoteAlbum, string hash, string magnetLink)
|
protected override string AddFromMagnetLink(RemoteAlbum remoteAlbum, string hash, string magnetLink)
|
||||||
|
@ -152,8 +167,15 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
item.Status = DownloadItemStatus.Paused;
|
item.Status = DownloadItemStatus.Paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No stop ratio data is present, so do not delete
|
// Grab cached seedConfig
|
||||||
item.CanMoveFiles = item.CanBeRemoved = false;
|
var seedConfig = _downloadSeedConfigProvider.GetSeedConfiguration(torrent.Hash);
|
||||||
|
|
||||||
|
// Check if torrent is finished and if it exceeds cached seedConfig
|
||||||
|
item.CanMoveFiles = item.CanBeRemoved =
|
||||||
|
torrent.IsFinished && seedConfig != null &&
|
||||||
|
(
|
||||||
|
(torrent.Ratio / 1000.0) >= seedConfig.Ratio ||
|
||||||
|
(DateTimeOffset.Now - DateTimeOffset.FromUnixTimeSeconds(torrent.FinishedTime)) >= seedConfig.SeedTime);
|
||||||
|
|
||||||
items.Add(item);
|
items.Add(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Net;
|
||||||
using CookComputing.XmlRpc;
|
using CookComputing.XmlRpc;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.RTorrent
|
namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
{
|
{
|
||||||
|
@ -17,6 +18,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
void RemoveTorrent(string hash, RTorrentSettings settings);
|
void RemoveTorrent(string hash, RTorrentSettings settings);
|
||||||
void SetTorrentLabel(string hash, string label, RTorrentSettings settings);
|
void SetTorrentLabel(string hash, string label, RTorrentSettings settings);
|
||||||
bool HasHashTorrent(string hash, RTorrentSettings settings);
|
bool HasHashTorrent(string hash, RTorrentSettings settings);
|
||||||
|
void PushTorrentUniqueView(string hash, string view, RTorrentSettings settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IRTorrent : IXmlRpcProxy
|
public interface IRTorrent : IXmlRpcProxy
|
||||||
|
@ -45,6 +47,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
[XmlRpcMethod("d.custom1.set")]
|
[XmlRpcMethod("d.custom1.set")]
|
||||||
string SetLabel(string hash, string label);
|
string SetLabel(string hash, string label);
|
||||||
|
|
||||||
|
[XmlRpcMethod("d.views.push_back_unique")]
|
||||||
|
int PushUniqueView(string hash, string view);
|
||||||
|
|
||||||
[XmlRpcMethod("system.client_version")]
|
[XmlRpcMethod("system.client_version")]
|
||||||
string GetVersion();
|
string GetVersion();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +91,10 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
"d.ratio=", // long
|
"d.ratio=", // long
|
||||||
"d.is_open=", // long
|
"d.is_open=", // long
|
||||||
"d.is_active=", // long
|
"d.is_active=", // long
|
||||||
"d.complete=")); //long
|
"d.complete=", //long
|
||||||
|
"d.timestamp.finished=")); // long (unix timestamp)
|
||||||
|
|
||||||
|
_logger.Trace(ret.ToJson());
|
||||||
|
|
||||||
var items = new List<RTorrentTorrent>();
|
var items = new List<RTorrentTorrent>();
|
||||||
|
|
||||||
|
@ -106,6 +114,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
item.IsOpen = Convert.ToBoolean((long)torrent[8]);
|
item.IsOpen = Convert.ToBoolean((long)torrent[8]);
|
||||||
item.IsActive = Convert.ToBoolean((long)torrent[9]);
|
item.IsActive = Convert.ToBoolean((long)torrent[9]);
|
||||||
item.IsFinished = Convert.ToBoolean((long)torrent[10]);
|
item.IsFinished = Convert.ToBoolean((long)torrent[10]);
|
||||||
|
item.FinishedTime = (long)torrent[11];
|
||||||
|
|
||||||
items.Add(item);
|
items.Add(item);
|
||||||
}
|
}
|
||||||
|
@ -172,6 +181,18 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PushTorrentUniqueView(string hash, string view, RTorrentSettings settings)
|
||||||
|
{
|
||||||
|
_logger.Debug("Executing remote method: d.views.push_back_unique");
|
||||||
|
|
||||||
|
var client = BuildClient(settings);
|
||||||
|
var response = ExecuteRequest(() => client.PushUniqueView(hash, view));
|
||||||
|
if (response != 0)
|
||||||
|
{
|
||||||
|
throw new DownloadClientException("Could not push unique view {0} for torrent: {1}.", view, hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RemoveTorrent(string hash, RTorrentSettings settings)
|
public void RemoveTorrent(string hash, RTorrentSettings settings)
|
||||||
{
|
{
|
||||||
_logger.Debug("Executing remote method: d.erase");
|
_logger.Debug("Executing remote method: d.erase");
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
public long RemainingSize { get; set; }
|
public long RemainingSize { get; set; }
|
||||||
public long DownRate { get; set; }
|
public long DownRate { get; set; }
|
||||||
public long Ratio { get; set; }
|
public long Ratio { get; set; }
|
||||||
|
public long FinishedTime { get; set; }
|
||||||
public bool IsFinished { get; set; }
|
public bool IsFinished { get; set; }
|
||||||
public bool IsOpen { get; set; }
|
public bool IsOpen { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|
|
@ -2,8 +2,11 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Fluent;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
@ -11,6 +14,7 @@ using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
|
@ -18,6 +22,7 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
void Check(TrackedDownload trackedDownload);
|
void Check(TrackedDownload trackedDownload);
|
||||||
void Import(TrackedDownload trackedDownload);
|
void Import(TrackedDownload trackedDownload);
|
||||||
|
bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> importResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CompletedDownloadService : ICompletedDownloadService
|
public class CompletedDownloadService : ICompletedDownloadService
|
||||||
|
@ -27,27 +32,32 @@ namespace NzbDrone.Core.Download
|
||||||
private readonly IDownloadedTracksImportService _downloadedTracksImportService;
|
private readonly IDownloadedTracksImportService _downloadedTracksImportService;
|
||||||
private readonly IArtistService _artistService;
|
private readonly IArtistService _artistService;
|
||||||
private readonly IProvideImportItemService _provideImportItemService;
|
private readonly IProvideImportItemService _provideImportItemService;
|
||||||
|
private readonly IParsingService _parsingService;
|
||||||
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public CompletedDownloadService(IEventAggregator eventAggregator,
|
public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||||
IHistoryService historyService,
|
IHistoryService historyService,
|
||||||
IProvideImportItemService provideImportItemService,
|
IProvideImportItemService provideImportItemService,
|
||||||
IDownloadedTracksImportService downloadedTracksImportService,
|
IDownloadedTracksImportService downloadedTracksImportService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported)
|
IParsingService parsingService,
|
||||||
|
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported,
|
||||||
|
Logger logger)
|
||||||
{
|
{
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
_provideImportItemService = provideImportItemService;
|
_provideImportItemService = provideImportItemService;
|
||||||
_downloadedTracksImportService = downloadedTracksImportService;
|
_downloadedTracksImportService = downloadedTracksImportService;
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
|
_parsingService = parsingService;
|
||||||
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Check(TrackedDownload trackedDownload)
|
public void Check(TrackedDownload trackedDownload)
|
||||||
{
|
{
|
||||||
if (trackedDownload.DownloadItem.Status != DownloadItemStatus.Completed ||
|
if (trackedDownload.DownloadItem.Status != DownloadItemStatus.Completed)
|
||||||
trackedDownload.RemoteAlbum == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +83,7 @@ namespace NzbDrone.Core.Download
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var artist = trackedDownload.RemoteAlbum.Artist;
|
var artist = _parsingService.GetArtist(trackedDownload.DownloadItem.Title);
|
||||||
|
|
||||||
if (artist == null)
|
if (artist == null)
|
||||||
{
|
{
|
||||||
|
@ -101,62 +111,119 @@ namespace NzbDrone.Core.Download
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackedDownload.RemoteAlbum == null)
|
||||||
|
{
|
||||||
|
trackedDownload.Warn("Unable to parse download, automatic import is not possible.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
trackedDownload.State = TrackedDownloadState.Importing;
|
trackedDownload.State = TrackedDownloadState.Importing;
|
||||||
|
|
||||||
var outputPath = trackedDownload.ImportItem.OutputPath.FullPath;
|
var outputPath = trackedDownload.ImportItem.OutputPath.FullPath;
|
||||||
var importResults = _downloadedTracksImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteAlbum.Artist, trackedDownload.DownloadItem);
|
var importResults = _downloadedTracksImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteAlbum.Artist, trackedDownload.DownloadItem);
|
||||||
|
|
||||||
if (importResults.Empty())
|
if (VerifyImport(trackedDownload, importResults))
|
||||||
{
|
{
|
||||||
trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
|
|
||||||
trackedDownload.State = TrackedDownloadState.ImportPending;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackedDownload.State = TrackedDownloadState.ImportPending;
|
||||||
|
|
||||||
|
if (importResults.Empty())
|
||||||
|
{
|
||||||
|
trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusMessages = new List<TrackedDownloadStatusMessage>
|
||||||
|
{
|
||||||
|
new TrackedDownloadStatusMessage("One or more albums expected in this release were not imported or missing", new List<string>())
|
||||||
|
};
|
||||||
|
|
||||||
|
if (importResults.Any(c => c.Result != ImportResultType.Imported))
|
||||||
|
{
|
||||||
|
//Mark as failed to prevent further attempts at processing
|
||||||
|
trackedDownload.State = TrackedDownloadState.ImportFailed;
|
||||||
|
|
||||||
|
statusMessages.AddRange(
|
||||||
|
importResults
|
||||||
|
.Where(v => v.Result != ImportResultType.Imported && v.ImportDecision.Item != null)
|
||||||
|
.OrderBy(v => v.ImportDecision.Item.Path)
|
||||||
|
.Select(v =>
|
||||||
|
new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.Item.Path),
|
||||||
|
v.Errors)));
|
||||||
|
|
||||||
|
if (statusMessages.Any())
|
||||||
|
{
|
||||||
|
trackedDownload.Warn(statusMessages.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Publish event to notify Album was imported incompelte
|
||||||
|
_eventAggregator.PublishEvent(new AlbumImportIncompleteEvent(trackedDownload));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> importResults)
|
||||||
|
{
|
||||||
var allTracksImported = importResults.All(c => c.Result == ImportResultType.Imported) ||
|
var allTracksImported = importResults.All(c => c.Result == ImportResultType.Imported) ||
|
||||||
importResults.Count(c => c.Result == ImportResultType.Imported) >=
|
importResults.Count(c => c.Result == ImportResultType.Imported) >=
|
||||||
Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)));
|
Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)));
|
||||||
|
|
||||||
if (allTracksImported)
|
if (allTracksImported)
|
||||||
{
|
{
|
||||||
|
_logger.Debug("All albums were imported for {0}", trackedDownload.DownloadItem.Title);
|
||||||
|
trackedDownload.State = TrackedDownloadState.Imported;
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double check if all episodes were imported by checking the history if at least one
|
||||||
|
// file was imported. This will allow the decision engine to reject already imported
|
||||||
|
// episode files and still mark the download complete when all files are imported.
|
||||||
|
|
||||||
|
// EDGE CASE: This process relies on EpisodeIds being consistent between executions, if a series is updated
|
||||||
|
// and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
|
||||||
|
// Since imports should be relatively fast and these types of data changes are infrequent this should be quite
|
||||||
|
// safe, but commenting for future benefit.
|
||||||
|
var atLeastOneEpisodeImported = importResults.Any(c => c.Result == ImportResultType.Imported);
|
||||||
|
|
||||||
|
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var allTracksImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
||||||
|
|
||||||
|
if (allTracksImportedInHistory)
|
||||||
|
{
|
||||||
|
// Log different error messages depending on the circumstances, but treat both as fully imported, because that's the reality.
|
||||||
|
// The second message shouldn't be logged in most cases, but continued reporting would indicate an ongoing issue.
|
||||||
|
if (atLeastOneEpisodeImported)
|
||||||
|
{
|
||||||
|
_logger.Debug("All albums were imported in history for {0}", trackedDownload.DownloadItem.Title);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug()
|
||||||
|
.Message("No albums were just imported, but all albums were previously imported, possible issue with download history.")
|
||||||
|
.Property("ArtistId", trackedDownload.RemoteAlbum.Artist.Id)
|
||||||
|
.Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
|
||||||
|
.Property("Title", trackedDownload.DownloadItem.Title)
|
||||||
|
.Property("Path", trackedDownload.DownloadItem.OutputPath.ToString())
|
||||||
|
.WriteSentryWarn("DownloadHistoryIncomplete")
|
||||||
|
.Write();
|
||||||
|
}
|
||||||
|
|
||||||
trackedDownload.State = TrackedDownloadState.Imported;
|
trackedDownload.State = TrackedDownloadState.Imported;
|
||||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
|
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
|
||||||
return;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double check if all albums were imported by checking the history if at least one
|
_logger.Debug("Not all albums have been imported for {0}", trackedDownload.DownloadItem.Title);
|
||||||
// file was imported. This will allow the decision engine to reject already imported
|
return false;
|
||||||
// albums and still mark the download complete when all files are imported.
|
|
||||||
if (importResults.Any(c => c.Result == ImportResultType.Imported))
|
|
||||||
{
|
|
||||||
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
|
||||||
.OrderByDescending(h => h.Date)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var allTracksImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
|
||||||
|
|
||||||
if (allTracksImportedInHistory)
|
|
||||||
{
|
|
||||||
trackedDownload.State = TrackedDownloadState.Imported;
|
|
||||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trackedDownload.State = TrackedDownloadState.ImportPending;
|
|
||||||
|
|
||||||
if (importResults.Any(c => c.Result != ImportResultType.Imported))
|
|
||||||
{
|
|
||||||
trackedDownload.State = TrackedDownloadState.ImportFailed;
|
|
||||||
var statusMessages = importResults
|
|
||||||
.Where(v => v.Result != ImportResultType.Imported)
|
|
||||||
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.Item.Path), v.Errors))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
trackedDownload.Warn(statusMessages);
|
|
||||||
_eventAggregator.PublishEvent(new AlbumImportIncompleteEvent(trackedDownload));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetImportItem(TrackedDownload trackedDownload)
|
private void SetImportItem(TrackedDownload trackedDownload)
|
||||||
|
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
@ -75,7 +74,6 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
_logger.Trace("DownloadItem {0} in {1} history not found, skipping delete data.", item.DownloadId, Name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("{DownloadClientName}:{Title}")]
|
[DebuggerDisplay("{DownloadClientInfo?.Name}:{Title}")]
|
||||||
public class DownloadClientItem
|
public class DownloadClientItem
|
||||||
{
|
{
|
||||||
public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
|
public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
using System;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Download.Clients;
|
||||||
|
using NzbDrone.Core.Download.History;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public interface IDownloadSeedConfigProvider
|
||||||
|
{
|
||||||
|
TorrentSeedConfiguration GetSeedConfiguration(string infoHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadSeedConfigProvider : IDownloadSeedConfigProvider
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
private readonly ISeedConfigProvider _indexerSeedConfigProvider;
|
||||||
|
private readonly IDownloadHistoryService _downloadHistoryService;
|
||||||
|
|
||||||
|
private class CachedSeedConfiguration
|
||||||
|
{
|
||||||
|
public int IndexerId { get; set; }
|
||||||
|
public bool Discography { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ICached<CachedSeedConfiguration> _cacheDownloads;
|
||||||
|
|
||||||
|
public DownloadSeedConfigProvider(IDownloadHistoryService downloadHistoryService, ISeedConfigProvider indexerSeedConfigProvider, ICacheManager cacheManager, Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_indexerSeedConfigProvider = indexerSeedConfigProvider;
|
||||||
|
_downloadHistoryService = downloadHistoryService;
|
||||||
|
|
||||||
|
_cacheDownloads = cacheManager.GetRollingCache<CachedSeedConfiguration>(GetType(), "indexerByHash", TimeSpan.FromHours(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TorrentSeedConfiguration GetSeedConfiguration(string infoHash)
|
||||||
|
{
|
||||||
|
if (infoHash.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
infoHash = infoHash.ToUpper();
|
||||||
|
|
||||||
|
var cachedConfig = _cacheDownloads.Get(infoHash, () => FetchIndexer(infoHash));
|
||||||
|
|
||||||
|
if (cachedConfig == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seedConfig = _indexerSeedConfigProvider.GetSeedConfiguration(cachedConfig.IndexerId, cachedConfig.Discography);
|
||||||
|
|
||||||
|
return seedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CachedSeedConfiguration FetchIndexer(string infoHash)
|
||||||
|
{
|
||||||
|
var historyItem = _downloadHistoryService.GetLatestGrab(infoHash);
|
||||||
|
|
||||||
|
if (historyItem == null)
|
||||||
|
{
|
||||||
|
_logger.Debug("No download history item for infohash {0}, unable to provide seed configuration", infoHash);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedAlbumInfo parsedAlbumInfo = null;
|
||||||
|
if (historyItem.Release != null)
|
||||||
|
{
|
||||||
|
parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(historyItem.Release.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedAlbumInfo == null)
|
||||||
|
{
|
||||||
|
_logger.Debug("No parsed title in download history item for infohash {0}, unable to provide seed configuration", infoHash);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CachedSeedConfiguration
|
||||||
|
{
|
||||||
|
IndexerId = historyItem.IndexerId,
|
||||||
|
Discography = parsedAlbumInfo.Discography
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -102,6 +102,8 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
var albumGrabbedEvent = new AlbumGrabbedEvent(remoteAlbum);
|
var albumGrabbedEvent = new AlbumGrabbedEvent(remoteAlbum);
|
||||||
albumGrabbedEvent.DownloadClient = downloadClient.Name;
|
albumGrabbedEvent.DownloadClient = downloadClient.Name;
|
||||||
|
albumGrabbedEvent.DownloadClientId = downloadClient.Definition.Id;
|
||||||
|
albumGrabbedEvent.DownloadClientName = downloadClient.Definition.Name;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(downloadClientId))
|
if (!string.IsNullOrWhiteSpace(downloadClientId))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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", skipReDownload: skipReDownload);
|
PublishDownloadFailedEvent(new List<EntityHistory> { history }, "Manually marked as failed", skipReDownload: skipReDownload);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var grabbedHistory = _historyService.Find(downloadId, HistoryEventType.Grabbed).ToList();
|
var grabbedHistory = _historyService.Find(downloadId, EntityHistoryEventType.Grabbed).ToList();
|
||||||
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
|
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkAsFailed(string downloadId, bool skipReDownload = false)
|
public void MarkAsFailed(string downloadId, bool skipReDownload = false)
|
||||||
{
|
{
|
||||||
var history = _historyService.Find(downloadId, HistoryEventType.Grabbed);
|
var history = _historyService.Find(downloadId, EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
if (history.Any())
|
if (history.Any())
|
||||||
{
|
{
|
||||||
PublishDownloadFailedEvent(history, "Manually marked as failed", skipReDownload: skipReDownload);
|
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||||
|
|
||||||
|
PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload, skipReDownload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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, EntityHistoryEventType.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, EntityHistoryEventType.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, bool skipReDownload = false)
|
private void PublishDownloadFailedEvent(List<EntityHistory> historyItems, string message, TrackedDownload trackedDownload = null, bool skipReDownload = false)
|
||||||
{
|
{
|
||||||
var historyItem = historyItems.First();
|
var historyItem = historyItems.First();
|
||||||
|
|
||||||
|
@ -119,7 +124,7 @@ namespace NzbDrone.Core.Download
|
||||||
AlbumIds = historyItems.Select(h => h.AlbumId).ToList(),
|
AlbumIds = historyItems.Select(h => h.AlbumId).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(EntityHistory.DOWNLOAD_CLIENT),
|
||||||
DownloadId = historyItem.DownloadId,
|
DownloadId = historyItem.DownloadId,
|
||||||
Message = message,
|
Message = message,
|
||||||
Data = historyItem.Data,
|
Data = historyItem.Data,
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
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 ArtistId { 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,
|
||||||
|
DownloadImportIncomplete = 6
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
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 DeleteByArtistIds(List<int> artistIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadHistoryRepository : BasicRepository<DownloadHistory>, IDownloadHistoryRepository
|
||||||
|
{
|
||||||
|
public DownloadHistoryRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DownloadHistory> FindByDownloadId(string downloadId)
|
||||||
|
{
|
||||||
|
return Query(x => x.DownloadId == downloadId).OrderByDescending(h => h.Date).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteByArtistIds(List<int> artistIds)
|
||||||
|
{
|
||||||
|
Delete(r => artistIds.Contains(r.ArtistId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.History;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Music.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Download.History
|
||||||
|
{
|
||||||
|
public interface IDownloadHistoryService
|
||||||
|
{
|
||||||
|
bool DownloadAlreadyImported(string downloadId);
|
||||||
|
DownloadHistory GetLatestDownloadHistoryItem(string downloadId);
|
||||||
|
DownloadHistory GetLatestGrab(string downloadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadHistoryService : IDownloadHistoryService,
|
||||||
|
IHandle<AlbumGrabbedEvent>,
|
||||||
|
IHandle<TrackImportedEvent>,
|
||||||
|
IHandle<AlbumImportIncompleteEvent>,
|
||||||
|
IHandle<DownloadCompletedEvent>,
|
||||||
|
IHandle<DownloadFailedEvent>,
|
||||||
|
IHandle<DownloadIgnoredEvent>,
|
||||||
|
IHandle<ArtistsDeletedEvent>
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.EventType == DownloadHistoryEventType.DownloadImportIncomplete)
|
||||||
|
{
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadHistory GetLatestGrab(string downloadId)
|
||||||
|
{
|
||||||
|
return _repository.FindByDownloadId(downloadId)
|
||||||
|
.FirstOrDefault(d => d.EventType == DownloadHistoryEventType.DownloadGrabbed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(AlbumGrabbedEvent message)
|
||||||
|
{
|
||||||
|
var history = new DownloadHistory
|
||||||
|
{
|
||||||
|
EventType = DownloadHistoryEventType.DownloadGrabbed,
|
||||||
|
ArtistId = message.Album.Artist.Id,
|
||||||
|
DownloadId = message.DownloadId,
|
||||||
|
SourceTitle = message.Album.Release.Title,
|
||||||
|
Date = DateTime.UtcNow,
|
||||||
|
Protocol = message.Album.Release.DownloadProtocol,
|
||||||
|
IndexerId = message.Album.Release.IndexerId,
|
||||||
|
DownloadClientId = message.DownloadClientId,
|
||||||
|
Release = message.Album.Release
|
||||||
|
};
|
||||||
|
|
||||||
|
history.Data.Add("Indexer", message.Album.Release.Indexer);
|
||||||
|
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||||
|
history.Data.Add("DownloadClientName", message.DownloadClientName);
|
||||||
|
history.Data.Add("PreferredWordScore", message.Album.PreferredWordScore.ToString());
|
||||||
|
|
||||||
|
_repository.Insert(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(TrackImportedEvent 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,
|
||||||
|
ArtistId = message.TrackInfo.Artist.Id,
|
||||||
|
DownloadId = downloadId,
|
||||||
|
SourceTitle = message.TrackInfo.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.TrackInfo.Path);
|
||||||
|
history.Data.Add("DestinationPath", message.ImportedTrack.Path);
|
||||||
|
|
||||||
|
_repository.Insert(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(AlbumImportIncompleteEvent message)
|
||||||
|
{
|
||||||
|
var history = new DownloadHistory
|
||||||
|
{
|
||||||
|
EventType = DownloadHistoryEventType.DownloadImportIncomplete,
|
||||||
|
ArtistId = message.TrackedDownload.RemoteAlbum?.Artist.Id ?? 0,
|
||||||
|
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);
|
||||||
|
history.Data.Add("StatusMessages", message.TrackedDownload.StatusMessages.ToJson());
|
||||||
|
|
||||||
|
_repository.Insert(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(DownloadCompletedEvent message)
|
||||||
|
{
|
||||||
|
var history = new DownloadHistory
|
||||||
|
{
|
||||||
|
EventType = DownloadHistoryEventType.DownloadImported,
|
||||||
|
ArtistId = message.TrackedDownload.RemoteAlbum.Artist.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,
|
||||||
|
ArtistId = message.ArtistId,
|
||||||
|
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,
|
||||||
|
ArtistId = message.ArtistId,
|
||||||
|
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(ArtistsDeletedEvent message)
|
||||||
|
{
|
||||||
|
_repository.DeleteByArtistIds(message.Artists.Select(a => a.Id).ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.History;
|
using NzbDrone.Core.History;
|
||||||
|
|
||||||
|
@ -7,15 +8,25 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
public interface ITrackedDownloadAlreadyImported
|
public interface ITrackedDownloadAlreadyImported
|
||||||
{
|
{
|
||||||
bool IsImported(TrackedDownload trackedDownload, List<History.History> historyItems);
|
bool IsImported(TrackedDownload trackedDownload, List<EntityHistory> historyItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TrackedDownloadAlreadyImported : ITrackedDownloadAlreadyImported
|
public class TrackedDownloadAlreadyImported : ITrackedDownloadAlreadyImported
|
||||||
{
|
{
|
||||||
public bool IsImported(TrackedDownload trackedDownload, List<History.History> historyItems)
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public TrackedDownloadAlreadyImported(Logger logger)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsImported(TrackedDownload trackedDownload, List<EntityHistory> historyItems)
|
||||||
|
{
|
||||||
|
_logger.Trace("Checking if all items for '{0}' have been imported", trackedDownload.DownloadItem.Title);
|
||||||
|
|
||||||
if (historyItems.Empty())
|
if (historyItems.Empty())
|
||||||
{
|
{
|
||||||
|
_logger.Trace("No history for {0}", trackedDownload.DownloadItem.Title);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +41,17 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
|
|
||||||
if (lastHistoryItem == null)
|
if (lastHistoryItem == null)
|
||||||
{
|
{
|
||||||
|
_logger.Trace($"No history for album: {album}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { HistoryEventType.DownloadImported, HistoryEventType.TrackFileImported }.Contains(lastHistoryItem.EventType);
|
_logger.Trace($"Last event for album: {album} is: {lastHistoryItem.EventType}");
|
||||||
|
|
||||||
|
return new[] { EntityHistoryEventType.DownloadImported, EntityHistoryEventType.TrackFileImported }.Contains(lastHistoryItem.EventType);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_logger.Trace("All albums for '{0}' have been imported: {1}", trackedDownload.DownloadItem.Title, allAlbumsImportedInHistory);
|
||||||
|
|
||||||
return allAlbumsImportedInHistory;
|
return allAlbumsImportedInHistory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ using NLog;
|
||||||
using NzbDrone.Common.Cache;
|
using NzbDrone.Common.Cache;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
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.Music;
|
using NzbDrone.Core.Music;
|
||||||
|
@ -28,6 +29,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 IDownloadHistoryService _downloadHistoryService;
|
||||||
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
private readonly ICached<TrackedDownload> _cache;
|
private readonly ICached<TrackedDownload> _cache;
|
||||||
|
@ -35,15 +37,17 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
public TrackedDownloadService(IParsingService parsingService,
|
public TrackedDownloadService(IParsingService parsingService,
|
||||||
ICacheManager cacheManager,
|
ICacheManager cacheManager,
|
||||||
IHistoryService historyService,
|
IHistoryService historyService,
|
||||||
|
IDownloadHistoryService downloadHistoryService,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported,
|
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_parsingService = parsingService;
|
_parsingService = parsingService;
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
|
_cache = cacheManager.GetCache<TrackedDownload>(GetType());
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
||||||
_cache = cacheManager.GetCache<TrackedDownload>(GetType());
|
_downloadHistoryService = downloadHistoryService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,41 +120,31 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(trackedDownload.DownloadItem.Title);
|
|
||||||
var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId)
|
var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId)
|
||||||
.OrderByDescending(h => h.Date)
|
.OrderByDescending(h => h.Date)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
//TODO: Create release info from history and use that here, so we don't loose indexer flags!
|
||||||
|
var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(trackedDownload.DownloadItem.Title);
|
||||||
|
|
||||||
if (parsedAlbumInfo != null)
|
if (parsedAlbumInfo != null)
|
||||||
{
|
{
|
||||||
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo);
|
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
var allImported = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
|
||||||
|
|
||||||
trackedDownload.State = allImported ? TrackedDownloadState.Imported : TrackedDownloadState.Downloading;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trackedDownload.State = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstHistoryItem.EventType == HistoryEventType.AlbumImportIncomplete)
|
|
||||||
{
|
|
||||||
var messages = Json.Deserialize<List<TrackedDownloadStatusMessage>>(firstHistoryItem?.Data["statusMessages"]).ToArray();
|
|
||||||
trackedDownload.Warn(messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == HistoryEventType.Grabbed);
|
|
||||||
trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
|
trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
|
||||||
|
|
||||||
if (parsedAlbumInfo == null ||
|
if (parsedAlbumInfo == null ||
|
||||||
|
@ -159,7 +153,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
trackedDownload.RemoteAlbum.Albums.Empty())
|
trackedDownload.RemoteAlbum.Albums.Empty())
|
||||||
{
|
{
|
||||||
// Try parsing the original source title and if that fails, try parsing it as a special
|
// Try parsing the original source title and if that fails, try parsing it as a special
|
||||||
// TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
|
|
||||||
var historyArtist = firstHistoryItem.Artist;
|
var historyArtist = firstHistoryItem.Artist;
|
||||||
var historyAlbums = new List<Album> { firstHistoryItem.Album };
|
var historyAlbums = new List<Album> { firstHistoryItem.Album };
|
||||||
|
|
||||||
|
@ -169,7 +162,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
|
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
|
||||||
firstHistoryItem.ArtistId,
|
firstHistoryItem.ArtistId,
|
||||||
historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.AlbumId)
|
historyItems.Where(v => v.EventType == EntityHistoryEventType.Grabbed).Select(h => h.AlbumId)
|
||||||
.Distinct());
|
.Distinct());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -183,7 +176,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
{
|
{
|
||||||
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
|
trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
|
||||||
firstHistoryItem.ArtistId,
|
firstHistoryItem.ArtistId,
|
||||||
historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.AlbumId)
|
historyItems.Where(v => v.EventType == EntityHistoryEventType.Grabbed).Select(h => h.AlbumId)
|
||||||
.Distinct());
|
.Distinct());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +187,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
if (trackedDownload.RemoteAlbum == null)
|
if (trackedDownload.RemoteAlbum == null)
|
||||||
{
|
{
|
||||||
_logger.Trace("No Album found for download '{0}'", trackedDownload.DownloadItem.Title);
|
_logger.Trace("No Album found for download '{0}'", trackedDownload.DownloadItem.Title);
|
||||||
trackedDownload.Warn("No Album found for download '{0}'", trackedDownload.DownloadItem.Title);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -224,6 +216,23 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TrackedDownloadState GetStateFromHistory(DownloadHistoryEventType eventType)
|
||||||
|
{
|
||||||
|
switch (eventType)
|
||||||
|
{
|
||||||
|
case DownloadHistoryEventType.DownloadImportIncomplete:
|
||||||
|
return TrackedDownloadState.ImportFailed;
|
||||||
|
case DownloadHistoryEventType.DownloadImported:
|
||||||
|
return TrackedDownloadState.Imported;
|
||||||
|
case DownloadHistoryEventType.DownloadFailed:
|
||||||
|
return TrackedDownloadState.DownloadFailed;
|
||||||
|
case DownloadHistoryEventType.DownloadIgnored:
|
||||||
|
return TrackedDownloadState.Ignored;
|
||||||
|
default:
|
||||||
|
return TrackedDownloadState.Downloading;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LogItemChange(TrackedDownload trackedDownload, DownloadClientItem existingItem, DownloadClientItem downloadItem)
|
private void LogItemChange(TrackedDownload trackedDownload, DownloadClientItem existingItem, DownloadClientItem downloadItem)
|
||||||
{
|
{
|
||||||
if (existingItem == null ||
|
if (existingItem == null ||
|
||||||
|
@ -242,29 +251,6 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrackedDownloadState GetStateFromHistory(NzbDrone.Core.History.History history)
|
|
||||||
{
|
|
||||||
switch (history.EventType)
|
|
||||||
{
|
|
||||||
case HistoryEventType.AlbumImportIncomplete:
|
|
||||||
return TrackedDownloadState.ImportFailed;
|
|
||||||
case HistoryEventType.DownloadImported:
|
|
||||||
return TrackedDownloadState.Imported;
|
|
||||||
case HistoryEventType.DownloadFailed:
|
|
||||||
return TrackedDownloadState.DownloadFailed;
|
|
||||||
case HistoryEventType.DownloadIgnored:
|
|
||||||
return TrackedDownloadState.Ignored;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since DownloadComplete is a new event type, we can't assume it exists for old downloads
|
|
||||||
if (history.EventType == HistoryEventType.TrackFileImported)
|
|
||||||
{
|
|
||||||
return DateTime.UtcNow.Subtract(history.Date).TotalSeconds < 60 ? TrackedDownloadState.Importing : TrackedDownloadState.Imported;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TrackedDownloadState.Downloading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Handle(AlbumDeletedEvent message)
|
public void Handle(AlbumDeletedEvent message)
|
||||||
{
|
{
|
||||||
UpdateAlbumCache(message.Album.Id);
|
UpdateAlbumCache(message.Album.Id);
|
||||||
|
|
|
@ -136,7 +136,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
|
|
||||||
// If the previous case did not match then the failure occured in DownloadedTracksImportService,
|
// If the previous case did not match then the failure occured in DownloadedTracksImportService,
|
||||||
// while trying to locate the files reported by the download client
|
// while trying to locate the files reported by the download client
|
||||||
var client = _downloadClientProvider.GetDownloadClients().FirstOrDefault(x => x.Definition.Name == failureMessage.DownloadClient);
|
var client = _downloadClientProvider.Get(failureMessage.DownloadClientInfo.Id);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var status = client.GetStatus();
|
var status = client.GetStatus();
|
||||||
|
|
|
@ -6,11 +6,11 @@ using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
namespace NzbDrone.Core.History
|
namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
public class History : ModelBase
|
public class EntityHistory : ModelBase
|
||||||
{
|
{
|
||||||
public const string DOWNLOAD_CLIENT = "downloadClient";
|
public const string DOWNLOAD_CLIENT = "downloadClient";
|
||||||
|
|
||||||
public History()
|
public EntityHistory()
|
||||||
{
|
{
|
||||||
Data = new Dictionary<string, string>();
|
Data = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@ namespace NzbDrone.Core.History
|
||||||
public Album Album { get; set; }
|
public Album Album { get; set; }
|
||||||
public Artist Artist { get; set; }
|
public Artist Artist { get; set; }
|
||||||
public Track Track { get; set; }
|
public Track Track { get; set; }
|
||||||
public HistoryEventType EventType { get; set; }
|
public EntityHistoryEventType EventType { get; set; }
|
||||||
public Dictionary<string, string> Data { get; set; }
|
public Dictionary<string, string> Data { get; set; }
|
||||||
|
|
||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum HistoryEventType
|
public enum EntityHistoryEventType
|
||||||
{
|
{
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Grabbed = 1,
|
Grabbed = 1,
|
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.History
|
||||||
|
{
|
||||||
|
public interface IHistoryRepository : IBasicRepository<EntityHistory>
|
||||||
|
{
|
||||||
|
EntityHistory MostRecentForAlbum(int albumId);
|
||||||
|
EntityHistory MostRecentForDownloadId(string downloadId);
|
||||||
|
List<EntityHistory> FindByDownloadId(string downloadId);
|
||||||
|
List<EntityHistory> GetByArtist(int artistId, EntityHistoryEventType? eventType);
|
||||||
|
List<EntityHistory> GetByAlbum(int albumId, EntityHistoryEventType? eventType);
|
||||||
|
List<EntityHistory> FindDownloadHistory(int idArtistId, QualityModel quality);
|
||||||
|
void DeleteForArtists(List<int> artistIds);
|
||||||
|
List<EntityHistory> Since(DateTime date, EntityHistoryEventType? eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EntityHistoryRepository : BasicRepository<EntityHistory>, IHistoryRepository
|
||||||
|
{
|
||||||
|
public EntityHistoryRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityHistory MostRecentForAlbum(int albumId)
|
||||||
|
{
|
||||||
|
return Query(h => h.AlbumId == albumId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityHistory MostRecentForDownloadId(string downloadId)
|
||||||
|
{
|
||||||
|
return Query(h => h.DownloadId == downloadId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EntityHistory> FindByDownloadId(string downloadId)
|
||||||
|
{
|
||||||
|
return _database.QueryJoined<EntityHistory, Artist, Album>(
|
||||||
|
Builder()
|
||||||
|
.Join<EntityHistory, Artist>((h, a) => h.ArtistId == a.Id)
|
||||||
|
.Join<EntityHistory, Album>((h, a) => h.AlbumId == a.Id)
|
||||||
|
.Where<EntityHistory>(h => h.DownloadId == downloadId),
|
||||||
|
(history, artist, album) =>
|
||||||
|
{
|
||||||
|
history.Artist = artist;
|
||||||
|
history.Album = album;
|
||||||
|
return history;
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EntityHistory> GetByArtist(int artistId, EntityHistoryEventType? eventType)
|
||||||
|
{
|
||||||
|
var builder = Builder().Where<EntityHistory>(h => h.ArtistId == artistId);
|
||||||
|
|
||||||
|
if (eventType.HasValue)
|
||||||
|
{
|
||||||
|
builder.Where<EntityHistory>(h => h.EventType == eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Query(builder).OrderByDescending(h => h.Date).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EntityHistory> GetByAlbum(int albumId, EntityHistoryEventType? eventType)
|
||||||
|
{
|
||||||
|
var builder = Builder()
|
||||||
|
.Join<EntityHistory, Album>((h, a) => h.AlbumId == a.Id)
|
||||||
|
.Where<EntityHistory>(h => h.AlbumId == albumId);
|
||||||
|
|
||||||
|
if (eventType.HasValue)
|
||||||
|
{
|
||||||
|
builder.Where<EntityHistory>(h => h.EventType == eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _database.QueryJoined<EntityHistory, Album>(
|
||||||
|
builder,
|
||||||
|
(history, album) =>
|
||||||
|
{
|
||||||
|
history.Album = album;
|
||||||
|
return history;
|
||||||
|
}).OrderByDescending(h => h.Date).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EntityHistory> FindDownloadHistory(int idArtistId, QualityModel quality)
|
||||||
|
{
|
||||||
|
var allowed = new[] { EntityHistoryEventType.Grabbed, EntityHistoryEventType.DownloadFailed, EntityHistoryEventType.TrackFileImported };
|
||||||
|
|
||||||
|
return Query(h => h.ArtistId == idArtistId &&
|
||||||
|
h.Quality == quality &&
|
||||||
|
allowed.Contains(h.EventType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteForArtists(List<int> artistIds)
|
||||||
|
{
|
||||||
|
Delete(c => artistIds.Contains(c.ArtistId));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override SqlBuilder PagedBuilder() => new SqlBuilder()
|
||||||
|
.Join<EntityHistory, Artist>((h, a) => h.ArtistId == a.Id)
|
||||||
|
.Join<EntityHistory, Album>((h, a) => h.AlbumId == a.Id)
|
||||||
|
.LeftJoin<EntityHistory, Track>((h, t) => h.TrackId == t.Id);
|
||||||
|
protected override IEnumerable<EntityHistory> PagedQuery(SqlBuilder builder) =>
|
||||||
|
_database.QueryJoined<EntityHistory, Artist, Album, Track>(builder, (history, artist, album, track) =>
|
||||||
|
{
|
||||||
|
history.Artist = artist;
|
||||||
|
history.Album = album;
|
||||||
|
history.Track = track;
|
||||||
|
return history;
|
||||||
|
});
|
||||||
|
|
||||||
|
public List<EntityHistory> Since(DateTime date, EntityHistoryEventType? eventType)
|
||||||
|
{
|
||||||
|
var builder = Builder().Where<EntityHistory>(x => x.Date >= date);
|
||||||
|
|
||||||
|
if (eventType.HasValue)
|
||||||
|
{
|
||||||
|
builder.Where<EntityHistory>(h => h.EventType == eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Query(builder).OrderBy(h => h.Date).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,19 +18,20 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
public interface IHistoryService
|
public interface IHistoryService
|
||||||
{
|
{
|
||||||
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
PagingSpec<EntityHistory> Paged(PagingSpec<EntityHistory> pagingSpec);
|
||||||
History MostRecentForAlbum(int albumId);
|
EntityHistory MostRecentForAlbum(int albumId);
|
||||||
History MostRecentForDownloadId(string downloadId);
|
EntityHistory MostRecentForDownloadId(string downloadId);
|
||||||
History Get(int historyId);
|
EntityHistory Get(int historyId);
|
||||||
List<History> GetByArtist(int artistId, HistoryEventType? eventType);
|
List<EntityHistory> GetByArtist(int artistId, EntityHistoryEventType? eventType);
|
||||||
List<History> GetByAlbum(int albumId, HistoryEventType? eventType);
|
List<EntityHistory> GetByAlbum(int albumId, EntityHistoryEventType? eventType);
|
||||||
List<History> Find(string downloadId, HistoryEventType eventType);
|
List<EntityHistory> Find(string downloadId, EntityHistoryEventType eventType);
|
||||||
List<History> FindByDownloadId(string downloadId);
|
List<EntityHistory> FindByDownloadId(string downloadId);
|
||||||
List<History> Since(DateTime date, HistoryEventType? eventType);
|
string FindDownloadId(TrackImportedEvent trackedDownload);
|
||||||
void UpdateMany(IList<History> items);
|
List<EntityHistory> Since(DateTime date, EntityHistoryEventType? eventType);
|
||||||
|
void UpdateMany(IList<EntityHistory> items);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryService : IHistoryService,
|
public class EntityHistoryService : IHistoryService,
|
||||||
IHandle<AlbumGrabbedEvent>,
|
IHandle<AlbumGrabbedEvent>,
|
||||||
IHandle<AlbumImportIncompleteEvent>,
|
IHandle<AlbumImportIncompleteEvent>,
|
||||||
IHandle<TrackImportedEvent>,
|
IHandle<TrackImportedEvent>,
|
||||||
|
@ -45,53 +46,53 @@ namespace NzbDrone.Core.History
|
||||||
private readonly IHistoryRepository _historyRepository;
|
private readonly IHistoryRepository _historyRepository;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public HistoryService(IHistoryRepository historyRepository, Logger logger)
|
public EntityHistoryService(IHistoryRepository historyRepository, Logger logger)
|
||||||
{
|
{
|
||||||
_historyRepository = historyRepository;
|
_historyRepository = historyRepository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PagingSpec<History> Paged(PagingSpec<History> pagingSpec)
|
public PagingSpec<EntityHistory> Paged(PagingSpec<EntityHistory> pagingSpec)
|
||||||
{
|
{
|
||||||
return _historyRepository.GetPaged(pagingSpec);
|
return _historyRepository.GetPaged(pagingSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public History MostRecentForAlbum(int albumId)
|
public EntityHistory MostRecentForAlbum(int albumId)
|
||||||
{
|
{
|
||||||
return _historyRepository.MostRecentForAlbum(albumId);
|
return _historyRepository.MostRecentForAlbum(albumId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public History MostRecentForDownloadId(string downloadId)
|
public EntityHistory MostRecentForDownloadId(string downloadId)
|
||||||
{
|
{
|
||||||
return _historyRepository.MostRecentForDownloadId(downloadId);
|
return _historyRepository.MostRecentForDownloadId(downloadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public History Get(int historyId)
|
public EntityHistory Get(int historyId)
|
||||||
{
|
{
|
||||||
return _historyRepository.Get(historyId);
|
return _historyRepository.Get(historyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<History> GetByArtist(int artistId, HistoryEventType? eventType)
|
public List<EntityHistory> GetByArtist(int artistId, EntityHistoryEventType? eventType)
|
||||||
{
|
{
|
||||||
return _historyRepository.GetByArtist(artistId, eventType);
|
return _historyRepository.GetByArtist(artistId, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<History> GetByAlbum(int albumId, HistoryEventType? eventType)
|
public List<EntityHistory> GetByAlbum(int albumId, EntityHistoryEventType? eventType)
|
||||||
{
|
{
|
||||||
return _historyRepository.GetByAlbum(albumId, eventType);
|
return _historyRepository.GetByAlbum(albumId, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<History> Find(string downloadId, HistoryEventType eventType)
|
public List<EntityHistory> Find(string downloadId, EntityHistoryEventType 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<EntityHistory> FindByDownloadId(string downloadId)
|
||||||
{
|
{
|
||||||
return _historyRepository.FindByDownloadId(downloadId);
|
return _historyRepository.FindByDownloadId(downloadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string FindDownloadId(TrackImportedEvent trackedDownload)
|
public string FindDownloadId(TrackImportedEvent trackedDownload)
|
||||||
{
|
{
|
||||||
_logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedTrack.Path);
|
_logger.Debug("Trying to find downloadId for {0} from history", trackedDownload.ImportedTrack.Path);
|
||||||
|
|
||||||
|
@ -103,10 +104,10 @@ namespace NzbDrone.Core.History
|
||||||
var albumsHistory = allHistory.Where(h => albumIds.Contains(h.AlbumId)).ToList();
|
var albumsHistory = allHistory.Where(h => albumIds.Contains(h.AlbumId)).ToList();
|
||||||
|
|
||||||
var processedDownloadId = albumsHistory
|
var processedDownloadId = albumsHistory
|
||||||
.Where(c => c.EventType != HistoryEventType.Grabbed && c.DownloadId != null)
|
.Where(c => c.EventType != EntityHistoryEventType.Grabbed && c.DownloadId != null)
|
||||||
.Select(c => c.DownloadId);
|
.Select(c => c.DownloadId);
|
||||||
|
|
||||||
var stillDownloading = albumsHistory.Where(c => c.EventType == HistoryEventType.Grabbed && !processedDownloadId.Contains(c.DownloadId)).ToList();
|
var stillDownloading = albumsHistory.Where(c => c.EventType == EntityHistoryEventType.Grabbed && !processedDownloadId.Contains(c.DownloadId)).ToList();
|
||||||
|
|
||||||
string downloadId = null;
|
string downloadId = null;
|
||||||
|
|
||||||
|
@ -139,9 +140,9 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
foreach (var album in message.Album.Albums)
|
foreach (var album in message.Album.Albums)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.Grabbed,
|
EventType = EntityHistoryEventType.Grabbed,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.Album.ParsedAlbumInfo.Quality,
|
Quality = message.Album.ParsedAlbumInfo.Quality,
|
||||||
SourceTitle = message.Album.Release.Title,
|
SourceTitle = message.Album.Release.Title,
|
||||||
|
@ -184,9 +185,9 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
foreach (var album in message.TrackedDownload.RemoteAlbum.Albums)
|
foreach (var album in message.TrackedDownload.RemoteAlbum.Albums)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.AlbumImportIncomplete,
|
EventType = EntityHistoryEventType.AlbumImportIncomplete,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackedDownload.RemoteAlbum.ParsedAlbumInfo?.Quality ?? new QualityModel(),
|
Quality = message.TrackedDownload.RemoteAlbum.ParsedAlbumInfo?.Quality ?? new QualityModel(),
|
||||||
SourceTitle = message.TrackedDownload.DownloadItem.Title,
|
SourceTitle = message.TrackedDownload.DownloadItem.Title,
|
||||||
|
@ -216,9 +217,9 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
foreach (var track in message.TrackInfo.Tracks)
|
foreach (var track in message.TrackInfo.Tracks)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.TrackFileImported,
|
EventType = EntityHistoryEventType.TrackFileImported,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackInfo.Quality,
|
Quality = message.TrackInfo.Quality,
|
||||||
SourceTitle = message.ImportedTrack.SceneName ?? Path.GetFileNameWithoutExtension(message.TrackInfo.Path),
|
SourceTitle = message.ImportedTrack.SceneName ?? Path.GetFileNameWithoutExtension(message.TrackInfo.Path),
|
||||||
|
@ -232,7 +233,7 @@ 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.TrackInfo.Path);
|
history.Data.Add("DroppedPath", message.TrackInfo.Path);
|
||||||
history.Data.Add("ImportedPath", message.ImportedTrack.Path);
|
history.Data.Add("ImportedPath", message.ImportedTrack.Path);
|
||||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
history.Data.Add("DownloadClient", message.DownloadClientInfo.Name);
|
||||||
|
|
||||||
_historyRepository.Insert(history);
|
_historyRepository.Insert(history);
|
||||||
}
|
}
|
||||||
|
@ -242,9 +243,9 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
foreach (var albumId in message.AlbumIds)
|
foreach (var albumId in message.AlbumIds)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.DownloadFailed,
|
EventType = EntityHistoryEventType.DownloadFailed,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.Quality,
|
Quality = message.Quality,
|
||||||
SourceTitle = message.SourceTitle,
|
SourceTitle = message.SourceTitle,
|
||||||
|
@ -264,9 +265,9 @@ namespace NzbDrone.Core.History
|
||||||
{
|
{
|
||||||
foreach (var album in message.TrackedDownload.RemoteAlbum.Albums)
|
foreach (var album in message.TrackedDownload.RemoteAlbum.Albums)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.DownloadImported,
|
EventType = EntityHistoryEventType.DownloadImported,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackedDownload.RemoteAlbum.ParsedAlbumInfo?.Quality ?? new QualityModel(),
|
Quality = message.TrackedDownload.RemoteAlbum.ParsedAlbumInfo?.Quality ?? new QualityModel(),
|
||||||
SourceTitle = message.TrackedDownload.DownloadItem.Title,
|
SourceTitle = message.TrackedDownload.DownloadItem.Title,
|
||||||
|
@ -294,9 +295,9 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
foreach (var track in message.TrackFile.Tracks.Value)
|
foreach (var track in message.TrackFile.Tracks.Value)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.TrackFileDeleted,
|
EventType = EntityHistoryEventType.TrackFileDeleted,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackFile.Quality,
|
Quality = message.TrackFile.Quality,
|
||||||
SourceTitle = message.TrackFile.Path,
|
SourceTitle = message.TrackFile.Path,
|
||||||
|
@ -318,9 +319,9 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
foreach (var track in message.TrackFile.Tracks.Value)
|
foreach (var track in message.TrackFile.Tracks.Value)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.TrackFileRenamed,
|
EventType = EntityHistoryEventType.TrackFileRenamed,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackFile.Quality,
|
Quality = message.TrackFile.Quality,
|
||||||
SourceTitle = message.OriginalPath,
|
SourceTitle = message.OriginalPath,
|
||||||
|
@ -342,9 +343,9 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
foreach (var track in message.TrackFile.Tracks.Value)
|
foreach (var track in message.TrackFile.Tracks.Value)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.TrackFileRetagged,
|
EventType = EntityHistoryEventType.TrackFileRetagged,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.TrackFile.Quality,
|
Quality = message.TrackFile.Quality,
|
||||||
SourceTitle = path,
|
SourceTitle = path,
|
||||||
|
@ -372,12 +373,12 @@ namespace NzbDrone.Core.History
|
||||||
|
|
||||||
public void Handle(DownloadIgnoredEvent message)
|
public void Handle(DownloadIgnoredEvent message)
|
||||||
{
|
{
|
||||||
var historyToAdd = new List<History>();
|
var historyToAdd = new List<EntityHistory>();
|
||||||
foreach (var albumId in message.AlbumIds)
|
foreach (var albumId in message.AlbumIds)
|
||||||
{
|
{
|
||||||
var history = new History
|
var history = new EntityHistory
|
||||||
{
|
{
|
||||||
EventType = HistoryEventType.DownloadIgnored,
|
EventType = EntityHistoryEventType.DownloadIgnored,
|
||||||
Date = DateTime.UtcNow,
|
Date = DateTime.UtcNow,
|
||||||
Quality = message.Quality,
|
Quality = message.Quality,
|
||||||
SourceTitle = message.SourceTitle,
|
SourceTitle = message.SourceTitle,
|
||||||
|
@ -395,12 +396,12 @@ namespace NzbDrone.Core.History
|
||||||
_historyRepository.InsertMany(historyToAdd);
|
_historyRepository.InsertMany(historyToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<History> Since(DateTime date, HistoryEventType? eventType)
|
public List<EntityHistory> Since(DateTime date, EntityHistoryEventType? eventType)
|
||||||
{
|
{
|
||||||
return _historyRepository.Since(date, eventType);
|
return _historyRepository.Since(date, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMany(IList<History> items)
|
public void UpdateMany(IList<EntityHistory> items)
|
||||||
{
|
{
|
||||||
_historyRepository.UpdateMany(items);
|
_historyRepository.UpdateMany(items);
|
||||||
}
|
}
|
|
@ -1,130 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using NzbDrone.Core.Datastore;
|
|
||||||
using NzbDrone.Core.Messaging.Events;
|
|
||||||
using NzbDrone.Core.Music;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.History
|
|
||||||
{
|
|
||||||
public interface IHistoryRepository : IBasicRepository<History>
|
|
||||||
{
|
|
||||||
History MostRecentForAlbum(int albumId);
|
|
||||||
History MostRecentForDownloadId(string downloadId);
|
|
||||||
List<History> FindByDownloadId(string downloadId);
|
|
||||||
List<History> GetByArtist(int artistId, HistoryEventType? eventType);
|
|
||||||
List<History> GetByAlbum(int albumId, HistoryEventType? eventType);
|
|
||||||
List<History> FindDownloadHistory(int idArtistId, QualityModel quality);
|
|
||||||
void DeleteForArtists(List<int> artistIds);
|
|
||||||
List<History> Since(DateTime date, HistoryEventType? eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
|
||||||
{
|
|
||||||
public HistoryRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
|
||||||
: base(database, eventAggregator)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public History MostRecentForAlbum(int albumId)
|
|
||||||
{
|
|
||||||
return Query(h => h.AlbumId == albumId)
|
|
||||||
.OrderByDescending(h => h.Date)
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public History MostRecentForDownloadId(string downloadId)
|
|
||||||
{
|
|
||||||
return Query(h => h.DownloadId == downloadId)
|
|
||||||
.OrderByDescending(h => h.Date)
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<History> FindByDownloadId(string downloadId)
|
|
||||||
{
|
|
||||||
return _database.QueryJoined<History, Artist, Album>(
|
|
||||||
Builder()
|
|
||||||
.Join<History, Artist>((h, a) => h.ArtistId == a.Id)
|
|
||||||
.Join<History, Album>((h, a) => h.AlbumId == a.Id)
|
|
||||||
.Where<History>(h => h.DownloadId == downloadId),
|
|
||||||
(history, artist, album) =>
|
|
||||||
{
|
|
||||||
history.Artist = artist;
|
|
||||||
history.Album = album;
|
|
||||||
return history;
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<History> GetByArtist(int artistId, HistoryEventType? eventType)
|
|
||||||
{
|
|
||||||
var builder = Builder().Where<History>(h => h.ArtistId == artistId);
|
|
||||||
|
|
||||||
if (eventType.HasValue)
|
|
||||||
{
|
|
||||||
builder.Where<History>(h => h.EventType == eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Query(builder).OrderByDescending(h => h.Date).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<History> GetByAlbum(int albumId, HistoryEventType? eventType)
|
|
||||||
{
|
|
||||||
var builder = Builder()
|
|
||||||
.Join<History, Album>((h, a) => h.AlbumId == a.Id)
|
|
||||||
.Where<History>(h => h.AlbumId == albumId);
|
|
||||||
|
|
||||||
if (eventType.HasValue)
|
|
||||||
{
|
|
||||||
builder.Where<History>(h => h.EventType == eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _database.QueryJoined<History, Album>(
|
|
||||||
builder,
|
|
||||||
(history, album) =>
|
|
||||||
{
|
|
||||||
history.Album = album;
|
|
||||||
return history;
|
|
||||||
}).OrderByDescending(h => h.Date).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<History> FindDownloadHistory(int idArtistId, QualityModel quality)
|
|
||||||
{
|
|
||||||
var allowed = new[] { HistoryEventType.Grabbed, HistoryEventType.DownloadFailed, HistoryEventType.TrackFileImported };
|
|
||||||
|
|
||||||
return Query(h => h.ArtistId == idArtistId &&
|
|
||||||
h.Quality == quality &&
|
|
||||||
allowed.Contains(h.EventType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteForArtists(List<int> artistIds)
|
|
||||||
{
|
|
||||||
Delete(c => artistIds.Contains(c.ArtistId));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override SqlBuilder PagedBuilder() => new SqlBuilder()
|
|
||||||
.Join<History, Artist>((h, a) => h.ArtistId == a.Id)
|
|
||||||
.Join<History, Album>((h, a) => h.AlbumId == a.Id)
|
|
||||||
.LeftJoin<History, Track>((h, t) => h.TrackId == t.Id);
|
|
||||||
protected override IEnumerable<History> PagedQuery(SqlBuilder builder) =>
|
|
||||||
_database.QueryJoined<History, Artist, Album, Track>(builder, (history, artist, album, track) =>
|
|
||||||
{
|
|
||||||
history.Artist = artist;
|
|
||||||
history.Album = album;
|
|
||||||
history.Track = track;
|
|
||||||
return history;
|
|
||||||
});
|
|
||||||
|
|
||||||
public List<History> Since(DateTime date, HistoryEventType? eventType)
|
|
||||||
{
|
|
||||||
var builder = Builder().Where<History>(x => x.Date >= date);
|
|
||||||
|
|
||||||
if (eventType.HasValue)
|
|
||||||
{
|
|
||||||
builder.Where<History>(h => h.EventType == eventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Query(builder).OrderBy(h => h.Date).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,28 @@
|
||||||
using System;
|
using System;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.ThingiProvider.Events;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public interface ISeedConfigProvider
|
public interface ISeedConfigProvider
|
||||||
{
|
{
|
||||||
TorrentSeedConfiguration GetSeedConfiguration(RemoteAlbum release);
|
TorrentSeedConfiguration GetSeedConfiguration(RemoteAlbum release);
|
||||||
|
TorrentSeedConfiguration GetSeedConfiguration(int indexerId, bool discography);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SeedConfigProvider : ISeedConfigProvider
|
public class SeedConfigProvider : ISeedConfigProvider, IHandle<ProviderUpdatedEvent<IIndexer>>
|
||||||
{
|
{
|
||||||
private readonly IIndexerFactory _indexerFactory;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
|
private readonly ICached<SeedCriteriaSettings> _cache;
|
||||||
|
|
||||||
public SeedConfigProvider(IIndexerFactory indexerFactory)
|
public SeedConfigProvider(IIndexerFactory indexerFactory, ICacheManager cacheManager)
|
||||||
{
|
{
|
||||||
_indexerFactory = indexerFactory;
|
_indexerFactory = indexerFactory;
|
||||||
|
_cache = cacheManager.GetRollingCache<SeedCriteriaSettings>(GetType(), "criteriaByIndexer", TimeSpan.FromHours(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TorrentSeedConfiguration GetSeedConfiguration(RemoteAlbum remoteAlbum)
|
public TorrentSeedConfiguration GetSeedConfiguration(RemoteAlbum remoteAlbum)
|
||||||
|
@ -31,33 +37,55 @@ namespace NzbDrone.Core.Indexers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return GetSeedConfiguration(remoteAlbum.Release.IndexerId, remoteAlbum.ParsedAlbumInfo.Discography);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TorrentSeedConfiguration GetSeedConfiguration(int indexerId, bool fullSeason)
|
||||||
|
{
|
||||||
|
if (indexerId == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seedCriteria = _cache.Get(indexerId.ToString(), () => FetchSeedCriteria(indexerId));
|
||||||
|
|
||||||
|
if (seedCriteria == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seedConfig = new TorrentSeedConfiguration
|
||||||
|
{
|
||||||
|
Ratio = seedCriteria.SeedRatio
|
||||||
|
};
|
||||||
|
|
||||||
|
var seedTime = fullSeason ? seedCriteria.DiscographySeedTime : seedCriteria.SeedTime;
|
||||||
|
if (seedTime.HasValue)
|
||||||
|
{
|
||||||
|
seedConfig.SeedTime = TimeSpan.FromMinutes(seedTime.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return seedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SeedCriteriaSettings FetchSeedCriteria(int indexerId)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var indexer = _indexerFactory.Get(remoteAlbum.Release.IndexerId);
|
var indexer = _indexerFactory.Get(indexerId);
|
||||||
var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings;
|
var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings;
|
||||||
|
|
||||||
if (torrentIndexerSettings != null && torrentIndexerSettings.SeedCriteria != null)
|
return torrentIndexerSettings?.SeedCriteria;
|
||||||
{
|
|
||||||
var seedConfig = new TorrentSeedConfiguration
|
|
||||||
{
|
|
||||||
Ratio = torrentIndexerSettings.SeedCriteria.SeedRatio
|
|
||||||
};
|
|
||||||
|
|
||||||
var seedTime = remoteAlbum.ParsedAlbumInfo.Discography ? torrentIndexerSettings.SeedCriteria.DiscographySeedTime : torrentIndexerSettings.SeedCriteria.SeedTime;
|
|
||||||
if (seedTime.HasValue)
|
|
||||||
{
|
|
||||||
seedConfig.SeedTime = TimeSpan.FromMinutes(seedTime.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return seedConfig;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (ModelNotFoundException)
|
catch (ModelNotFoundException)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
public void Handle(ProviderUpdatedEvent<IIndexer> message)
|
||||||
|
{
|
||||||
|
_cache.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.MediaFiles.Commands;
|
using NzbDrone.Core.MediaFiles.Commands;
|
||||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||||
|
@ -16,16 +17,19 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
private readonly IDownloadedTracksImportService _downloadedTracksImportService;
|
private readonly IDownloadedTracksImportService _downloadedTracksImportService;
|
||||||
private readonly ITrackedDownloadService _trackedDownloadService;
|
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly ICompletedDownloadService _completedDownloadService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public DownloadedAlbumsCommandService(IDownloadedTracksImportService downloadedTracksImportService,
|
public DownloadedAlbumsCommandService(IDownloadedTracksImportService downloadedTracksImportService,
|
||||||
ITrackedDownloadService trackedDownloadService,
|
ITrackedDownloadService trackedDownloadService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
|
ICompletedDownloadService completedDownloadService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_downloadedTracksImportService = downloadedTracksImportService;
|
_downloadedTracksImportService = downloadedTracksImportService;
|
||||||
_trackedDownloadService = trackedDownloadService;
|
_trackedDownloadService = trackedDownloadService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
|
_completedDownloadService = completedDownloadService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,14 +49,14 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
{
|
{
|
||||||
_logger.Debug("External directory scan request for known download {0}. [{1}]", message.DownloadClientId, message.Path);
|
_logger.Debug("External directory scan request for known download {0}. [{1}]", message.DownloadClientId, message.Path);
|
||||||
|
|
||||||
return _downloadedTracksImportService.ProcessPath(message.Path, message.ImportMode, trackedDownload.RemoteAlbum.Artist, trackedDownload.DownloadItem);
|
var importResults = _downloadedTracksImportService.ProcessPath(message.Path, message.ImportMode, trackedDownload.RemoteAlbum.Artist, trackedDownload.DownloadItem);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Warn("External directory scan request for unknown download {0}, attempting normal import. [{1}]", message.DownloadClientId, message.Path);
|
|
||||||
|
|
||||||
return _downloadedTracksImportService.ProcessPath(message.Path, message.ImportMode);
|
_completedDownloadService.VerifyImport(trackedDownload, importResults);
|
||||||
|
|
||||||
|
return importResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Warn("External directory scan request for unknown download {0}, attempting normal import. [{1}]", message.DownloadClientId, message.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _downloadedTracksImportService.ProcessPath(message.Path, message.ImportMode);
|
return _downloadedTracksImportService.ProcessPath(message.Path, message.ImportMode);
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
public List<TrackFile> ImportedTracks { get; private set; }
|
public List<TrackFile> ImportedTracks { get; private set; }
|
||||||
public List<TrackFile> OldFiles { get; private set; }
|
public List<TrackFile> 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 AlbumImportedEvent(Artist artist, Album album, AlbumRelease release, List<TrackFile> importedTracks, List<TrackFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem)
|
public AlbumImportedEvent(Artist artist, Album album, AlbumRelease release, List<TrackFile> importedTracks, List<TrackFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem)
|
||||||
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
|
||||||
if (downloadClientItem != null)
|
if (downloadClientItem != null)
|
||||||
{
|
{
|
||||||
DownloadClient = downloadClientItem.DownloadClientInfo.Name;
|
DownloadClientInfo = downloadClientItem.DownloadClientInfo;
|
||||||
DownloadId = downloadClientItem.DownloadId;
|
DownloadId = downloadClientItem.DownloadId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
public Exception Exception { get; set; }
|
public Exception Exception { get; set; }
|
||||||
public LocalTrack TrackInfo { get; }
|
public LocalTrack TrackInfo { get; }
|
||||||
public bool NewDownload { get; }
|
public bool NewDownload { get; }
|
||||||
public string DownloadClient { get; }
|
public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
|
||||||
public string DownloadId { get; }
|
public string DownloadId { get; }
|
||||||
|
|
||||||
public TrackImportFailedEvent(Exception exception, LocalTrack trackInfo, bool newDownload, DownloadClientItem downloadClientItem)
|
public TrackImportFailedEvent(Exception exception, LocalTrack trackInfo, bool newDownload, DownloadClientItem downloadClientItem)
|
||||||
|
@ -21,7 +21,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
|
||||||
if (downloadClientItem != null)
|
if (downloadClientItem != null)
|
||||||
{
|
{
|
||||||
DownloadClient = downloadClientItem.DownloadClientInfo.Name;
|
DownloadClientInfo = downloadClientItem.DownloadClientInfo;
|
||||||
DownloadId = downloadClientItem.DownloadId;
|
DownloadId = downloadClientItem.DownloadId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
public TrackFile ImportedTrack { get; private set; }
|
public TrackFile ImportedTrack { get; private set; }
|
||||||
public List<TrackFile> OldFiles { get; private set; }
|
public List<TrackFile> 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 TrackImportedEvent(LocalTrack trackInfo, TrackFile importedTrack, List<TrackFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem)
|
public TrackImportedEvent(LocalTrack trackInfo, TrackFile importedTrack, List<TrackFile> oldFiles, bool newDownload, DownloadClientItem downloadClientItem)
|
||||||
|
@ -23,7 +23,7 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
|
||||||
if (downloadClientItem != null)
|
if (downloadClientItem != null)
|
||||||
{
|
{
|
||||||
DownloadClient = downloadClientItem.DownloadClientInfo.Name;
|
DownloadClientInfo = downloadClientItem.DownloadClientInfo;
|
||||||
DownloadId = downloadClientItem.DownloadId;
|
DownloadId = downloadClientItem.DownloadId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,16 +40,18 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
}
|
}
|
||||||
|
|
||||||
var albumHistory = _historyService.GetByAlbum(albumRelease.AlbumId, null);
|
var albumHistory = _historyService.GetByAlbum(albumRelease.AlbumId, null);
|
||||||
var lastImported = albumHistory.FirstOrDefault(h => h.EventType == HistoryEventType.DownloadImported);
|
var lastImported = albumHistory.FirstOrDefault(h => h.EventType == EntityHistoryEventType.DownloadImported);
|
||||||
var lastGrabbed = albumHistory.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed);
|
var lastGrabbed = albumHistory.FirstOrDefault(h => h.EventType == EntityHistoryEventType.Grabbed);
|
||||||
|
|
||||||
if (lastImported == null)
|
if (lastImported == null)
|
||||||
{
|
{
|
||||||
|
_logger.Trace("Track file has not been imported");
|
||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastGrabbed != null && lastGrabbed.Date.After(lastImported.Date))
|
if (lastGrabbed != null && lastGrabbed.Date.After(lastImported.Date))
|
||||||
{
|
{
|
||||||
|
_logger.Trace("Track file was grabbed again after importing");
|
||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
Artist = message.Artist,
|
Artist = message.Artist,
|
||||||
Album = message.Album,
|
Album = message.Album,
|
||||||
Release = message.AlbumRelease,
|
Release = message.AlbumRelease,
|
||||||
DownloadClient = message.DownloadClient,
|
DownloadClient = message.DownloadClientInfo?.Name,
|
||||||
DownloadId = message.DownloadId,
|
DownloadId = message.DownloadId,
|
||||||
TrackFiles = message.ImportedTracks,
|
TrackFiles = message.ImportedTracks,
|
||||||
OldFiles = message.OldFiles,
|
OldFiles = message.OldFiles,
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace NzbDrone.Core.Queue
|
||||||
private Queue MapQueueItem(TrackedDownload trackedDownload, Album album)
|
private Queue MapQueueItem(TrackedDownload trackedDownload, Album album)
|
||||||
{
|
{
|
||||||
bool downloadForced = false;
|
bool downloadForced = false;
|
||||||
var history = _historyService.Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed).FirstOrDefault();
|
var history = _historyService.Find(trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed).FirstOrDefault();
|
||||||
if (history != null && history.Data.ContainsKey("downloadForced"))
|
if (history != null && history.Data.ContainsKey("downloadForced"))
|
||||||
{
|
{
|
||||||
downloadForced = bool.Parse(history.Data["downloadForced"]);
|
downloadForced = bool.Parse(history.Data["downloadForced"]);
|
||||||
|
|
Loading…
Reference in New Issue