Merge branch 'search-log'
This commit is contained in:
commit
b52710859c
|
@ -6,9 +6,11 @@ using FizzWare.NBuilder;
|
|||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Model.Notification;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common.AutoMoq;
|
||||
|
||||
|
@ -39,10 +41,16 @@ namespace NzbDrone.Core.Test.JobTests
|
|||
[Test]
|
||||
public void SeasonSearch_partial_season_success()
|
||||
{
|
||||
var resultItems = Builder<SearchHistoryItem>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(e => e.SearchError = ReportRejectionType.None)
|
||||
.With(e => e.Success = true)
|
||||
.Build();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(e => e.SeriesId = 1)
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.SeriesId = 5)
|
||||
.Build();
|
||||
|
||||
var notification = new ProgressNotification("Season Search");
|
||||
|
@ -88,7 +96,7 @@ namespace NzbDrone.Core.Test.JobTests
|
|||
|
||||
Mocker.GetMock<SearchProvider>()
|
||||
.Setup(c => c.PartialSeasonSearch(notification, 1, 1))
|
||||
.Returns(new List<int>{1});
|
||||
.Returns(new List<int>());
|
||||
|
||||
//Act
|
||||
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1);
|
||||
|
|
|
@ -88,42 +88,42 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_be_allowed_if_all_conditions_are_met()
|
||||
{
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeTrue();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.None);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_allowed_if_profile_is_not_allowed()
|
||||
{
|
||||
WithProfileNotAllowed();
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.QualityNotWanted);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_allowed_if_size_is_not_allowed()
|
||||
{
|
||||
WithNotAcceptableSize();
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.Size);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_allowed_if_disk_is_not_upgrade()
|
||||
{
|
||||
WithNoDiskUpgrade();
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_allowed_if_episode_is_already_in_queue()
|
||||
{
|
||||
WithEpisodeAlreadyInQueue();
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.AlreadyInQueue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_allowed_if_report_is_over_retention()
|
||||
{
|
||||
WithOverRetention();
|
||||
spec.IsSatisfiedBy(parseResult).Should().BeFalse();
|
||||
spec.IsSatisfiedBy(parseResult).Should().Be(ReportRejectionType.Retention);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -134,7 +134,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DecisionEngineTests
|
|||
WithProfileNotAllowed();
|
||||
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>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||
.Returns(true);
|
||||
.Returns(ReportRejectionType.None);
|
||||
}
|
||||
|
||||
private void WithQualityNotNeeded()
|
||||
{
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||
.Returns(false);
|
||||
.Returns(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -103,13 +103,13 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
||||
.Returns(true);
|
||||
.Returns(ReportRejectionType.None);
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeTrue();
|
||||
result.Should().Contain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Once());
|
||||
|
@ -133,7 +133,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeFalse();
|
||||
result.Should().NotContain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Exactly(5));
|
||||
|
@ -155,7 +155,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeFalse();
|
||||
result.Should().NotContain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Never());
|
||||
|
@ -175,7 +175,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeFalse();
|
||||
result.Should().NotContain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Never());
|
||||
|
@ -198,7 +198,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeTrue();
|
||||
result.Should().Contain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Once());
|
||||
|
@ -230,7 +230,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeTrue();
|
||||
result.Should().Contain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Exactly(2));
|
||||
|
@ -250,7 +250,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeFalse();
|
||||
result.Should().NotContain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Never());
|
||||
|
@ -270,7 +270,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||
|
||||
//Assert
|
||||
result.Should().BeFalse();
|
||||
result.Should().NotContain(n => n.Success);
|
||||
|
||||
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Never());
|
||||
|
|
|
@ -11,6 +11,7 @@ using NzbDrone.Core.Providers;
|
|||
using NzbDrone.Core.Providers.DecisionEngine;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||
|
@ -73,14 +74,14 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
{
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||
.Returns(true);
|
||||
.Returns(ReportRejectionType.None);
|
||||
}
|
||||
|
||||
private void WithQualityNotNeeded()
|
||||
{
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
|
||||
.Returns(false);
|
||||
.Returns(ReportRejectionType.ExistingQualityIsEqualOrBetter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -102,14 +103,14 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
||||
.Returns(true);
|
||||
.Returns(ReportRejectionType.None);
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//Assert
|
||||
result.Should().HaveCount(1);
|
||||
result.First().Should().Be(1);
|
||||
result.Should().HaveCount(parseResults.Count);
|
||||
result.Should().Contain(s => s.Success);
|
||||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
|
||||
Times.Once());
|
||||
|
@ -135,13 +136,14 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithSuccessfulDownload();
|
||||
|
||||
Mocker.GetMock<AllowedDownloadSpecification>()
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>())).Returns(true);
|
||||
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>())).Returns(ReportRejectionType.None);
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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());
|
||||
|
@ -162,10 +164,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithQualityNotNeeded();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Exactly(5));
|
||||
|
@ -185,10 +188,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithNullSeries();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Never());
|
||||
|
@ -206,10 +210,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithMisMatchedSeries();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Never());
|
||||
|
@ -227,10 +232,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithMatchingSeries();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Never());
|
||||
|
@ -248,10 +254,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithMatchingSeries();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Never());
|
||||
|
@ -274,10 +281,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
WithSuccessfulDownload();
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Once());
|
||||
|
@ -307,10 +315,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
|||
.Returns(true);
|
||||
|
||||
//Act
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, _matchingSeries, 1);
|
||||
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1);
|
||||
|
||||
//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>()),
|
||||
Times.Exactly(2));
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
using System.Data;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migrations
|
||||
{
|
||||
[Migration(20120420)]
|
||||
public class Migration20120420 : NzbDroneMigration
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Database.AddTable("SearchHistory", new[]
|
||||
{
|
||||
new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
|
||||
new Column("SeriesId", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("SeasonNumber", DbType.Int32, ColumnProperty.Null),
|
||||
new Column("EpisodeId", DbType.Int32, ColumnProperty.Null),
|
||||
new Column("SearchTime", DbType.DateTime, ColumnProperty.NotNull),
|
||||
new Column("SuccessfulDownload", DbType.Boolean, ColumnProperty.NotNull)
|
||||
});
|
||||
|
||||
Database.AddTable("SearchHistoryItems", new[]
|
||||
{
|
||||
new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
|
||||
new Column("SearchHistoryId", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("ReportTitle", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("Indexer", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("NzbUrl", DbType.String, ColumnProperty.NotNull),
|
||||
new Column("NzbInfoUrl", DbType.String, ColumnProperty.Null),
|
||||
new Column("Success", DbType.Boolean, ColumnProperty.NotNull),
|
||||
new Column("SearchError", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("Quality", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("Proper", DbType.Boolean, ColumnProperty.NotNull),
|
||||
new Column("Age", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("Language", DbType.Int32, ColumnProperty.NotNull),
|
||||
new Column("Size", DbType.Int64, ColumnProperty.NotNull),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,5 +87,60 @@ namespace NzbDrone.Core
|
|||
return s.Substring(0, i);
|
||||
}
|
||||
|
||||
public static string AddSpacesToEnum(this Enum enumValue)
|
||||
{
|
||||
var text = enumValue.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return "";
|
||||
var newText = new StringBuilder(text.Length * 2);
|
||||
newText.Append(text[0]);
|
||||
for (int i = 1; i < text.Length; i++)
|
||||
{
|
||||
if (char.IsUpper(text[i]) && text[i - 1] != ' ')
|
||||
newText.Append(' ');
|
||||
newText.Append(text[i]);
|
||||
}
|
||||
return newText.ToString();
|
||||
}
|
||||
|
||||
private const Decimal ONE_KILOBYTE = 1024M;
|
||||
private const Decimal ONE_MEGABYTE = ONE_KILOBYTE * 1024M;
|
||||
private const Decimal ONE_GIGABYTE = ONE_MEGABYTE * 1024M;
|
||||
|
||||
public static string ToBestFileSize(this long bytes, int precision = 0)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return "0B";
|
||||
|
||||
decimal size = Convert.ToDecimal(bytes);
|
||||
|
||||
string suffix;
|
||||
|
||||
if (size > ONE_GIGABYTE)
|
||||
{
|
||||
size /= ONE_GIGABYTE;
|
||||
suffix = "GB";
|
||||
}
|
||||
|
||||
else if (size > ONE_MEGABYTE)
|
||||
{
|
||||
size /= ONE_MEGABYTE;
|
||||
suffix = "MB";
|
||||
}
|
||||
|
||||
else if (size > ONE_KILOBYTE)
|
||||
{
|
||||
size /= ONE_KILOBYTE;
|
||||
suffix = "KB";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
suffix = " B";
|
||||
}
|
||||
|
||||
return String.Format("{0:N" + precision + "} {1}", size, suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Helpers
|
||||
{
|
||||
public static class FileSizeFormatHelper
|
||||
{
|
||||
private const Decimal OneKiloByte = 1024M;
|
||||
private const Decimal OneMegaByte = OneKiloByte * 1024M;
|
||||
private const Decimal OneGigaByte = OneMegaByte * 1024M;
|
||||
|
||||
public static string Format(long bytes, int precision = 0)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return "0B";
|
||||
|
||||
decimal size = Convert.ToDecimal(bytes);
|
||||
|
||||
string suffix;
|
||||
|
||||
if (size > OneGigaByte)
|
||||
{
|
||||
size /= OneGigaByte;
|
||||
suffix = "GB";
|
||||
}
|
||||
|
||||
else if (size > OneMegaByte)
|
||||
{
|
||||
size /= OneMegaByte;
|
||||
suffix = "MB";
|
||||
}
|
||||
|
||||
else if (size > OneKiloByte)
|
||||
{
|
||||
size /= OneKiloByte;
|
||||
suffix = "KB";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
suffix = " B";
|
||||
}
|
||||
|
||||
return String.Format("{0:N" + precision + "}{1}", size, suffix);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Jobs
|
|||
try
|
||||
{
|
||||
if (_isMonitoredEpisodeSpecification.IsSatisfiedBy(episodeParseResult) &&
|
||||
_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult) &&
|
||||
_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult) == ReportRejectionType.None &&
|
||||
_upgradeHistorySpecification.IsSatisfiedBy(episodeParseResult))
|
||||
{
|
||||
_downloadProvider.DownloadReport(episodeParseResult);
|
||||
|
|
|
@ -60,15 +60,15 @@ namespace NzbDrone.Core.Jobs
|
|||
//Perform a Partial Season Search
|
||||
var addedSeries = _searchProvider.PartialSeasonSearch(notification, targetId, secondaryTargetId);
|
||||
|
||||
addedSeries.Distinct().ToList().Sort();
|
||||
var episodeNumbers = episodes.Where(w => w.AirDate <= DateTime.Today.AddDays(1)).Select(s => s.EpisodeNumber).ToList();
|
||||
episodeNumbers.Sort();
|
||||
//addedSeries.Distinct().ToList().Sort();
|
||||
//var episodeNumbers = episodes.Where(w => w.AirDate <= DateTime.Today.AddDays(1)).Select(s => s.EpisodeNumber).ToList();
|
||||
//episodeNumbers.Sort();
|
||||
|
||||
if (addedSeries.SequenceEqual(episodeNumbers))
|
||||
return;
|
||||
//if (addedSeries.SequenceEqual(episodeNumbers))
|
||||
// return;
|
||||
|
||||
//Get the list of episodes that weren't downloaded
|
||||
var missingEpisodes = episodeNumbers.Except(addedSeries).ToList();
|
||||
////Get the list of episodes that weren't downloaded
|
||||
//var missingEpisodes = episodeNumbers.Except(addedSeries).ToList();
|
||||
|
||||
//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)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Model
|
||||
{
|
||||
public enum ReportRejectionType
|
||||
{
|
||||
None = 0,
|
||||
WrongSeries = 1,
|
||||
QualityNotWanted = 2,
|
||||
WrongSeason = 3,
|
||||
WrongEpisode = 4,
|
||||
Size = 5,
|
||||
Retention = 6,
|
||||
ExistingQualityIsEqualOrBetter = 7,
|
||||
Cutoff = 8,
|
||||
AlreadyInQueue = 9,
|
||||
DownloadClientFailure = 10,
|
||||
Skipped = 11,
|
||||
Failure = 12,
|
||||
}
|
||||
}
|
|
@ -222,6 +222,7 @@
|
|||
<Compile Include="Datastore\MigrationLogger.cs" />
|
||||
<Compile Include="Datastore\MigrationsHelper.cs" />
|
||||
<Compile Include="Datastore\CustomeMapper.cs" />
|
||||
<Compile Include="Datastore\Migrations\Migration20120420.cs" />
|
||||
<Compile Include="Datastore\Migrations\Migration20120228.cs" />
|
||||
<Compile Include="Datastore\Migrations\Migration20120227.cs" />
|
||||
<Compile Include="Datastore\Migrations\Migration20120220.cs" />
|
||||
|
@ -239,7 +240,6 @@
|
|||
<Compile Include="Datastore\PetaPoco\EpisodeSeasonRelator.cs" />
|
||||
<Compile Include="Fluent.cs" />
|
||||
<Compile Include="Helpers\EpisodeSortingHelper.cs" />
|
||||
<Compile Include="Helpers\FileSizeFormatHelper.cs" />
|
||||
<Compile Include="Helpers\SortHelper.cs" />
|
||||
<Compile Include="Helpers\SabnzbdQueueTimeConverter.cs" />
|
||||
<Compile Include="Jobs\CheckpointJob.cs" />
|
||||
|
@ -277,6 +277,7 @@
|
|||
<Compile Include="Providers\Indexer\NzbIndex.cs" />
|
||||
<Compile Include="Providers\Indexer\FileSharingTalk.cs" />
|
||||
<Compile Include="Providers\Indexer\Wombles.cs" />
|
||||
<Compile Include="Providers\SearchHistoryProvider.cs" />
|
||||
<Compile Include="Providers\SeasonProvider.cs" />
|
||||
<Compile Include="Jobs\RecentBacklogSearchJob.cs" />
|
||||
<Compile Include="Jobs\TrimLogsJob.cs" />
|
||||
|
@ -304,6 +305,9 @@
|
|||
<Compile Include="Providers\AnalyticsProvider.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Repository\Search\SearchHistoryItem.cs" />
|
||||
<Compile Include="Repository\Search\SearchHistory.cs" />
|
||||
<Compile Include="Model\ReportRejectionType.cs" />
|
||||
<Compile Include="Repository\Season.cs" />
|
||||
<Compile Include="Providers\AutoConfigureProvider.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using NLog;
|
||||
using Ninject;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
|
||||
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 (!_upgradeDiskSpecification.IsSatisfiedBy(subject)) return false;
|
||||
if (!_retentionSpecification.IsSatisfiedBy(subject)) return false;
|
||||
if (!_acceptableSizeSpecification.IsSatisfiedBy(subject)) return false;
|
||||
if (_alreadyInQueueSpecification.IsSatisfiedBy(subject)) return false;
|
||||
if (!_qualityAllowedByProfileSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.QualityNotWanted;
|
||||
if (!_upgradeDiskSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.ExistingQualityIsEqualOrBetter;
|
||||
if (!_retentionSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.Retention;
|
||||
if (!_acceptableSizeSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.Size;
|
||||
if (_alreadyInQueueSpecification.IsSatisfiedBy(subject)) return ReportRejectionType.AlreadyInQueue;
|
||||
|
||||
logger.Debug("Episode {0} is needed", subject);
|
||||
return true;
|
||||
return ReportRejectionType.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -124,7 +124,7 @@ namespace NzbDrone.Core.Providers
|
|||
|
||||
foreach (var episode in parseResult.EpisodeNumbers)
|
||||
{
|
||||
episodeString.Add(String.Format("{0}x{1}", parseResult.SeasonNumber, episode));
|
||||
episodeString.Add(String.Format("{0}x{1:00}", parseResult.SeasonNumber, episode));
|
||||
}
|
||||
|
||||
var epNumberString = String.Join("-", episodeString);
|
||||
|
|
|
@ -192,7 +192,6 @@ namespace NzbDrone.Core.Providers.Indexer
|
|||
{
|
||||
parsedEpisode.NzbUrl = NzbDownloadUrl(item);
|
||||
parsedEpisode.Indexer = Name;
|
||||
parsedEpisode.OriginalString = item.Title.Text;
|
||||
result.Add(parsedEpisode);
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +236,7 @@ namespace NzbDrone.Core.Providers.Indexer
|
|||
var title = TitlePreParser(item);
|
||||
|
||||
var episodeParseResult = Parser.ParseTitle(title);
|
||||
episodeParseResult.OriginalString = title;
|
||||
if (episodeParseResult != null) episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PublishDate.Date).Days;
|
||||
|
||||
_logger.Trace("Parsed: {0} from: {1}", episodeParseResult, item.Title.Text);
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using Ninject;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
using PetaPoco;
|
||||
|
||||
namespace NzbDrone.Core.Providers
|
||||
{
|
||||
public class SearchHistoryProvider
|
||||
{
|
||||
private readonly IDatabase _database;
|
||||
private readonly SeriesProvider _seriesProvider;
|
||||
private readonly DownloadProvider _downloadProvider;
|
||||
private readonly EpisodeProvider _episodeProvider;
|
||||
|
||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Inject]
|
||||
public SearchHistoryProvider(IDatabase database, SeriesProvider seriesProvider,
|
||||
DownloadProvider downloadProvider, EpisodeProvider episodeProvider)
|
||||
{
|
||||
_database = database;
|
||||
_seriesProvider = seriesProvider;
|
||||
_downloadProvider = downloadProvider;
|
||||
_episodeProvider = episodeProvider;
|
||||
}
|
||||
|
||||
public SearchHistoryProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Add(SearchHistory searchResult)
|
||||
{
|
||||
logger.Trace("Adding new search result");
|
||||
searchResult.SuccessfulDownload = searchResult.SearchHistoryItems.Any(s => s.Success);
|
||||
var id = Convert.ToInt32(_database.Insert(searchResult));
|
||||
|
||||
searchResult.SearchHistoryItems.ForEach(s => s.SearchHistoryId = id);
|
||||
logger.Trace("Adding search result items");
|
||||
_database.InsertMany(searchResult.SearchHistoryItems);
|
||||
}
|
||||
|
||||
public virtual void Delete(int id)
|
||||
{
|
||||
logger.Trace("Deleting search result items attached to: {0}", id);
|
||||
_database.Execute("DELETE FROM SearchHistoryItems WHERE SearchHistoryId = @0", id);
|
||||
|
||||
logger.Trace("Deleting search result: {0}", id);
|
||||
_database.Delete<SearchHistory>(id);
|
||||
}
|
||||
|
||||
public virtual List<SearchHistory> AllSearchHistory()
|
||||
{
|
||||
var sql = @"SELECT SearchHistory.Id, SearchHistory.SeriesId, SearchHistory.SeasonNumber,
|
||||
SearchHistory.EpisodeId, SearchHistory.SearchTime,
|
||||
Series.Title as SeriesTitle, Series.IsDaily,
|
||||
Episodes.EpisodeNumber, Episodes.SeasonNumber, Episodes.Title as EpisodeTitle,
|
||||
Episodes.AirDate,
|
||||
Count(SearchHistoryItems.Id) as TotalItems,
|
||||
SUM(CASE WHEN SearchHistoryItems.Success = 1 THEN 1 ELSE 0 END) as SuccessfulCount
|
||||
FROM SearchHistory
|
||||
INNER JOIN Series
|
||||
ON Series.SeriesId = SearchHistory.SeriesId
|
||||
LEFT JOIN Episodes
|
||||
ON Episodes.EpisodeId = SearchHistory.EpisodeId
|
||||
INNER JOIN SearchHistoryItems
|
||||
ON SearchHistoryItems.SearchHistoryId = SearchHistory.Id
|
||||
GROUP BY SearchHistory.Id, SearchHistory.SeriesId, SearchHistory.SeasonNumber,
|
||||
SearchHistory.EpisodeId, SearchHistory.SearchTime,
|
||||
Series.Title, Series.IsDaily,
|
||||
Episodes.EpisodeNumber, Episodes.SeasonNumber, Episodes.Title,
|
||||
Episodes.AirDate";
|
||||
|
||||
return _database.Fetch<SearchHistory>(sql);
|
||||
}
|
||||
|
||||
public virtual SearchHistory GetSearchHistory(int id)
|
||||
{
|
||||
var sql = @"SELECT SearchHistory.Id, SearchHistory.SeriesId, SearchHistory.SeasonNumber,
|
||||
SearchHistory.EpisodeId, SearchHistory.SearchTime,
|
||||
Series.Title as SeriesTitle, Series.IsDaily,
|
||||
Episodes.EpisodeNumber, Episodes.SeasonNumber, Episodes.Title as EpisodeTitle,
|
||||
Episodes.AirDate
|
||||
FROM SearchHistory
|
||||
INNER JOIN Series
|
||||
ON Series.SeriesId = SearchHistory.SeriesId
|
||||
LEFT JOIN Episodes
|
||||
ON Episodes.EpisodeId = SearchHistory.EpisodeId
|
||||
WHERE SearchHistory.Id = @0";
|
||||
|
||||
var result = _database.Single<SearchHistory>(sql, id);
|
||||
result.SearchHistoryItems = _database.Fetch<SearchHistoryItem>("WHERE SearchHistoryId = @0", id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual void ForceDownload(int itemId)
|
||||
{
|
||||
var item = _database.Single<SearchHistoryItem>(itemId);
|
||||
var searchResult = _database.Single<SearchHistory>(item.SearchHistoryId);
|
||||
var series = _seriesProvider.GetSeries(searchResult.SeriesId);
|
||||
|
||||
var parseResult = Parser.ParseTitle(item.ReportTitle);
|
||||
parseResult.NzbUrl = item.NzbUrl;
|
||||
parseResult.Series = series;
|
||||
parseResult.Indexer = item.Indexer;
|
||||
var episodes = _episodeProvider.GetEpisodesByParseResult(parseResult);
|
||||
|
||||
_downloadProvider.DownloadReport(parseResult);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ using NzbDrone.Core.Model;
|
|||
using NzbDrone.Core.Model.Notification;
|
||||
using NzbDrone.Core.Providers.DecisionEngine;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
|
||||
namespace NzbDrone.Core.Providers
|
||||
{
|
||||
|
@ -21,13 +22,15 @@ namespace NzbDrone.Core.Providers
|
|||
private readonly SceneMappingProvider _sceneMappingProvider;
|
||||
private readonly UpgradePossibleSpecification _upgradePossibleSpecification;
|
||||
private readonly AllowedDownloadSpecification _allowedDownloadSpecification;
|
||||
private readonly SearchHistoryProvider _searchHistoryProvider;
|
||||
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Inject]
|
||||
public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider,
|
||||
IndexerProvider indexerProvider, SceneMappingProvider sceneMappingProvider,
|
||||
UpgradePossibleSpecification upgradePossibleSpecification, AllowedDownloadSpecification allowedDownloadSpecification)
|
||||
UpgradePossibleSpecification upgradePossibleSpecification, AllowedDownloadSpecification allowedDownloadSpecification,
|
||||
SearchHistoryProvider searchHistoryProvider)
|
||||
{
|
||||
_episodeProvider = episodeProvider;
|
||||
_downloadProvider = downloadProvider;
|
||||
|
@ -36,6 +39,7 @@ namespace NzbDrone.Core.Providers
|
|||
_sceneMappingProvider = sceneMappingProvider;
|
||||
_upgradePossibleSpecification = upgradePossibleSpecification;
|
||||
_allowedDownloadSpecification = allowedDownloadSpecification;
|
||||
_searchHistoryProvider = searchHistoryProvider;
|
||||
}
|
||||
|
||||
public SearchProvider()
|
||||
|
@ -44,13 +48,20 @@ namespace NzbDrone.Core.Providers
|
|||
|
||||
public virtual bool SeasonSearch(ProgressNotification notification, int seriesId, int seasonNumber)
|
||||
{
|
||||
var searchResult = new SearchHistory
|
||||
{
|
||||
SearchTime = DateTime.Now,
|
||||
SeriesId = seriesId,
|
||||
SeasonNumber = seasonNumber
|
||||
};
|
||||
|
||||
var series = _seriesProvider.GetSeries(seriesId);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
Logger.Error("Unable to find an series {0} in database", seriesId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Return false if the series is a daily series (we only support individual episode searching
|
||||
if (series.IsDaily)
|
||||
|
@ -80,19 +91,20 @@ namespace NzbDrone.Core.Providers
|
|||
e => e.EpisodeNumbers = episodeNumbers.ToList()
|
||||
);
|
||||
|
||||
var downloadedEpisodes = ProcessSearchResults(notification, reports, series, seasonNumber);
|
||||
searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, searchResult, series, seasonNumber);
|
||||
_searchHistoryProvider.Add(searchResult);
|
||||
|
||||
downloadedEpisodes.Sort();
|
||||
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));
|
||||
return (searchResult.Successes.Count == episodeNumbers.Count);
|
||||
}
|
||||
|
||||
public virtual List<int> 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 SearchHistory
|
||||
{
|
||||
SearchTime = DateTime.Now,
|
||||
SeriesId = seriesId,
|
||||
SeasonNumber = seasonNumber
|
||||
};
|
||||
|
||||
var series = _seriesProvider.GetSeries(seriesId);
|
||||
|
||||
|
@ -107,19 +119,18 @@ namespace NzbDrone.Core.Providers
|
|||
return new List<int>();
|
||||
|
||||
notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber);
|
||||
|
||||
var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber);
|
||||
|
||||
var reports = PerformSearch(notification, series, seasonNumber, episodes);
|
||||
|
||||
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
||||
|
||||
if (reports.Count == 0)
|
||||
return new List<int>();
|
||||
|
||||
notification.CurrentMessage = "Processing search results";
|
||||
searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, searchResult, series, seasonNumber);
|
||||
|
||||
return ProcessSearchResults(notification, reports, series, seasonNumber);
|
||||
_searchHistoryProvider.Add(searchResult);
|
||||
return searchResult.Successes;
|
||||
}
|
||||
|
||||
public virtual bool EpisodeSearch(ProgressNotification notification, int episodeId)
|
||||
|
@ -136,7 +147,7 @@ namespace NzbDrone.Core.Providers
|
|||
if (!_upgradePossibleSpecification.IsSatisfiedBy(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;
|
||||
}
|
||||
|
||||
|
@ -145,19 +156,39 @@ namespace NzbDrone.Core.Providers
|
|||
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
|
||||
{
|
||||
Logger.Warn("AirDate is not Valid for: {0}", episode);
|
||||
notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode);
|
||||
return false;
|
||||
}
|
||||
|
||||
var searchResult = new SearchHistory
|
||||
{
|
||||
SearchTime = DateTime.Now,
|
||||
SeriesId = episode.Series.SeriesId
|
||||
};
|
||||
|
||||
var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List<Episode> { episode });
|
||||
|
||||
Logger.Debug("Finished searching all indexers. Total {0}", reports.Count);
|
||||
notification.CurrentMessage = "Processing search results";
|
||||
|
||||
if (!episode.Series.IsDaily && ProcessSearchResults(notification, reports, episode.Series, episode.SeasonNumber, episode.EpisodeNumber).Count == 1)
|
||||
return true;
|
||||
if (episode.Series.IsDaily)
|
||||
{
|
||||
searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, episode.Series, episode.AirDate.Value);
|
||||
_searchHistoryProvider.Add(searchResult);
|
||||
|
||||
if (episode.Series.IsDaily && ProcessSearchResults(notification, reports, episode.Series, episode.AirDate.Value))
|
||||
if (searchResult.SearchHistoryItems.Any(r => r.Success))
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
searchResult.EpisodeId = episodeId;
|
||||
searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, searchResult, episode.Series, episode.SeasonNumber, episode.EpisodeNumber);
|
||||
_searchHistoryProvider.Add(searchResult);
|
||||
|
||||
if (searchResult.SearchHistoryItems.Any(r => r.Success))
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger.Warn("Unable to find {0} in any of indexers.", episode);
|
||||
|
||||
|
@ -170,7 +201,6 @@ namespace NzbDrone.Core.Providers
|
|||
notification.CurrentMessage = String.Format("Sorry, couldn't find you {0} in any of indexers.", episode);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -227,9 +257,10 @@ namespace NzbDrone.Core.Providers
|
|||
return reports;
|
||||
}
|
||||
|
||||
public List<int> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, int seasonNumber, int? episodeNumber = null)
|
||||
public List<SearchHistoryItem> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, SearchHistory searchResult, Series series, int seasonNumber, int? episodeNumber = null)
|
||||
{
|
||||
var successes = new List<int>();
|
||||
var items = new List<SearchHistoryItem>();
|
||||
|
||||
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality).ThenBy(c => c.Age))
|
||||
{
|
||||
|
@ -237,6 +268,20 @@ namespace NzbDrone.Core.Providers
|
|||
{
|
||||
Logger.Trace("Analysing report " + episodeParseResult);
|
||||
|
||||
var item = new SearchHistoryItem
|
||||
{
|
||||
ReportTitle = episodeParseResult.OriginalString,
|
||||
NzbUrl = episodeParseResult.NzbUrl,
|
||||
Indexer = episodeParseResult.Indexer,
|
||||
Quality = episodeParseResult.Quality.QualityType,
|
||||
Proper = episodeParseResult.Quality.Proper,
|
||||
Size = episodeParseResult.Size,
|
||||
Age = episodeParseResult.Age,
|
||||
Language = episodeParseResult.Language
|
||||
};
|
||||
|
||||
items.Add(item);
|
||||
|
||||
//Get the matching series
|
||||
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
|
||||
|
||||
|
@ -244,6 +289,7 @@ namespace NzbDrone.Core.Providers
|
|||
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
||||
{
|
||||
Logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle);
|
||||
item.SearchError = ReportRejectionType.WrongSeries;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -251,6 +297,7 @@ namespace NzbDrone.Core.Providers
|
|||
if (episodeParseResult.SeasonNumber != seasonNumber)
|
||||
{
|
||||
Logger.Trace("Season number does not match searched season number, skipping.");
|
||||
item.SearchError = ReportRejectionType.WrongSeason;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -258,6 +305,7 @@ namespace NzbDrone.Core.Providers
|
|||
if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value))
|
||||
{
|
||||
Logger.Trace("Searched episode number is not contained in post, skipping.");
|
||||
item.SearchError = ReportRejectionType.WrongEpisode;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -265,10 +313,12 @@ namespace NzbDrone.Core.Providers
|
|||
if (successes.Intersect(episodeParseResult.EpisodeNumbers).Any())
|
||||
{
|
||||
Logger.Trace("Episode has already been downloaded in this search, skipping.");
|
||||
item.SearchError = ReportRejectionType.Skipped;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult))
|
||||
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
|
||||
if (item.SearchError == ReportRejectionType.None)
|
||||
{
|
||||
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
||||
try
|
||||
|
@ -279,12 +329,18 @@ namespace NzbDrone.Core.Providers
|
|||
|
||||
//Add the list of episode numbers from this release
|
||||
successes.AddRange(episodeParseResult.EpisodeNumbers);
|
||||
item.Success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||
}
|
||||
}
|
||||
catch (Exception 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);
|
||||
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,15 +350,38 @@ namespace NzbDrone.Core.Providers
|
|||
}
|
||||
}
|
||||
|
||||
return successes;
|
||||
return items;
|
||||
}
|
||||
|
||||
public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, DateTime airDate)
|
||||
public List<SearchHistoryItem> ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, DateTime airDate)
|
||||
{
|
||||
var items = new List<SearchHistoryItem>();
|
||||
var skip = false;
|
||||
|
||||
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality))
|
||||
{
|
||||
try
|
||||
{
|
||||
var item = new SearchHistoryItem
|
||||
{
|
||||
ReportTitle = episodeParseResult.OriginalString,
|
||||
NzbUrl = episodeParseResult.NzbUrl,
|
||||
Indexer = episodeParseResult.Indexer,
|
||||
Quality = episodeParseResult.Quality.QualityType,
|
||||
Proper = episodeParseResult.Quality.Proper,
|
||||
Size = episodeParseResult.Size,
|
||||
Age = episodeParseResult.Age,
|
||||
Language = episodeParseResult.Language
|
||||
};
|
||||
|
||||
items.Add(item);
|
||||
|
||||
if (skip)
|
||||
{
|
||||
item.SearchError = ReportRejectionType.Skipped;
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.Trace("Analysing report " + episodeParseResult);
|
||||
|
||||
//Get the matching series
|
||||
|
@ -310,13 +389,20 @@ namespace NzbDrone.Core.Providers
|
|||
|
||||
//If series is null or doesn't match the series we're looking for return
|
||||
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
||||
{
|
||||
item.SearchError = ReportRejectionType.WrongSeries;
|
||||
continue;
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
item.SearchError = ReportRejectionType.WrongEpisode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult))
|
||||
item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);
|
||||
if (item.SearchError == ReportRejectionType.None)
|
||||
{
|
||||
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
||||
try
|
||||
|
@ -327,13 +413,19 @@ namespace NzbDrone.Core.Providers
|
|||
String.Format("{0} - {1} {2} Added to download queue",
|
||||
episodeParseResult.Series.Title, episodeParseResult.AirDate.Value.ToShortDateString(), episodeParseResult.Quality);
|
||||
|
||||
return true;
|
||||
item.Success = true;
|
||||
skip = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||
}
|
||||
}
|
||||
catch (Exception 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);
|
||||
item.SearchError = ReportRejectionType.DownloadClientFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +434,8 @@ namespace NzbDrone.Core.Providers
|
|||
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)
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
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("SearchHistory")]
|
||||
public class SearchHistory
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int SeriesId { get; set; }
|
||||
public int? SeasonNumber { get; set; }
|
||||
public int? EpisodeId { get; set; }
|
||||
public DateTime SearchTime { get; set; }
|
||||
public bool SuccessfulDownload { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public List<SearchHistoryItem> SearchHistoryItems { get; set; }
|
||||
|
||||
[Ignore]
|
||||
public List<int> Successes { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public string SeriesTitle { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public bool IsDaily { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public int? EpisodeNumber { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public DateTime AirDate { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public int TotalItems { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public int SuccessfulCount { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
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("SearchHistoryItems")]
|
||||
public class SearchHistoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int SearchHistoryId { get; set; }
|
||||
public string ReportTitle { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string NzbUrl { get; set; }
|
||||
public string NzbInfoUrl { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public ReportRejectionType SearchError { get; set; }
|
||||
public QualityTypes Quality { get; set; }
|
||||
public bool Proper { get; set; }
|
||||
public int Age { get; set; }
|
||||
public LanguageType Language { get; set; }
|
||||
public long Size { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} - {1} - {2}", ReportTitle, Quality, SearchError);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Linq.Dynamic;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using DataTables.Mvc.Core;
|
||||
using DataTables.Mvc.Core.Models;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
|
@ -17,7 +18,8 @@ namespace NzbDrone.Web.Controllers
|
|||
private readonly EnvironmentProvider _environmentProvider;
|
||||
private readonly DiskProvider _diskProvider;
|
||||
|
||||
public LogController(LogProvider logProvider, EnvironmentProvider environmentProvider, DiskProvider diskProvider)
|
||||
public LogController(LogProvider logProvider, EnvironmentProvider environmentProvider,
|
||||
DiskProvider diskProvider)
|
||||
{
|
||||
_logProvider = logProvider;
|
||||
_environmentProvider = environmentProvider;
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using NzbDrone.Core;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
using NzbDrone.Web.Models;
|
||||
|
||||
namespace NzbDrone.Web.Controllers
|
||||
{
|
||||
public class SearchHistoryController : Controller
|
||||
{
|
||||
private readonly SearchHistoryProvider _searchHistoryProvider;
|
||||
|
||||
public SearchHistoryController(SearchHistoryProvider searchHistoryProvider)
|
||||
{
|
||||
_searchHistoryProvider = searchHistoryProvider;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
var results = _searchHistoryProvider.AllSearchHistory();
|
||||
|
||||
var model = results.Select(s => new SearchHistoryModel
|
||||
{
|
||||
Id = s.Id,
|
||||
SearchTime = s.SearchTime.ToString(),
|
||||
DisplayName = GetDisplayName(s),
|
||||
ReportCount = s.TotalItems,
|
||||
Successful = s.SuccessfulCount > 0
|
||||
});
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult Details(int searchId)
|
||||
{
|
||||
var searchResult = _searchHistoryProvider.GetSearchHistory(searchId);
|
||||
var model = new SearchDetailsModel
|
||||
{
|
||||
Id = searchResult.Id,
|
||||
DisplayName = GetDisplayName(searchResult),
|
||||
SearchHistoryItems =
|
||||
searchResult.SearchHistoryItems.Select(s => new SearchItemModel
|
||||
{
|
||||
Id = s.Id,
|
||||
ReportTitle = s.ReportTitle,
|
||||
Indexer = s.Indexer,
|
||||
NzbUrl = s.NzbUrl,
|
||||
NzbInfoUrl = s.NzbInfoUrl,
|
||||
Success = s.Success,
|
||||
SearchError = s.SearchError.AddSpacesToEnum().Replace("None", "Grabbed"),
|
||||
Quality = s.Quality.ToString(),
|
||||
QualityInt = (int)s.Quality,
|
||||
Proper = s.Proper,
|
||||
Age = s.Age,
|
||||
Size = s.Size.ToBestFileSize(1),
|
||||
Language = s.Language.ToString()
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public JsonResult ForceDownload(int id)
|
||||
{
|
||||
_searchHistoryProvider.ForceDownload(id);
|
||||
|
||||
return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
|
||||
}
|
||||
|
||||
public string GetDisplayName(SearchHistory searchResult)
|
||||
{
|
||||
if (!searchResult.EpisodeNumber.HasValue)
|
||||
{
|
||||
return String.Format("{0} - Season {1}", searchResult.SeriesTitle, searchResult.SeasonNumber);
|
||||
}
|
||||
|
||||
string episodeString;
|
||||
|
||||
if (searchResult.IsDaily)
|
||||
episodeString = searchResult.AirDate.ToShortDateString().Replace('/', '-');
|
||||
|
||||
else
|
||||
episodeString = String.Format("S{0:00}E{1:00}", searchResult.SeasonNumber,
|
||||
searchResult.EpisodeNumber);
|
||||
|
||||
return String.Format("{0} - {1} - {2}", searchResult.SeriesTitle, episodeString, searchResult.EpisodeTitle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Web.Mvc;
|
||||
using System.Web.Script.Serialization;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core;
|
||||
using NzbDrone.Core.Helpers;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Providers;
|
||||
|
@ -129,7 +130,7 @@ namespace NzbDrone.Web.Controllers
|
|||
foreach (var fileInfo in files)
|
||||
{
|
||||
fileResult += String.Format("<div><div style=\"width: 600px; display: inline-block;\">{0}</div><div style=\"display: inline-block;\">{1}</div></div>", fileInfo.Name,
|
||||
FileSizeFormatHelper.Format(fileInfo.Length, 1));
|
||||
fileInfo.Length.ToBestFileSize(1));
|
||||
}
|
||||
|
||||
model.Files = fileResult;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Repository.Search;
|
||||
|
||||
namespace NzbDrone.Web.Models
|
||||
{
|
||||
public class SearchDetailsModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public List<SearchItemModel> SearchHistoryItems { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Web.Models
|
||||
{
|
||||
public class SearchHistoryModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string SearchTime { get; set; }
|
||||
public int ReportCount { get; set; }
|
||||
public bool Successful { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Repository.Quality;
|
||||
|
||||
namespace NzbDrone.Web.Models
|
||||
{
|
||||
public class SearchItemModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string ReportTitle { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public string NzbUrl { get; set; }
|
||||
public string NzbInfoUrl { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public string SearchError { get; set; }
|
||||
public string Quality { get; set; }
|
||||
public int QualityInt { get; set; }
|
||||
public bool Proper { get; set; }
|
||||
public int Age { get; set; }
|
||||
public string Language { get; set; }
|
||||
public string Size { get; set; }
|
||||
public string Details { get; set; }
|
||||
}
|
||||
}
|
|
@ -52,7 +52,8 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="DataTables.Mvc.Core">
|
||||
<HintPath>..\packages\DataTables.Mvc.0.1.0.54\lib\DataTables.Mvc.Core.dll</HintPath>
|
||||
<HintPath>..\packages\DataTables.Mvc.0.1.0.67\lib\DataTables.Mvc.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Dynamic">
|
||||
<HintPath>..\packages\DynamicQuery.1.0\lib\35\Dynamic.dll</HintPath>
|
||||
|
@ -142,6 +143,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App_Start\DataTablesMvc.cs" />
|
||||
<Compile Include="Controllers\SearchHistoryController.cs" />
|
||||
<Compile Include="Helpers\Validation\RequiredIfAnyAttribute.cs" />
|
||||
<Compile Include="Helpers\Validation\RequiredIfAttribute.cs" />
|
||||
<Content Include="Content\DataTables-1.9.0\media\css\jquery.dataTables.css" />
|
||||
|
@ -235,9 +237,12 @@
|
|||
<Compile Include="Helpers\DescriptionExtension.cs" />
|
||||
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
|
||||
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
|
||||
<Compile Include="Models\SearchDetailsModel.cs" />
|
||||
<Compile Include="Models\JobModel.cs" />
|
||||
<Compile Include="Models\LogModel.cs" />
|
||||
<Compile Include="Models\PostUpgradeModel.cs" />
|
||||
<Compile Include="Models\SearchItemModel.cs" />
|
||||
<Compile Include="Models\SearchHistoryModel.cs" />
|
||||
<Compile Include="Models\UpcomingEpisodesModel.cs" />
|
||||
<Compile Include="Models\SeasonModel.cs" />
|
||||
<Compile Include="Models\SeriesDetailsModel.cs" />
|
||||
|
@ -520,6 +525,12 @@
|
|||
<Content Include="Views\Shared\NoSeriesBanner.cshtml" />
|
||||
<Content Include="Views\Update\Post.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\SearchHistory\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\SearchHistory\Details.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
jqXHR.error(function (xhr, textStatus, thrownError) {
|
||||
//ignore notification errors.
|
||||
if (this.url.indexOf("/notification/Comet") === 0 || this.url.indexOf("/Health/Index") === 0)
|
||||
if (this.url.indexOf("/notification/Comet") === 0 || this.url.indexOf("/Health/Index") === 0 || this.url.indexOf("/signalr") === 0)
|
||||
return;
|
||||
|
||||
alert("Status: " + textStatus + ", Error: " + thrownError);
|
||||
|
|
|
@ -92,5 +92,5 @@ $(function () {
|
|||
};
|
||||
|
||||
// Start the connection
|
||||
$.connection.hub.start();
|
||||
$.connection.hub.start({ transport: 'longPolling' });
|
||||
});
|
|
@ -4,6 +4,7 @@
|
|||
<ul class="sub-menu">
|
||||
<li>@Ajax.ActionLink("Trim History", "Trim", "History", null, new AjaxOptions{ OnSuccess = "reloadGrid", Confirm = "Delete history items older than 30 days?"}, new { Title = "Delete history items older than 30 days" })</li>
|
||||
<li>@Ajax.ActionLink("Purge History", "Purge", "History", null, new AjaxOptions{ OnSuccess = "reloadGrid", Confirm = "Purge all history items?" }, new { Title = "Delete all history items" })</li>
|
||||
<li>@Html.ActionLink("Search Hisotry", "Index", "SearchHistory", null, new { Title = "Review recent searches" })</li>
|
||||
</ul>
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
@using DataTables.Mvc.Core
|
||||
@using DataTables.Mvc.Core.Enum
|
||||
@model NzbDrone.Web.Models.SearchDetailsModel
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Search Details";
|
||||
}
|
||||
|
||||
<h2>@Model.DisplayName</h2>
|
||||
|
||||
@Html.GridHtml("searchDetailsGrid")
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
@(Html.GridScriptFor(m => m.SearchHistoryItems, "#searchDetailsGrid")
|
||||
.PageLength(20)
|
||||
.ChangePageLength(false)
|
||||
.AddColumn(new Column().Image("/Content/Images/Indexers/{Indexer}.png", new { alt = "{Indexer}", title = "{Indexer}" }, "{Indexer}").Sortable(false).Title("").Width("20px"))
|
||||
.AddColumn(new Column().DataProperty("ReportTitle").Title("Report Title"))
|
||||
.AddColumn(new Column().DataProperty("Success").Title("Successful").Width("120px"))
|
||||
.AddColumn(new Column().DisplayAndSort("Quality", "QualityInt").Title("Quality").Width("80px"))
|
||||
.AddColumn(new Column().DataProperty("SearchError").Title("Error"))
|
||||
.AddColumn(new Column().DataProperty("return actionColumn(source, type, val);", true))
|
||||
.AddColumn(new Column().DataProperty("Details").RenderFunction("return getDetails(row, val);").Visible(false))
|
||||
.AddSorting(3, SortDirection.Desc))
|
||||
|
||||
<script type="text/javascript">
|
||||
function getDetails(row, val) {
|
||||
var result = "<a href=\"" + row.aData["NzbInfoUrl"] + "\">Nzb Info</a><br/>" +
|
||||
"<b>Proper: </b>" + row.aData["Proper"] + " <br/>" +
|
||||
"<b>Age: </b>" + row.aData["Age"] + " days<br/>" +
|
||||
"<b>Size: </b>" + row.aData["Size"] + " <br/>" +
|
||||
"<b>Language: </b>" + row.aData["Language"] + " <br/>";
|
||||
return result;
|
||||
}
|
||||
|
||||
function actionColumn(source, type, val) {
|
||||
if (type === 'display' || type === 'filter') {
|
||||
return '<a href="/SearchHistory/ForceDownload/' + source["Id"] + '" data-ajax="true" data-ajax-confirm="Are you sure?"><img src="/Content/Images/Plus.png" alt="Force" title="Force" class="gridAction"/></a>';
|
||||
}
|
||||
// 'sort' and 'type' both just use the raw data
|
||||
return '';
|
||||
}
|
||||
</script>
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
@using DataTables.Mvc.Core
|
||||
@model IEnumerable<NzbDrone.Web.Models.SearchHistoryModel>
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Search Results";
|
||||
}
|
||||
|
||||
@Html.GridHtml("searchResultsGrid", "dataTablesGrid no-details")
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
@(
|
||||
Html.GridScriptForModel("#searchResultsGrid")
|
||||
.PageLength(20)
|
||||
.ChangePageLength(false)
|
||||
.AddColumn(new Column().DataProperty("DisplayName").Link("SearchHistory/Details?searchId={Id}", "{DisplayName}", null).Title("Name"))
|
||||
.AddColumn(new Column().DataProperty("SearchTime").Title("Time").Width("170px"))
|
||||
.AddColumn(new Column().DataProperty("ReportCount").Title("Reports Found").Width("140px"))
|
||||
.AddColumn(new Column().DataProperty("Successful").Title("Successful").Width("110px"))
|
||||
.AddSorting(1)
|
||||
)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="DataTables.Mvc" version="0.1.0.54" />
|
||||
<package id="DataTables.Mvc" version="0.1.0.67" />
|
||||
<package id="DynamicQuery" version="1.0" />
|
||||
<package id="EntityFramework" version="4.3.0" />
|
||||
<package id="EntityFramework.SqlServerCompact" version="4.1.8482.2" />
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,17 @@
|
|||
using DataTables.Mvc.Core.Helpers;
|
||||
using DataTables.Mvc.Core.Models;
|
||||
using System.Web.Mvc;
|
||||
|
||||
[assembly: WebActivator.PreApplicationStartMethod(typeof($rootnamespace$.App_Start.DataTablesModelBinderActivator), "Start")]
|
||||
|
||||
namespace $rootnamespace$.App_Start
|
||||
{
|
||||
public static class DataTablesModelBinderActivator
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
if (!ModelBinders.Binders.ContainsKey(typeof(DataTablesParams)))
|
||||
ModelBinders.Binders.Add(typeof(DataTablesParams), new DataTablesModelBinder());
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
$path = [System.IO.Path]
|
||||
$appstart = $path::Combine($path::GetDirectoryName($project.FileName), "App_Start\DataTablesMvc.cs")
|
||||
$DTE.ItemOperations.OpenFile($appstart)
|
Loading…
Reference in New Issue