Episode searching now stores the results of the tests.

pull/4/head
Mark McDowall 13 years ago
parent b9e3d1a921
commit c7f8f57f77

@ -6,9 +6,11 @@ using FizzWare.NBuilder;
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 @@ namespace NzbDrone.Core.Test.JobTests
[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 @@ namespace NzbDrone.Core.Test.JobTests
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 @@ namespace NzbDrone.Core.Test.JobTests
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 @@ namespace NzbDrone.Core.Test.JobTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
[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 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
WithProfileNotAllowed(); WithProfileNotAllowed();
WithOverRetention(); WithOverRetention();
spec.IsSatisfiedBy(parseResult).Should().BeFalse(); spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.QualityNotWanted);
} }
} }
} }

@ -77,14 +77,14 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{ {
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{ {
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
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 @@ namespace NzbDrone.Core.Jobs
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 @@ namespace NzbDrone.Core.Jobs
//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)

@ -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 @@ namespace NzbDrone.Core.Providers.DecisionEngine
{ {
} }
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;
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
_sceneMappingProvider = sceneMappingProvider; _sceneMappingProvider = sceneMappingProvider;
_upgradePossibleSpecification = upgradePossibleSpecification; _upgradePossibleSpecification = upgradePossibleSpecification;
_allowedDownloadSpecification = allowedDownloadSpecification; _allowedDownloadSpecification = allowedDownloadSpecification;
_searchResultProvider = searchResultProvider;
} }
public SearchProvider() public SearchProvider()
@ -44,13 +48,20 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
{ {
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
//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 @@ namespace NzbDrone.Core.Providers
} }
} }
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 @@ namespace NzbDrone.Core.Providers
//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 @@ namespace NzbDrone.Core.Providers
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 @@ namespace NzbDrone.Core.Providers
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)

@ -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;
}
}
}

@ -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; }
}
}

@ -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…
Cancel
Save