mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-14 11:23:42 +02:00
Episode searching now stores the results of the tests.
This commit is contained in:
parent
b9e3d1a921
commit
c7f8f57f77
@ -6,9 +6,11 @@
|
|||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Jobs;
|
using NzbDrone.Core.Jobs;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
using NzbDrone.Core.Model.Notification;
|
using NzbDrone.Core.Model.Notification;
|
||||||
using NzbDrone.Core.Providers;
|
using NzbDrone.Core.Providers;
|
||||||
using NzbDrone.Core.Repository;
|
using NzbDrone.Core.Repository;
|
||||||
|
using NzbDrone.Core.Repository.Search;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common.AutoMoq;
|
using NzbDrone.Test.Common.AutoMoq;
|
||||||
|
|
||||||
@ -39,10 +41,16 @@ public void SeasonSearch_full_season_success()
|
|||||||
[Test]
|
[Test]
|
||||||
public void SeasonSearch_partial_season_success()
|
public void SeasonSearch_partial_season_success()
|
||||||
{
|
{
|
||||||
|
var resultItems = Builder<SearchResultItem>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(e => e.SearchError = ReportRejectionType.None)
|
||||||
|
.With(e => e.Success = true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||||
.All()
|
.All()
|
||||||
.With(e => e.SeriesId = 1)
|
|
||||||
.With(e => e.SeasonNumber = 1)
|
.With(e => e.SeasonNumber = 1)
|
||||||
|
.With(e => e.SeriesId = 5)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var notification = new ProgressNotification("Season Search");
|
var notification = new ProgressNotification("Season Search");
|
||||||
@ -55,7 +63,7 @@ public void SeasonSearch_partial_season_success()
|
|||||||
|
|
||||||
Mocker.GetMock<SearchProvider>()
|
Mocker.GetMock<SearchProvider>()
|
||||||
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
||||||
.Returns(episodes.Select(e => e.EpisodeNumber).ToList());
|
.Returns(resultItems.ToList());
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
||||||
@ -88,7 +96,7 @@ public void SeasonSearch_partial_season_failure()
|
|||||||
|
|
||||||
Mocker.GetMock<SearchProvider>()
|
Mocker.GetMock<SearchProvider>()
|
||||||
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
||||||
.Returns(new List<int>{1});
|
.Returns(new List<SearchResultItem>{ new SearchResultItem{ Success = true }});
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
||||||
@ -122,7 +130,7 @@ public void SeasonSearch_should_not_search_for_episodes_that_havent_aired_yet_or
|
|||||||
|
|
||||||
Mocker.GetMock<SearchProvider>()
|
Mocker.GetMock<SearchProvider>()
|
||||||
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
||||||
.Returns(new List<int>());
|
.Returns(new List<SearchResultItem> { new SearchResultItem { Success = false, SearchError = ReportRejectionType.Size} });
|
||||||
|
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
|
@ -88,42 +88,42 @@ private void WithOverRetention()
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_be_allowed_if_all_conditions_are_met()
|
public void should_be_allowed_if_all_conditions_are_met()
|
||||||
{
|
{
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeTrue();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_be_allowed_if_profile_is_not_allowed()
|
public void should_not_be_allowed_if_profile_is_not_allowed()
|
||||||
{
|
{
|
||||||
WithProfileNotAllowed();
|
WithProfileNotAllowed();
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.QualityNotWanted);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_be_allowed_if_size_is_not_allowed()
|
public void should_not_be_allowed_if_size_is_not_allowed()
|
||||||
{
|
{
|
||||||
WithNotAcceptableSize();
|
WithNotAcceptableSize();
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_be_allowed_if_disk_is_not_upgrade()
|
public void should_not_be_allowed_if_disk_is_not_upgrade()
|
||||||
{
|
{
|
||||||
WithNoDiskUpgrade();
|
WithNoDiskUpgrade();
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_be_allowed_if_episode_is_already_in_queue()
|
public void should_not_be_allowed_if_episode_is_already_in_queue()
|
||||||
{
|
{
|
||||||
WithEpisodeAlreadyInQueue();
|
WithEpisodeAlreadyInQueue();
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.AlreadyInQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_be_allowed_if_report_is_over_retention()
|
public void should_not_be_allowed_if_report_is_over_retention()
|
||||||
{
|
{
|
||||||
WithOverRetention();
|
WithOverRetention();
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.Retention);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -134,7 +134,7 @@ public void should_not_be_allowed_if_none_of_conditions_are_met()
|
|||||||
WithProfileNotAllowed();
|
WithProfileNotAllowed();
|
||||||
WithOverRetention();
|
WithOverRetention();
|
||||||
|
|
||||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.QualityNotWanted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -77,14 +77,14 @@ private void WithQualityNeeded()
|
|||||||
{
|
{
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||||
.Returns(true);
|
.Returns(ReportRejectionType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithQualityNotNeeded()
|
private void WithQualityNotNeeded()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||||
.Returns(false);
|
.Returns(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -103,13 +103,13 @@ public void processSearchResults_higher_quality_should_be_called_first()
|
|||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
||||||
.Returns(true);
|
.Returns(ReportRejectionType.None);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeTrue();
|
result.Should().Contain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Once());
|
Times.Once());
|
||||||
@ -133,7 +133,7 @@ public void processSearchResults_when_quality_is_not_needed_should_check_the_res
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeFalse();
|
result.Should().NotContain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Exactly(5));
|
Times.Exactly(5));
|
||||||
@ -155,7 +155,7 @@ public void processSearchResults_should_skip_if_series_is_null()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeFalse();
|
result.Should().NotContain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -175,7 +175,7 @@ public void processSearchResults_should_skip_if_series_is_mismatched()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeFalse();
|
result.Should().NotContain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -198,7 +198,7 @@ public void processSearchResults_should_return_after_successful_download()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeTrue();
|
result.Should().Contain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Once());
|
Times.Once());
|
||||||
@ -230,7 +230,7 @@ public void processSearchResults_should_try_next_if_download_fails()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeTrue();
|
result.Should().Contain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Exactly(2));
|
Times.Exactly(2));
|
||||||
@ -250,7 +250,7 @@ public void processSearchResults_should_skip_if_parseResult_does_not_have_airdat
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeFalse();
|
result.Should().NotContain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -270,7 +270,7 @@ public void processSearchResults_should_skip_if_parseResult_airdate_does_not_mat
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().BeFalse();
|
result.Should().NotContain(n => n.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
|
@ -73,14 +73,14 @@ private void WithQualityNeeded()
|
|||||||
{
|
{
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||||
.Returns(true);
|
.Returns(ReportRejectionType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithQualityNotNeeded()
|
private void WithQualityNotNeeded()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||||
.Returns(false);
|
.Returns(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -102,14 +102,14 @@ public void processSearchResults_higher_quality_should_be_called_first()
|
|||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
||||||
.Returns(true);
|
.Returns(ReportRejectionType.None);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
result.First().Should().Be(1);
|
result.Should().Contain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Once());
|
Times.Once());
|
||||||
@ -135,13 +135,14 @@ public void processSearchResults_newer_report_should_be_called_first()
|
|||||||
WithSuccessfulDownload();
|
WithSuccessfulDownload();
|
||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>())).Returns(true);
|
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>())).Returns(ReportRejectionType.None);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().Contain(s => s.Success);
|
||||||
|
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.Is<EpisodeParseResult>(d => d.Age != 100)), Times.Never());
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.Is<EpisodeParseResult>(d => d.Age != 100)), Times.Never());
|
||||||
@ -165,7 +166,8 @@ public void processSearchResults_when_quality_is_not_needed_should_check_the_res
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(0);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().NotContain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Exactly(5));
|
Times.Exactly(5));
|
||||||
@ -188,7 +190,8 @@ public void processSearchResults_should_skip_if_series_is_null()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(0);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().NotContain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -209,7 +212,8 @@ public void processSearchResults_should_skip_if_series_is_mismatched()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(0);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().NotContain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -230,7 +234,8 @@ public void processSearchResults_should_skip_if_season_doesnt_match()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(0);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().NotContain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -251,7 +256,8 @@ public void processSearchResults_should_skip_if_episodeNumber_doesnt_match()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(0);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().NotContain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
@ -277,7 +283,8 @@ public void processSearchResults_should_skip_if_any_episodeNumber_was_already_ad
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().Contain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Once());
|
Times.Once());
|
||||||
@ -310,7 +317,8 @@ public void processSearchResults_should_try_next_if_download_fails()
|
|||||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(parseResults.Count);
|
||||||
|
result.Should().Contain(s => s.Success);
|
||||||
|
|
||||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
Times.Exactly(2));
|
Times.Exactly(2));
|
||||||
|
@ -70,7 +70,7 @@ public void Start(ProgressNotification notification, int targetId, int secondary
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_isMonitoredEpisodeSpecification.IsSatisfiedBy(episodeParseResult) &&
|
if (_isMonitoredEpisodeSpecification.IsSatisfiedBy(episodeParseResult) &&
|
||||||
_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult) &&
|
_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult) == ReportRejectionType.None &&
|
||||||
_upgradeHistorySpecification.IsSatisfiedBy(episodeParseResult))
|
_upgradeHistorySpecification.IsSatisfiedBy(episodeParseResult))
|
||||||
{
|
{
|
||||||
_downloadProvider.DownloadReport(episodeParseResult);
|
_downloadProvider.DownloadReport(episodeParseResult);
|
||||||
|
@ -60,15 +60,15 @@ public virtual void Start(ProgressNotification notification, int targetId, int s
|
|||||||
//Perform a Partial Season Search
|
//Perform a Partial Season Search
|
||||||
var addedSeries = _searchProvider.PartialSeasonSearch(notification, targetId, secondaryTargetId);
|
var addedSeries = _searchProvider.PartialSeasonSearch(notification, targetId, secondaryTargetId);
|
||||||
|
|
||||||
addedSeries.Distinct().ToList().Sort();
|
//addedSeries.Distinct().ToList().Sort();
|
||||||
var episodeNumbers = episodes.Where(w => w.AirDate <= DateTime.Today.AddDays(1)).Select(s => s.EpisodeNumber).ToList();
|
//var episodeNumbers = episodes.Where(w => w.AirDate <= DateTime.Today.AddDays(1)).Select(s => s.EpisodeNumber).ToList();
|
||||||
episodeNumbers.Sort();
|
//episodeNumbers.Sort();
|
||||||
|
|
||||||
if (addedSeries.SequenceEqual(episodeNumbers))
|
//if (addedSeries.SequenceEqual(episodeNumbers))
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
//Get the list of episodes that weren't downloaded
|
////Get the list of episodes that weren't downloaded
|
||||||
var missingEpisodes = episodeNumbers.Except(addedSeries).ToList();
|
//var missingEpisodes = episodeNumbers.Except(addedSeries).ToList();
|
||||||
|
|
||||||
//TODO: do one by one check only when max number of feeds have been returned by the indexer
|
//TODO: do one by one check only when max number of feeds have been returned by the indexer
|
||||||
//Only process episodes that is in missing episodes (To ensure we double check if the episode is available)
|
//Only process episodes that is in missing episodes (To ensure we double check if the episode is available)
|
||||||
|
21
NzbDrone.Core/Model/ReportRejectionType.cs
Normal file
21
NzbDrone.Core/Model/ReportRejectionType.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Model
|
||||||
|
{
|
||||||
|
public enum ReportRejectionType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
WrongSeries = 1,
|
||||||
|
QualityNotWanted = 2,
|
||||||
|
WrongSeason = 3,
|
||||||
|
WrongEpisode = 3,
|
||||||
|
Size = 3,
|
||||||
|
Retention = 3,
|
||||||
|
ExistingQualityIsEqualOrBetter = 4,
|
||||||
|
Cutoff = 5,
|
||||||
|
AlreadyInQueue = 6,
|
||||||
|
DownloadClientFailure = 7,
|
||||||
|
Skipped = 8,
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
}
|
@ -277,6 +277,7 @@
|
|||||||
<Compile Include="Providers\Indexer\NzbIndex.cs" />
|
<Compile Include="Providers\Indexer\NzbIndex.cs" />
|
||||||
<Compile Include="Providers\Indexer\FileSharingTalk.cs" />
|
<Compile Include="Providers\Indexer\FileSharingTalk.cs" />
|
||||||
<Compile Include="Providers\Indexer\Wombles.cs" />
|
<Compile Include="Providers\Indexer\Wombles.cs" />
|
||||||
|
<Compile Include="Providers\SearchResultProvider.cs" />
|
||||||
<Compile Include="Providers\SeasonProvider.cs" />
|
<Compile Include="Providers\SeasonProvider.cs" />
|
||||||
<Compile Include="Jobs\RecentBacklogSearchJob.cs" />
|
<Compile Include="Jobs\RecentBacklogSearchJob.cs" />
|
||||||
<Compile Include="Jobs\TrimLogsJob.cs" />
|
<Compile Include="Jobs\TrimLogsJob.cs" />
|
||||||
@ -304,6 +305,9 @@
|
|||||||
<Compile Include="Providers\AnalyticsProvider.cs">
|
<Compile Include="Providers\AnalyticsProvider.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Repository\Search\SearchResultItem.cs" />
|
||||||
|
<Compile Include="Repository\Search\SearchResult.cs" />
|
||||||
|
<Compile Include="Model\ReportRejectionType.cs" />
|
||||||
<Compile Include="Repository\Season.cs" />
|
<Compile Include="Repository\Season.cs" />
|
||||||
<Compile Include="Providers\AutoConfigureProvider.cs">
|
<Compile Include="Providers\AutoConfigureProvider.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using NzbDrone.Core.Model;
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Repository.Search;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Providers.DecisionEngine
|
namespace NzbDrone.Core.Providers.DecisionEngine
|
||||||
{
|
{
|
||||||
@ -30,16 +31,16 @@ public AllowedDownloadSpecification()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsSatisfiedBy(EpisodeParseResult subject)
|
public virtual ReportRejectionType IsSatisfiedBy(EpisodeParseResult subject)
|
||||||
{
|
{
|
||||||
if (!_qualityAllowedByProfileSpecification.IsSatisfiedBy(subject)) return false;
|
if (!_qualityAllowedByProfileSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.QualityNotWanted;
|
||||||
if (!_upgradeDiskSpecification.IsSatisfiedBy(subject)) return false;
|
if (!_upgradeDiskSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.ExistingQualityIsEqualOrBetter;
|
||||||
if (!_retentionSpecification.IsSatisfiedBy(subject)) return false;
|
if (!_retentionSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.Retention;
|
||||||
if (!_acceptableSizeSpecification.IsSatisfiedBy(subject)) return false;
|
if (!_acceptableSizeSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.Size;
|
||||||
if (_alreadyInQueueSpecification.IsSatisfiedBy(subject)) return false;
|
if (_alreadyInQueueSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.AlreadyInQueue;
|
||||||
|
|
||||||
logger.Debug("Episode {0} is needed", subject);
|
logger.Debug("Episode {0} is needed", subject);
|
||||||
return true;
|
return ReportRejectionType.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@
|
|||||||
using NzbDrone.Core.Model.Notification;
|
using NzbDrone.Core.Model.Notification;
|
||||||
using NzbDrone.Core.Providers.DecisionEngine;
|
using NzbDrone.Core.Providers.DecisionEngine;
|
||||||
using NzbDrone.Core.Repository;
|
using NzbDrone.Core.Repository;
|
||||||
|
using NzbDrone.Core.Repository.Search;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Providers
|
namespace NzbDrone.Core.Providers
|
||||||
{
|
{
|
||||||
@ -21,13 +22,15 @@ public class SearchProvider
|
|||||||
private readonly SceneMappingProvider _sceneMappingProvider;
|
private readonly SceneMappingProvider _sceneMappingProvider;
|
||||||
private readonly UpgradePossibleSpecification _upgradePossibleSpecification;
|
private readonly UpgradePossibleSpecification _upgradePossibleSpecification;
|
||||||
private readonly AllowedDownloadSpecification _allowedDownloadSpecification;
|
private readonly AllowedDownloadSpecification _allowedDownloadSpecification;
|
||||||
|
private readonly SearchResultProvider _searchResultProvider;
|
||||||
|
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider,
|
public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider,
|
||||||
IndexerProvider indexerProvider, SceneMappingProvider sceneMappingProvider,
|
IndexerProvider indexerProvider, SceneMappingProvider sceneMappingProvider,
|
||||||
UpgradePossibleSpecification upgradePossibleSpecification, AllowedDownloadSpecification allowedDownloadSpecification)
|
UpgradePossibleSpecification upgradePossibleSpecification, AllowedDownloadSpecification allowedDownloadSpecification,
|
||||||
|
SearchResultProvider searchResultProvider)
|
||||||
{
|
{
|
||||||
_episodeProvider = episodeProvider;
|
_episodeProvider = episodeProvider;
|
||||||
_downloadProvider = downloadProvider;
|
_downloadProvider = downloadProvider;
|
||||||
@ -36,6 +39,7 @@ public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider download
|
|||||||
_sceneMappingProvider = sceneMappingProvider;
|
_sceneMappingProvider = sceneMappingProvider;
|
||||||
_upgradePossibleSpecification = upgradePossibleSpecification;
|
_upgradePossibleSpecification = upgradePossibleSpecification;
|
||||||
_allowedDownloadSpecification = allowedDownloadSpecification;
|
_allowedDownloadSpecification = allowedDownloadSpecification;
|
||||||
|
_searchResultProvider = searchResultProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchProvider()
|
public SearchProvider()
|
||||||
@ -44,13 +48,20 @@ public SearchProvider()
|
|||||||
|
|
||||||
public virtual bool SeasonSearch(ProgressNotification notification, int seriesId, int seasonNumber)
|
public virtual bool SeasonSearch(ProgressNotification notification, int seriesId, int seasonNumber)
|
||||||
{
|
{
|
||||||
|
var searchResult = new SearchResult
|
||||||
|
{
|
||||||
|
SearchTime = DateTime.Now,
|
||||||
|
SeriesId = seriesId,
|
||||||
|
SeasonNumber = seasonNumber
|
||||||
|
};
|
||||||
|
|
||||||
var series = _seriesProvider.GetSeries(seriesId);
|
var series = _seriesProvider.GetSeries(seriesId);
|
||||||
|
|
||||||
if (series == null)
|
if (series == null)
|
||||||
{
|
{
|
||||||
Logger.Error("Unable to find an series {0} in database", seriesId);
|
Logger.Error("Unable to find an series {0} in database", seriesId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return false if the series is a daily series (we only support individual episode searching
|
//Return false if the series is a daily series (we only support individual episode searching
|
||||||
if (series.IsDaily)
|
if (series.IsDaily)
|
||||||
@ -80,46 +91,45 @@ public virtual bool SeasonSearch(ProgressNotification notification, int seriesId
|
|||||||
e => e.EpisodeNumbers = episodeNumbers.ToList()
|
e => e.EpisodeNumbers = episodeNumbers.ToList()
|
||||||
);
|
);
|
||||||
|
|
||||||
var downloadedEpisodes = ProcessSearchResults(notification, reports, series, seasonNumber);
|
searchResult.SearchResultItems = ProcessSearchResults(notification, reports, series, seasonNumber);
|
||||||
|
|
||||||
downloadedEpisodes.Sort();
|
return (searchResult.SearchResultItems.Select(s => s.Success).Count() == episodeNumbers.Count);
|
||||||
episodeNumbers.ToList().Sort();
|
|
||||||
|
|
||||||
//Returns true if the list of downloaded episodes matches the list of episode numbers
|
|
||||||
//(either a full season release was grabbed or all individual episodes)
|
|
||||||
return (downloadedEpisodes.SequenceEqual(episodeNumbers));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual List<int> PartialSeasonSearch(ProgressNotification notification, int seriesId, int seasonNumber)
|
public virtual List<SearchResultItem> PartialSeasonSearch(ProgressNotification notification, int seriesId, int seasonNumber)
|
||||||
{
|
{
|
||||||
//This method will search for episodes in a season in groups of 10 episodes S01E0, S01E1, S01E2, etc
|
var searchResult = new SearchResult
|
||||||
|
{
|
||||||
|
SearchTime = DateTime.Now,
|
||||||
|
SeriesId = seriesId,
|
||||||
|
SeasonNumber = seasonNumber
|
||||||
|
};
|
||||||
|
|
||||||
var series = _seriesProvider.GetSeries(seriesId);
|
var series = _seriesProvider.GetSeries(seriesId);
|
||||||
|
|
||||||
if (series == null)
|
if (series == null)
|
||||||
{
|
{
|
||||||
Logger.Error("Unable to find an series {0} in database", seriesId);
|
Logger.Error("Unable to find an series {0} in database", seriesId);
|
||||||
return new List<int>();
|
return new List<SearchResultItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return empty list if the series is a daily series (we only support individual episode searching
|
//Return empty list if the series is a daily series (we only support individual episode searching
|
||||||
if (series.IsDaily)
|
if (series.IsDaily)
|
||||||
return new List<int>();
|
return new List<SearchResultItem>();
|
||||||
|
|
||||||
notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber);
|
notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber);
|
||||||
|
|
||||||
var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber);
|
var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber);
|
||||||
|
|
||||||
var reports = PerformSearch(notification, series, seasonNumber, episodes);
|
var reports = PerformSearch(notification, series, seasonNumber, episodes);
|
||||||
|
|
||||||
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
||||||
|
|
||||||
if (reports.Count == 0)
|
if (reports.Count == 0)
|
||||||
return new List<int>();
|
return new List<SearchResultItem>();
|
||||||
|
|
||||||
notification.CurrentMessage = "Processing search results";
|
notification.CurrentMessage = "Processing search results";
|
||||||
|
searchResult.SearchResultItems = ProcessSearchResults(notification, reports, series, seasonNumber);
|
||||||
|
|
||||||
return ProcessSearchResults(notification, reports, series, seasonNumber);
|
_searchResultProvider.Add(searchResult);
|
||||||
|
return searchResult.SearchResultItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool EpisodeSearch(ProgressNotification notification, int episodeId)
|
public virtual bool EpisodeSearch(ProgressNotification notification, int episodeId)
|
||||||
@ -136,7 +146,7 @@ public virtual bool EpisodeSearch(ProgressNotification notification, int episode
|
|||||||
if (!_upgradePossibleSpecification.IsSatisfiedBy(episode))
|
if (!_upgradePossibleSpecification.IsSatisfiedBy(episode))
|
||||||
{
|
{
|
||||||
Logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
|
Logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode);
|
||||||
notification.CurrentMessage = String.Format("Skipping search for {0}, file you have is already at cutoff", episode);
|
notification.CurrentMessage = String.Format("Skipping search for {0}, the file you have is already at cutoff", episode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,19 +155,41 @@ public virtual bool EpisodeSearch(ProgressNotification notification, int episode
|
|||||||
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
|
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
|
||||||
{
|
{
|
||||||
Logger.Warn("AirDate is not Valid for: {0}", episode);
|
Logger.Warn("AirDate is not Valid for: {0}", episode);
|
||||||
|
notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var searchResult = new SearchResult
|
||||||
|
{
|
||||||
|
SearchTime = DateTime.Now,
|
||||||
|
SeriesId = episode.Series.SeriesId
|
||||||
|
};
|
||||||
|
|
||||||
var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List<Episode> { episode });
|
var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List<Episode> { episode });
|
||||||
|
|
||||||
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
||||||
notification.CurrentMessage = "Processing search results";
|
notification.CurrentMessage = "Processing search results";
|
||||||
|
|
||||||
if (!episode.Series.IsDaily && ProcessSearchResults(notification, reports, episode.Series, episode.SeasonNumber, episode.EpisodeNumber).Count == 1)
|
if (episode.Series.IsDaily)
|
||||||
return true;
|
{
|
||||||
|
searchResult.AirDate = episode.AirDate.Value;
|
||||||
|
searchResult.SearchResultItems = ProcessSearchResults(notification, reports, episode.Series, episode.AirDate.Value);
|
||||||
|
|
||||||
if (episode.Series.IsDaily && ProcessSearchResults(notification, reports, episode.Series, episode.AirDate.Value))
|
_searchResultProvider.Add(searchResult);
|
||||||
|
|
||||||
|
if (searchResult.SearchResultItems.Any(r => r.Success))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!episode.Series.IsDaily)
|
||||||
|
{
|
||||||
|
searchResult.SeasonNumber = episode.SeasonNumber;
|
||||||
|
searchResult.EpisodeId = episodeId;
|
||||||
|
ProcessSearchResults(notification, reports, episode.Series, episode.SeasonNumber, episode.EpisodeNumber);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Warn("Unable to find {0} in any of indexers.", episode);
|
Logger.Warn("Unable to find {0} in any of indexers.", episode);
|
||||||
|
|
||||||
@ -170,7 +202,6 @@ public virtual bool EpisodeSearch(ProgressNotification notification, int episode
|
|||||||
notification.CurrentMessage = String.Format("Sorry, couldn't find you {0} in any of indexers.", episode);
|
notification.CurrentMessage = String.Format("Sorry, couldn't find you {0} in any of indexers.", episode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,9 +258,10 @@ public List<EpisodeParseResult> PerformSearch(ProgressNotification notification,
|
|||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<int> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, int seasonNumber, int? episodeNumber = null)
|
public List<SearchResultItem> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, int seasonNumber, int? episodeNumber = null)
|
||||||
{
|
{
|
||||||
var successes = new List<int>();
|
var successes = new List<int>();
|
||||||
|
var items = new List<SearchResultItem>();
|
||||||
|
|
||||||
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality).ThenBy(c => c.Age))
|
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality).ThenBy(c => c.Age))
|
||||||
{
|
{
|
||||||
@ -237,6 +269,14 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
{
|
{
|
||||||
Logger.Trace("Analysing report " + episodeParseResult);
|
Logger.Trace("Analysing report " + episodeParseResult);
|
||||||
|
|
||||||
|
var item = new SearchResultItem
|
||||||
|
{
|
||||||
|
ReportTitle = episodeParseResult.OriginalString,
|
||||||
|
NzbUrl = episodeParseResult.NzbUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
items.Add(item);
|
||||||
|
|
||||||
//Get the matching series
|
//Get the matching series
|
||||||
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
|
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
|
||||||
|
|
||||||
@ -244,6 +284,7 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
||||||
{
|
{
|
||||||
Logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
|
Logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
|
||||||
|
item.SearchError = ReportRejectionType.WrongSeries;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +292,7 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
if (episodeParseResult.SeasonNumber != seasonNumber)
|
if (episodeParseResult.SeasonNumber != seasonNumber)
|
||||||
{
|
{
|
||||||
Logger.Trace("Season number does not match searched season number, skipping.");
|
Logger.Trace("Season number does not match searched season number, skipping.");
|
||||||
|
item.SearchError = ReportRejectionType.WrongSeason;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +300,7 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value))
|
if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value))
|
||||||
{
|
{
|
||||||
Logger.Trace("Searched episode number is not contained in post, skipping.");
|
Logger.Trace("Searched episode number is not contained in post, skipping.");
|
||||||
|
item.SearchError = ReportRejectionType.WrongEpisode;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,10 +308,12 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
if (successes.Intersect(episodeParseResult.EpisodeNumbers).Any())
|
if (successes.Intersect(episodeParseResult.EpisodeNumbers).Any())
|
||||||
{
|
{
|
||||||
Logger.Trace("Episode has already been downloaded in this search, skipping.");
|
Logger.Trace("Episode has already been downloaded in this search, skipping.");
|
||||||
|
item.SearchError = ReportRejectionType.Skipped;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult))
|
var rejectionType = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
|
||||||
|
if (rejectionType == ReportRejectionType.None)
|
||||||
{
|
{
|
||||||
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
||||||
try
|
try
|
||||||
@ -279,12 +324,18 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
|
|
||||||
//Add the list of episode numbers from this release
|
//Add the list of episode numbers from this release
|
||||||
successes.AddRange(episodeParseResult.EpisodeNumbers);
|
successes.AddRange(episodeParseResult.EpisodeNumbers);
|
||||||
|
item.Success = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
|
Logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e);
|
||||||
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
|
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
|
||||||
|
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,15 +345,32 @@ public List<int> ProcessSearchResults(ProgressNotification notification, IEnumer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return successes;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, DateTime airDate)
|
public List<SearchResultItem> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, DateTime airDate)
|
||||||
{
|
{
|
||||||
|
var items = new List<SearchResultItem>();
|
||||||
|
var skip = false;
|
||||||
|
|
||||||
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality))
|
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var item = new SearchResultItem
|
||||||
|
{
|
||||||
|
ReportTitle = episodeParseResult.OriginalString,
|
||||||
|
NzbUrl = episodeParseResult.NzbUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
items.Add(item);
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
item.SearchError = ReportRejectionType.Skipped;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Trace("Analysing report " + episodeParseResult);
|
Logger.Trace("Analysing report " + episodeParseResult);
|
||||||
|
|
||||||
//Get the matching series
|
//Get the matching series
|
||||||
@ -310,13 +378,20 @@ public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<
|
|||||||
|
|
||||||
//If series is null or doesn't match the series we're looking for return
|
//If series is null or doesn't match the series we're looking for return
|
||||||
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
||||||
|
{
|
||||||
|
item.SearchError = ReportRejectionType.WrongSeries;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//If parse result doesn't have an air date or it doesn't match passed in airdate, skip the report.
|
//If parse result doesn't have an air date or it doesn't match passed in airdate, skip the report.
|
||||||
if (!episodeParseResult.AirDate.HasValue || episodeParseResult.AirDate.Value.Date != airDate.Date)
|
if (!episodeParseResult.AirDate.HasValue || episodeParseResult.AirDate.Value.Date != airDate.Date)
|
||||||
|
{
|
||||||
|
item.SearchError = ReportRejectionType.WrongEpisode;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult))
|
var allowedDownload = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
|
||||||
|
if (allowedDownload == ReportRejectionType.None)
|
||||||
{
|
{
|
||||||
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
||||||
try
|
try
|
||||||
@ -327,7 +402,12 @@ public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<
|
|||||||
String.Format("{0} - {1} {2} Added to download queue",
|
String.Format("{0} - {1} {2} Added to download queue",
|
||||||
episodeParseResult.Series.Title, episodeParseResult.AirDate.Value.ToShortDateString(), episodeParseResult.Quality);
|
episodeParseResult.Series.Title, episodeParseResult.AirDate.Value.ToShortDateString(), episodeParseResult.Quality);
|
||||||
|
|
||||||
return true;
|
item.Success = true;
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -336,13 +416,18 @@ public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<
|
|||||||
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
|
notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SearchError = allowedDownload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
|
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<int> GetEpisodeNumberPrefixes(IEnumerable<int> episodeNumbers)
|
private List<int> GetEpisodeNumberPrefixes(IEnumerable<int> episodeNumbers)
|
||||||
|
60
NzbDrone.Core/Providers/SearchResultProvider.cs
Normal file
60
NzbDrone.Core/Providers/SearchResultProvider.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NLog;
|
||||||
|
using Ninject;
|
||||||
|
using NzbDrone.Core.Repository.Search;
|
||||||
|
using PetaPoco;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Providers
|
||||||
|
{
|
||||||
|
public class SearchResultProvider
|
||||||
|
{
|
||||||
|
private readonly IDatabase _database;
|
||||||
|
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
public SearchResultProvider(IDatabase database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchResultProvider()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Add(SearchResult searchResult)
|
||||||
|
{
|
||||||
|
logger.Trace("Adding new search result");
|
||||||
|
var id = Convert.ToInt32(_database.Insert(searchResult));
|
||||||
|
|
||||||
|
searchResult.SearchResultItems.ForEach(s => s.Id = id);
|
||||||
|
logger.Trace("Adding search result items");
|
||||||
|
_database.InsertMany(searchResult.SearchResultItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Delete(int id)
|
||||||
|
{
|
||||||
|
logger.Trace("Deleting search result items attached to: {0}", id);
|
||||||
|
_database.Execute("DELETE FROM SearchResultItems WHERE SearchResultId = @0", id);
|
||||||
|
|
||||||
|
logger.Trace("Deleting search result: {0}", id);
|
||||||
|
_database.Delete<SearchResult>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual List<SearchResult> AllSearchResults()
|
||||||
|
{
|
||||||
|
return _database.Fetch<SearchResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual SearchResult GetSearchResult(int id)
|
||||||
|
{
|
||||||
|
var result = _database.Single<SearchResult>(id);
|
||||||
|
result.SearchResultItems = _database.Fetch<SearchResultItem>("WHERE SearchResultId = @0", id);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
NzbDrone.Core/Repository/Search/SearchResult.cs
Normal file
24
NzbDrone.Core/Repository/Search/SearchResult.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Repository.Quality;
|
||||||
|
using PetaPoco;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Repository.Search
|
||||||
|
{
|
||||||
|
[PrimaryKey("Id", autoIncrement = true)]
|
||||||
|
[TableName("SearchResults")]
|
||||||
|
public class SearchResult
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int SeriesId { get; set; }
|
||||||
|
public int? SeasonNumber { get; set; }
|
||||||
|
public int? EpisodeId { get; set; }
|
||||||
|
public DateTime? AirDate { get; set; }
|
||||||
|
public DateTime SearchTime { get; set; }
|
||||||
|
|
||||||
|
[ResultColumn]
|
||||||
|
public List<SearchResultItem> SearchResultItems { get; set; }
|
||||||
|
}
|
||||||
|
}
|
22
NzbDrone.Core/Repository/Search/SearchResultItem.cs
Normal file
22
NzbDrone.Core/Repository/Search/SearchResultItem.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Repository.Quality;
|
||||||
|
using PetaPoco;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Repository.Search
|
||||||
|
{
|
||||||
|
[PrimaryKey("Id", autoIncrement = true)]
|
||||||
|
[TableName("SearchResultItems")]
|
||||||
|
public class SearchResultItem
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int SearchResultId { get; set; }
|
||||||
|
public string ReportTitle { get; set; }
|
||||||
|
public string NzbUrl { get; set; }
|
||||||
|
public string NzbInfoUrl { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public ReportRejectionType SearchError { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user