Merge branch 'markus' into kay.one
This commit is contained in:
commit
ed9460da66
|
@ -102,7 +102,10 @@
|
||||||
<Compile Include="JobTests\BacklogSearchJobTest.cs" />
|
<Compile Include="JobTests\BacklogSearchJobTest.cs" />
|
||||||
<Compile Include="JobTests\BannerDownloadJobTest.cs" />
|
<Compile Include="JobTests\BannerDownloadJobTest.cs" />
|
||||||
<Compile Include="JobTests\RecentBacklogSearchJobTest.cs" />
|
<Compile Include="JobTests\RecentBacklogSearchJobTest.cs" />
|
||||||
|
<Compile Include="ProviderTests\ReferenceDataProviderTest.cs" />
|
||||||
<Compile Include="ProviderTests\NotificationProviderTests\NotificationProviderFixture.cs" />
|
<Compile Include="ProviderTests\NotificationProviderTests\NotificationProviderFixture.cs" />
|
||||||
|
<Compile Include="ProviderTests\SearchProviderTests\ProcessDailySearchResultsFixture.cs" />
|
||||||
|
<Compile Include="ProviderTests\SearchProviderTests\SearchFixture.cs" />
|
||||||
<Compile Include="ProviderTests\SearchProviderTests\PerformSearchFixture.cs" />
|
<Compile Include="ProviderTests\SearchProviderTests\PerformSearchFixture.cs" />
|
||||||
<Compile Include="ProviderTests\SearchProviderTests\ProcessSearchResultsFixture.cs" />
|
<Compile Include="ProviderTests\SearchProviderTests\ProcessSearchResultsFixture.cs" />
|
||||||
<Compile Include="ProviderTests\NewznabProviderTest.cs" />
|
<Compile Include="ProviderTests\NewznabProviderTest.cs" />
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Providers;
|
||||||
|
using NzbDrone.Core.Providers.Core;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
using NzbDrone.Core.Repository.Quality;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
using NzbDrone.Test.Common.AutoMoq;
|
||||||
|
using PetaPoco;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ProviderTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
public class ReferenceDataProviderTest : CoreTest
|
||||||
|
{
|
||||||
|
private string validSeriesIds = String.Format("1{0}2{0}3{0}4{0}5", Environment.NewLine);
|
||||||
|
private string invalidSeriesIds = String.Format("1{0}2{0}NaN{0}4{0}5", Environment.NewLine);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetDailySeriesIds_should_return_list_of_int_when_all_are_valid()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<ReferenceDataProvider>().GetDailySeriesIds();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetDailySeriesIds_should_return_list_of_int_when_any_are_valid()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(invalidSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<ReferenceDataProvider>().GetDailySeriesIds();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetDailySeriesIds_should_return_empty_list_of_int_when_server_is_unavailable()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Throws(new Exception());
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<ReferenceDataProvider>().GetDailySeriesIds();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(0);
|
||||||
|
ExceptionVerification.ExcpectedWarns(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsDailySeries_should_return_true()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<ReferenceDataProvider>().IsSeriesDaily(1);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsDailySeries_should_return_false()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<ReferenceDataProvider>().IsSeriesDaily(10);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateDailySeries_should_update_series_that_match_daily_series_list()
|
||||||
|
{
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
var fakeSeries = Builder<Series>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(s => s.IsDaily = false)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Db.InsertMany(fakeSeries);
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
Mocker.Resolve<ReferenceDataProvider>().UpdateDailySeries();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
var result = Db.Fetch<Series>();
|
||||||
|
|
||||||
|
result.Where(s => s.IsDaily).Should().HaveCount(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateDailySeries_should_update_series_should_skip_series_that_dont_match()
|
||||||
|
{
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
var fakeSeries = Builder<Series>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(s => s.IsDaily = false)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.SeriesId = 10)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.SeriesId = 11)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.SeriesId = 12)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Db.InsertMany(fakeSeries);
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
Mocker.Resolve<ReferenceDataProvider>().UpdateDailySeries();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
var result = Db.Fetch<Series>();
|
||||||
|
|
||||||
|
result.Where(s => !s.IsDaily).Should().HaveCount(3);
|
||||||
|
result.Where(s => s.IsDaily).Should().HaveCount(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateDailySeries_should_update_series_should_not_overwrite_existing_isDaily()
|
||||||
|
{
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
var fakeSeries = Builder<Series>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(s => s.IsDaily = false)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.SeriesId = 10)
|
||||||
|
.With(s => s.IsDaily = true)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.SeriesId = 11)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.SeriesId = 12)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Db.InsertMany(fakeSeries);
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
Mocker.GetMock<HttpProvider>().Setup(s => s.DownloadString("http://www.nzbdrone.com/DailySeries.csv"))
|
||||||
|
.Returns(validSeriesIds);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
Mocker.Resolve<ReferenceDataProvider>().UpdateDailySeries();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
var result = Db.Fetch<Series>();
|
||||||
|
|
||||||
|
result.Where(s => s.IsDaily).Should().HaveCount(3);
|
||||||
|
result.Where(s => !s.IsDaily).Should().HaveCount(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,8 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
_episodeIndexer1 = new Mock<IndexerBase>();
|
_episodeIndexer1 = new Mock<IndexerBase>();
|
||||||
_episodeIndexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
_episodeIndexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
.Returns(parseResults);
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer1.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
|
||||||
|
.Returns(parseResults);
|
||||||
_episodeIndexer1.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
_episodeIndexer1.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
||||||
.Returns(parseResults);
|
.Returns(parseResults);
|
||||||
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
@ -65,6 +67,8 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
_episodeIndexer2 = new Mock<IndexerBase>();
|
_episodeIndexer2 = new Mock<IndexerBase>();
|
||||||
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
.Returns(parseResults);
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer2.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
|
||||||
|
.Returns(parseResults);
|
||||||
_episodeIndexer2.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
_episodeIndexer2.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
||||||
.Returns(parseResults);
|
.Returns(parseResults);
|
||||||
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
@ -123,6 +127,15 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
, times);
|
, times);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchDailyEpisode(Times times)
|
||||||
|
{
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchDailyEpisode(_series.Title, It.IsAny<DateTime>())
|
||||||
|
, times);
|
||||||
|
|
||||||
|
_episodeIndexer2.Verify(v => v.FetchDailyEpisode(_series.Title, It.IsAny<DateTime>())
|
||||||
|
, times);
|
||||||
|
}
|
||||||
|
|
||||||
private void VerifyFetchEpisodeWithSceneName(Times times)
|
private void VerifyFetchEpisodeWithSceneName(Times times)
|
||||||
{
|
{
|
||||||
_episodeIndexer1.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
|
_episodeIndexer1.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
@ -210,6 +223,21 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
VerifyFetchEpisode(Times.Once());
|
VerifyFetchEpisode(Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PerformSearch_for_daily_episode_should_call_FetchEpisode()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
_series.IsDaily = true;
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(PARSE_RESULT_COUNT * 2);
|
||||||
|
|
||||||
|
VerifyFetchDailyEpisode(Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void PerformSearch_for_partial_season_should_call_FetchPartialSeason()
|
public void PerformSearch_for_partial_season_should_call_FetchPartialSeason()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Model.Notification;
|
||||||
|
using NzbDrone.Core.Providers;
|
||||||
|
using NzbDrone.Core.Providers.Indexer;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
using NzbDrone.Core.Repository.Quality;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
using NzbDrone.Test.Common.AutoMoq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
public class ProcessDailySearchResultsFixture : CoreTest
|
||||||
|
{
|
||||||
|
private Series _matchingSeries = null;
|
||||||
|
private Series _mismatchedSeries = null;
|
||||||
|
private Series _nullSeries = null;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void setup()
|
||||||
|
{
|
||||||
|
_matchingSeries = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.SeriesId = 79488)
|
||||||
|
.With(s => s.Title = "30 Rock")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_mismatchedSeries = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.SeriesId = 12345)
|
||||||
|
.With(s => s.Title = "Not 30 Rock")
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithMatchingSeries()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<SeriesProvider>()
|
||||||
|
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_matchingSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithMisMatchedSeries()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<SeriesProvider>()
|
||||||
|
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_mismatchedSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithNullSeries()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<SeriesProvider>()
|
||||||
|
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_nullSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithSuccessfulDownload()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<DownloadProvider>()
|
||||||
|
.Setup(s => s.DownloadReport(It.IsAny<EpisodeParseResult>()))
|
||||||
|
.Returns(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithFailingDownload()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<DownloadProvider>()
|
||||||
|
.Setup(s => s.DownloadReport(It.IsAny<EpisodeParseResult>()))
|
||||||
|
.Returns(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithQualityNeeded()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<InventoryProvider>()
|
||||||
|
.Setup(s => s.IsQualityNeeded(It.IsAny<EpisodeParseResult>()))
|
||||||
|
.Returns(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithQualityNotNeeded()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<InventoryProvider>()
|
||||||
|
.Setup(s => s.IsQualityNeeded(It.IsAny<EpisodeParseResult>()))
|
||||||
|
.Returns(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_higher_quality_should_be_called_first()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(c => c.AirDate = DateTime.Today)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.DVD, true))
|
||||||
|
.Random(1)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.Bluray1080p, true))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
WithSuccessfulDownload();
|
||||||
|
|
||||||
|
Mocker.GetMock<InventoryProvider>()
|
||||||
|
.Setup(s => s.IsQualityNeeded(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.Bluray1080p)))
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeTrue();
|
||||||
|
|
||||||
|
Mocker.GetMock<InventoryProvider>().Verify(c => c.IsQualityNeeded(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Once());
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_when_quality_is_not_needed_should_check_the_rest()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(c => c.AirDate = DateTime.Today)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.DVD, true))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
WithQualityNotNeeded();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
|
||||||
|
Mocker.GetMock<InventoryProvider>().Verify(c => c.IsQualityNeeded(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Exactly(5));
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_skip_if_series_is_null()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithNullSeries();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_skip_if_series_is_mismatched()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMisMatchedSeries();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_return_after_successful_download()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.DVD, true))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
WithQualityNeeded();
|
||||||
|
WithSuccessfulDownload();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeTrue();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_try_next_if_download_fails()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.DVD, true))
|
||||||
|
.TheLast(1)
|
||||||
|
.With(c => c.Quality = new Quality(QualityTypes.SDTV, true))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
WithQualityNeeded();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>()
|
||||||
|
.Setup(s => s.DownloadReport(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.DVD)))
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>()
|
||||||
|
.Setup(s => s.DownloadReport(It.Is<EpisodeParseResult>(d => d.Quality.QualityType == QualityTypes.SDTV)))
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeTrue();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Exactly(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_skip_if_parseResult_does_not_have_airdate()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = null)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void processSearchResults_should_skip_if_parseResult_airdate_does_not_match()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(e => e.AirDate = DateTime.Today.AddDays(10))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
WithMatchingSeries();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
|
||||||
|
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
|
||||||
|
Times.Never());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,206 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Providers;
|
||||||
|
using NzbDrone.Core.Providers.Indexer;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
|
||||||
|
{
|
||||||
|
public class SearchFixture : CoreTest
|
||||||
|
{
|
||||||
|
private const string SCENE_NAME = "Scene Name";
|
||||||
|
private const int SEASON_NUMBER = 5;
|
||||||
|
private const int PARSE_RESULT_COUNT = 10;
|
||||||
|
|
||||||
|
private Mock<IndexerBase> _episodeIndexer1;
|
||||||
|
private Mock<IndexerBase> _episodeIndexer2;
|
||||||
|
private Mock<IndexerBase> _brokenIndexer;
|
||||||
|
private Mock<IndexerBase> _nullIndexer;
|
||||||
|
|
||||||
|
private List<IndexerBase> _indexers;
|
||||||
|
|
||||||
|
private Series _series;
|
||||||
|
private IList<Episode> _episodes;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(PARSE_RESULT_COUNT)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_series = Builder<Series>.CreateNew()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_episodes = Builder<Episode>.CreateListOfSize(1)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
BuildIndexers(parseResults);
|
||||||
|
|
||||||
|
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _episodeIndexer2.Object };
|
||||||
|
|
||||||
|
Mocker.GetMock<IndexerProvider>()
|
||||||
|
.Setup(c => c.GetEnabledIndexers())
|
||||||
|
.Returns(_indexers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildIndexers(IList<EpisodeParseResult> parseResults)
|
||||||
|
{
|
||||||
|
_episodeIndexer1 = new Mock<IndexerBase>();
|
||||||
|
_episodeIndexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer1.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
|
||||||
|
|
||||||
|
_episodeIndexer2 = new Mock<IndexerBase>();
|
||||||
|
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer2.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Returns(parseResults);
|
||||||
|
|
||||||
|
_brokenIndexer = new Mock<IndexerBase>();
|
||||||
|
_brokenIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Throws(new Exception());
|
||||||
|
|
||||||
|
_nullIndexer = new Mock<IndexerBase>();
|
||||||
|
_nullIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||||
|
.Returns<List<EpisodeParseResult>>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithTwoGoodOneBrokenIndexer()
|
||||||
|
{
|
||||||
|
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _brokenIndexer.Object, _episodeIndexer2.Object };
|
||||||
|
|
||||||
|
Mocker.GetMock<IndexerProvider>()
|
||||||
|
.Setup(c => c.GetEnabledIndexers())
|
||||||
|
.Returns(_indexers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithNullIndexers()
|
||||||
|
{
|
||||||
|
_indexers = new List<IndexerBase> { _nullIndexer.Object, _nullIndexer.Object };
|
||||||
|
|
||||||
|
Mocker.GetMock<IndexerProvider>()
|
||||||
|
.Setup(c => c.GetEnabledIndexers())
|
||||||
|
.Returns(_indexers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithSceneName()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<SceneMappingProvider>()
|
||||||
|
.Setup(s => s.GetSceneName(_series.SeriesId)).Returns(SCENE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void With30Episodes()
|
||||||
|
{
|
||||||
|
_episodes = Builder<Episode>.CreateListOfSize(30)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WithNullEpisodes()
|
||||||
|
{
|
||||||
|
_episodes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchEpisode(Times times)
|
||||||
|
{
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
|
||||||
|
_episodeIndexer2.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchEpisodeWithSceneName(Times times)
|
||||||
|
{
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
|
||||||
|
_episodeIndexer2.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchEpisodeBrokenIndexer(Times times)
|
||||||
|
{
|
||||||
|
_brokenIndexer.Verify(v => v.FetchEpisode(It.IsAny<string>(), SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchPartialSeason(Times times)
|
||||||
|
{
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
|
||||||
|
_episodeIndexer2.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
|
||||||
|
, times);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifyFetchSeason(Times times)
|
||||||
|
{
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
|
||||||
|
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SeasonSearch_should_skip_daily_series()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
_series.IsDaily = true;
|
||||||
|
|
||||||
|
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(1)).Returns(_series);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().SeasonSearch(MockNotification, _series.SeriesId, 1);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PartialSeasonSearch_should_skip_daily_series()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
_series.IsDaily = true;
|
||||||
|
|
||||||
|
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(1)).Returns(_series);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().PartialSeasonSearch(MockNotification, _series.SeriesId, 1);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EpisodeSearch_should_skip_if_air_date_is_null()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
_series.IsDaily = true;
|
||||||
|
var episode = _episodes.First();
|
||||||
|
episode.AirDate = null;
|
||||||
|
episode.Series = _series;
|
||||||
|
|
||||||
|
Mocker.GetMock<EpisodeProvider>().Setup(s => s.GetEpisode(episode.EpisodeId))
|
||||||
|
.Returns(episode);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SearchProvider>().EpisodeSearch(MockNotification, episode.EpisodeId);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
ExceptionVerification.ExcpectedWarns(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using Migrator.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migrations
|
||||||
|
{
|
||||||
|
|
||||||
|
[Migration(20111125)]
|
||||||
|
public class Migration2011125 : Migration
|
||||||
|
{
|
||||||
|
public override void Up()
|
||||||
|
{
|
||||||
|
Database.AddColumn("Series", "IsDaily", DbType.Boolean, ColumnProperty.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Down()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -204,6 +204,7 @@
|
||||||
<Compile Include="Datastore\MigrationLogger.cs" />
|
<Compile Include="Datastore\MigrationLogger.cs" />
|
||||||
<Compile Include="Datastore\MigrationsHelper.cs" />
|
<Compile Include="Datastore\MigrationsHelper.cs" />
|
||||||
<Compile Include="Datastore\CustomeMapper.cs" />
|
<Compile Include="Datastore\CustomeMapper.cs" />
|
||||||
|
<Compile Include="Datastore\Migrations\Migration20111125.cs" />
|
||||||
<Compile Include="Datastore\Migrations\Migration20111112.cs" />
|
<Compile Include="Datastore\Migrations\Migration20111112.cs" />
|
||||||
<Compile Include="Datastore\Migrations\Migration20111011.cs" />
|
<Compile Include="Datastore\Migrations\Migration20111011.cs" />
|
||||||
<Compile Include="Datastore\Migrations\Migration20110909.cs" />
|
<Compile Include="Datastore\Migrations\Migration20110909.cs" />
|
||||||
|
@ -261,6 +262,7 @@
|
||||||
<Compile Include="Providers\MisnamedProvider.cs" />
|
<Compile Include="Providers\MisnamedProvider.cs" />
|
||||||
<Compile Include="Providers\PostDownloadProvider.cs" />
|
<Compile Include="Providers\PostDownloadProvider.cs" />
|
||||||
<Compile Include="Providers\QualityTypeProvider.cs" />
|
<Compile Include="Providers\QualityTypeProvider.cs" />
|
||||||
|
<Compile Include="Providers\ReferenceDataProvider.cs" />
|
||||||
<Compile Include="Providers\SearchProvider.cs" />
|
<Compile Include="Providers\SearchProvider.cs" />
|
||||||
<Compile Include="Providers\SmtpProvider.cs" />
|
<Compile Include="Providers\SmtpProvider.cs" />
|
||||||
<Compile Include="Providers\TwitterProvider.cs" />
|
<Compile Include="Providers\TwitterProvider.cs" />
|
||||||
|
|
|
@ -179,6 +179,33 @@ namespace NzbDrone.Core.Providers.Indexer
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual IList<EpisodeParseResult> FetchDailyEpisode(string seriesTitle, DateTime airDate)
|
||||||
|
{
|
||||||
|
_logger.Debug("Searching {0} for {1}-{2}", Name, seriesTitle, airDate.ToShortDateString());
|
||||||
|
|
||||||
|
var result = new List<EpisodeParseResult>();
|
||||||
|
|
||||||
|
var searchModel = new SearchModel
|
||||||
|
{
|
||||||
|
SeriesTitle = GetQueryTitle(seriesTitle),
|
||||||
|
AirDate = airDate,
|
||||||
|
SearchType = SearchType.DailySearch
|
||||||
|
};
|
||||||
|
|
||||||
|
var searchUrls = GetSearchUrls(searchModel);
|
||||||
|
|
||||||
|
foreach (var url in searchUrls)
|
||||||
|
{
|
||||||
|
result.AddRange(Fetch(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.Where(e => e.CleanTitle == Parser.NormalizeTitle(seriesTitle)).ToList();
|
||||||
|
|
||||||
|
_logger.Info("Finished searching {0} for {1}-{2}, Found {3}", Name, seriesTitle, airDate.ToShortDateString(), result.Count);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<EpisodeParseResult> Fetch(string url)
|
private IEnumerable<EpisodeParseResult> Fetch(string url)
|
||||||
{
|
{
|
||||||
var result = new List<EpisodeParseResult>();
|
var result = new List<EpisodeParseResult>();
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Providers.Jobs
|
||||||
|
|
||||||
public int DefaultInterval
|
public int DefaultInterval
|
||||||
{
|
{
|
||||||
get { return 0; }
|
get { return 10080; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.Providers.Jobs
|
||||||
|
|
||||||
public int DefaultInterval
|
public int DefaultInterval
|
||||||
{
|
{
|
||||||
get { return 0; }
|
get { return 43200; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
||||||
|
|
|
@ -11,12 +11,15 @@ namespace NzbDrone.Core.Providers.Jobs
|
||||||
{
|
{
|
||||||
private readonly SeriesProvider _seriesProvider;
|
private readonly SeriesProvider _seriesProvider;
|
||||||
private readonly EpisodeProvider _episodeProvider;
|
private readonly EpisodeProvider _episodeProvider;
|
||||||
|
private readonly ReferenceDataProvider _referenceDataProvider;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public UpdateInfoJob(SeriesProvider seriesProvider, EpisodeProvider episodeProvider)
|
public UpdateInfoJob(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
|
||||||
|
ReferenceDataProvider referenceDataProvider)
|
||||||
{
|
{
|
||||||
_seriesProvider = seriesProvider;
|
_seriesProvider = seriesProvider;
|
||||||
_episodeProvider = episodeProvider;
|
_episodeProvider = episodeProvider;
|
||||||
|
_referenceDataProvider = referenceDataProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateInfoJob()
|
public UpdateInfoJob()
|
||||||
|
@ -31,7 +34,7 @@ namespace NzbDrone.Core.Providers.Jobs
|
||||||
|
|
||||||
public int DefaultInterval
|
public int DefaultInterval
|
||||||
{
|
{
|
||||||
get { return 1440; } //Daily
|
get { return 720; } //Daily
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
|
||||||
|
@ -46,6 +49,9 @@ namespace NzbDrone.Core.Providers.Jobs
|
||||||
seriesToUpdate = new List<Series>() { _seriesProvider.GetSeries(targetId) };
|
seriesToUpdate = new List<Series>() { _seriesProvider.GetSeries(targetId) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Update any Daily Series in the DB with the IsDaily flag
|
||||||
|
_referenceDataProvider.UpdateDailySeries();
|
||||||
|
|
||||||
foreach (var series in seriesToUpdate)
|
foreach (var series in seriesToUpdate)
|
||||||
{
|
{
|
||||||
notification.CurrentMessage = "Updating " + series.Title;
|
notification.CurrentMessage = "Updating " + series.Title;
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Providers.Core;
|
||||||
|
using PetaPoco;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Providers
|
||||||
|
{
|
||||||
|
public class ReferenceDataProvider
|
||||||
|
{
|
||||||
|
private readonly IDatabase _database;
|
||||||
|
private readonly HttpProvider _httpProvider;
|
||||||
|
|
||||||
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public ReferenceDataProvider(IDatabase database, HttpProvider httpProvider)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void UpdateDailySeries()
|
||||||
|
{
|
||||||
|
//Update all series in DB
|
||||||
|
//DailySeries.csv
|
||||||
|
|
||||||
|
var seriesIds = GetDailySeriesIds();
|
||||||
|
|
||||||
|
var dailySeriesString = String.Join(", ", seriesIds);
|
||||||
|
var sql = String.Format("UPDATE Series SET IsDaily = 1 WHERE SeriesId in ({0})", dailySeriesString);
|
||||||
|
|
||||||
|
_database.Execute(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsSeriesDaily(int seriesId)
|
||||||
|
{
|
||||||
|
return GetDailySeriesIds().Contains(seriesId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int> GetDailySeriesIds()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dailySeries = _httpProvider.DownloadString("http://www.nzbdrone.com/DailySeries.csv");
|
||||||
|
|
||||||
|
var seriesIds = new List<int>();
|
||||||
|
|
||||||
|
using (var reader = new StringReader(dailySeries))
|
||||||
|
{
|
||||||
|
string line;
|
||||||
|
while ((line = reader.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
int seriesId;
|
||||||
|
|
||||||
|
if (Int32.TryParse(line, out seriesId))
|
||||||
|
seriesIds.Add(seriesId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return seriesIds;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Logger.WarnException("Failed to get Daily Series", ex);
|
||||||
|
return new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
@ -48,6 +49,10 @@ namespace NzbDrone.Core.Providers
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Return false if the series is a daily series (we only support individual episode searching
|
||||||
|
if (series.IsDaily)
|
||||||
|
return false;
|
||||||
|
|
||||||
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 reports = PerformSearch(notification, series, seasonNumber);
|
var reports = PerformSearch(notification, series, seasonNumber);
|
||||||
|
@ -94,6 +99,10 @@ namespace NzbDrone.Core.Providers
|
||||||
return new List<int>();
|
return new List<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Return empty list if the series is a daily series (we only support individual episode searching
|
||||||
|
if (series.IsDaily)
|
||||||
|
return new List<int>();
|
||||||
|
|
||||||
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);
|
||||||
|
@ -119,41 +128,26 @@ namespace NzbDrone.Core.Providers
|
||||||
Logger.Error("Unable to find an episode {0} in database", episodeId);
|
Logger.Error("Unable to find an episode {0} in database", episodeId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.CurrentMessage = "Searching for " + episode;
|
notification.CurrentMessage = "Searching for " + episode;
|
||||||
|
|
||||||
var series = _seriesProvider.GetSeries(episode.SeriesId);
|
var series = _seriesProvider.GetSeries(episode.SeriesId);
|
||||||
|
|
||||||
var indexers = _indexerProvider.GetEnabledIndexers();
|
if (episode.Series.IsDaily && !episode.AirDate.HasValue)
|
||||||
var reports = new List<EpisodeParseResult>();
|
|
||||||
|
|
||||||
var title = _sceneMappingProvider.GetSceneName(series.SeriesId);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(title))
|
|
||||||
{
|
{
|
||||||
title = series.Title;
|
Logger.Warn("AirDate is not Valid for: {0}", episode);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var indexer in indexers)
|
var reports = PerformSearch(notification, series, episode.SeasonNumber, new List<Episode> { episode });
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name);
|
|
||||||
|
|
||||||
//TODO:Add support for daily episodes, maybe search using both date and season/episode?
|
|
||||||
var indexerResults = indexer.FetchEpisode(title, episode.SeasonNumber, episode.EpisodeNumber);
|
|
||||||
|
|
||||||
reports.AddRange(indexerResults);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (ProcessSearchResults(notification, reports, series, episode.SeasonNumber, episode.EpisodeNumber).Count == 1)
|
if (!series.IsDaily && ProcessSearchResults(notification, reports, series, episode.SeasonNumber, episode.EpisodeNumber).Count == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (series.IsDaily && ProcessSearchResults(notification, reports, series, episode.AirDate.Value))
|
||||||
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);
|
||||||
|
@ -182,15 +176,23 @@ namespace NzbDrone.Core.Providers
|
||||||
if (episodes == null)
|
if (episodes == null)
|
||||||
reports.AddRange(indexer.FetchSeason(title, seasonNumber));
|
reports.AddRange(indexer.FetchSeason(title, seasonNumber));
|
||||||
|
|
||||||
else if(episodes.Count == 1)
|
//Treat as single episode
|
||||||
reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodes.First().EpisodeNumber));
|
else if (episodes.Count == 1)
|
||||||
|
{
|
||||||
|
if (!series.IsDaily)
|
||||||
|
reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodes.First().EpisodeNumber));
|
||||||
|
|
||||||
|
//Daily Episode
|
||||||
|
else
|
||||||
|
reports.AddRange(indexer.FetchDailyEpisode(title, episodes.First().AirDate.Value));
|
||||||
|
}
|
||||||
|
|
||||||
//Treat as Partial Season
|
//Treat as Partial Season
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var prefixes = GetEpisodeNumberPrefixes(episodes.Select(s => s.EpisodeNumber));
|
var prefixes = GetEpisodeNumberPrefixes(episodes.Select(s => s.EpisodeNumber));
|
||||||
|
|
||||||
foreach(var episodePrefix in prefixes)
|
foreach (var episodePrefix in prefixes)
|
||||||
{
|
{
|
||||||
reports.AddRange(indexer.FetchPartialSeason(title, seasonNumber, episodePrefix));
|
reports.AddRange(indexer.FetchPartialSeason(title, seasonNumber, episodePrefix));
|
||||||
}
|
}
|
||||||
|
@ -267,6 +269,54 @@ namespace NzbDrone.Core.Providers
|
||||||
return successes;
|
return successes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ProcessSearchResults(ProgressNotification notification, IEnumerable<EpisodeParseResult> reports, Series series, DateTime airDate)
|
||||||
|
{
|
||||||
|
foreach (var episodeParseResult in reports.OrderByDescending(c => c.Quality))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Trace("Analysing report " + episodeParseResult);
|
||||||
|
|
||||||
|
//Get the matching series
|
||||||
|
episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);
|
||||||
|
|
||||||
|
//If series is null or doesn't match the series we're looking for return
|
||||||
|
if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
|
||||||
|
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)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_inventoryProvider.IsQualityNeeded(episodeParseResult))
|
||||||
|
{
|
||||||
|
Logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_downloadProvider.DownloadReport(episodeParseResult))
|
||||||
|
{
|
||||||
|
notification.CurrentMessage =
|
||||||
|
String.Format("{0} - {1} {2}Added to download queue",
|
||||||
|
episodeParseResult.Series.Title, episodeParseResult.AirDate.Value.ToShortDateString(), episodeParseResult.Quality);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private List<int> GetEpisodeNumberPrefixes(IEnumerable<int> episodeNumbers)
|
private List<int> GetEpisodeNumberPrefixes(IEnumerable<int> episodeNumbers)
|
||||||
{
|
{
|
||||||
var results = new List<int>();
|
var results = new List<int>();
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace NzbDrone.Core.Repository
|
||||||
|
|
||||||
public string BannerUrl { get; set; }
|
public string BannerUrl { get; set; }
|
||||||
|
|
||||||
|
public bool IsDaily { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this <see cref="Series"/> is hidden.
|
/// Gets or sets a value indicating whether this <see cref="Series"/> is hidden.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -34,18 +34,18 @@
|
||||||
.providerSection
|
.providerSection
|
||||||
{
|
{
|
||||||
float: left;
|
float: left;
|
||||||
width: 270px;
|
width: 255px;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
border:solid 1px #CCCCCD;
|
border:solid 1px #CCCCCD;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
padding: 5px 5px 5px 5px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerOptions label
|
.providerOptions label
|
||||||
{
|
{
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-left: 7px;
|
margin-left: 3px;
|
||||||
margin-right: 25px;
|
margin-right: 25px;
|
||||||
float: left;
|
float: left;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
padding:4px 2px;
|
padding:4px 2px;
|
||||||
border:solid 1px #aacfe4;
|
border:solid 1px #aacfe4;
|
||||||
width:170px;
|
width:170px;
|
||||||
margin-right: 2px;
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.providerOptions select
|
.providerOptions select
|
||||||
|
@ -80,7 +80,7 @@ input[type="checkbox"]
|
||||||
|
|
||||||
#newznabProviders
|
#newznabProviders
|
||||||
{
|
{
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
|
@ -1,7 +1,13 @@
|
||||||
#bottom
|
#top
|
||||||
|
{
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bottom
|
||||||
{
|
{
|
||||||
margin-top: -10px;
|
margin-top: -10px;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#addItem
|
#addItem
|
||||||
|
@ -17,6 +23,11 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#profiles
|
||||||
|
{
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* QualityProfileItem */
|
/* QualityProfileItem */
|
||||||
.quality-selectee
|
.quality-selectee
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,14 +7,9 @@
|
||||||
<style>
|
<style>
|
||||||
#examples
|
#examples
|
||||||
{
|
{
|
||||||
clear: both;
|
margin-top: 25px;
|
||||||
margin-top: 15px;
|
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
padding-left: 20px;
|
||||||
|
|
||||||
#singleEpisodeExample, #multiEpisodeExample
|
|
||||||
{
|
|
||||||
float: left
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
|
@ -81,12 +76,9 @@
|
||||||
</label>
|
</label>
|
||||||
@Html.DropDownListFor(m => m.MultiEpisodeStyle, Model.MultiEpisodeStyles, new { @class = "inputClass selectClass" })
|
@Html.DropDownListFor(m => m.MultiEpisodeStyle, Model.MultiEpisodeStyles, new { @class = "inputClass selectClass" })
|
||||||
|
|
||||||
<br/>
|
<div id ="examples">
|
||||||
<div id ="examples" class="clearfix">
|
<div id="singleEpisodeExample"></div>
|
||||||
<div id="singleEpisodeExample">
|
<div id="multiEpisodeExample"></div>
|
||||||
</div>
|
|
||||||
<div id="multiEpisodeExample">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" id="save_button" disabled="disabled">Save</button>
|
<button type="submit" id="save_button" disabled="disabled">Save</button>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="notifier clearfix">
|
<div class="notifier">
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.GrowlEnabled)
|
<label class="labelClass">@Html.LabelFor(m => m.GrowlEnabled)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.GrowlEnabled)</span>
|
<span class="small">@Html.DescriptionFor(m => m.GrowlEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
@model NzbDrone.Web.Models.IndexerSettingsModel
|
@model NzbDrone.Web.Models.IndexerSettingsModel
|
||||||
@section HeaderContent{
|
@section HeaderContent{
|
||||||
<link rel="stylesheet" type="text/css" href="../../Content/Settings.css" />
|
<link rel="stylesheet" type="text/css" href="../../Content/Settings.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../Content/IndexerSettings.css" />
|
||||||
<style>
|
<style>
|
||||||
.indexerPanel
|
.indexerPanel
|
||||||
{
|
{
|
||||||
|
overflow: auto;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +18,16 @@
|
||||||
font-size: 120%;
|
font-size: 120%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#stylized .indexerPanel .labelClass
|
||||||
|
{
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stylized .indexerPanel .small
|
||||||
|
{
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
@section TitleContent{
|
@section TitleContent{
|
||||||
|
@ -39,7 +51,7 @@ Settings
|
||||||
<div id="accordion">
|
<div id="accordion">
|
||||||
<h3>
|
<h3>
|
||||||
<a href="#">NZBs.org</a></h3>
|
<a href="#">NZBs.org</a></h3>
|
||||||
<div class="indexerPanel clearfix">
|
<div class="indexerPanel">
|
||||||
<label class="labelClass">
|
<label class="labelClass">
|
||||||
Enable <span class="small">@Html.DescriptionFor(m => m.NzbsOrgEnabled)</span>
|
Enable <span class="small">@Html.DescriptionFor(m => m.NzbsOrgEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -55,7 +67,7 @@ Settings
|
||||||
</div>
|
</div>
|
||||||
<h3>
|
<h3>
|
||||||
<a href="#">NZBMatrix</a></h3>
|
<a href="#">NZBMatrix</a></h3>
|
||||||
<div class="indexerPanel clearfix">
|
<div class="indexerPanel">
|
||||||
<label class="labelClass">
|
<label class="labelClass">
|
||||||
Enable <span class="small">@Html.DescriptionFor(m => m.NzbMatrixEnabled)</span>
|
Enable <span class="small">@Html.DescriptionFor(m => m.NzbMatrixEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -71,7 +83,7 @@ Settings
|
||||||
</div>
|
</div>
|
||||||
<h3>
|
<h3>
|
||||||
<a href="#">NZBsRus</a></h3>
|
<a href="#">NZBsRus</a></h3>
|
||||||
<div class="indexerPanel clearfix">
|
<div class="indexerPanel">
|
||||||
<label class="labelClass">
|
<label class="labelClass">
|
||||||
Enable <span class="small">@Html.DescriptionFor(m => m.NzbsRUsEnabled)</span>
|
Enable <span class="small">@Html.DescriptionFor(m => m.NzbsRUsEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -87,7 +99,7 @@ Settings
|
||||||
</div>
|
</div>
|
||||||
<h3>
|
<h3>
|
||||||
<a href="#">Newsbin</a></h3>
|
<a href="#">Newsbin</a></h3>
|
||||||
<div class="indexerPanel clearfix">
|
<div class="indexerPanel">
|
||||||
<label class="labelClass">
|
<label class="labelClass">
|
||||||
Enable <span class="small">@Html.DescriptionFor(m => m.NewzbinEnabled)</span>
|
Enable <span class="small">@Html.DescriptionFor(m => m.NewzbinEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -103,13 +115,14 @@ Settings
|
||||||
</div>
|
</div>
|
||||||
<h3>
|
<h3>
|
||||||
<a href="#">Newznab</a></h3>
|
<a href="#">Newznab</a></h3>
|
||||||
<div class="indexerPanel clearfix">
|
<div class="indexerPanel">
|
||||||
<label class="labelClass">
|
<label class="labelClass">
|
||||||
Enable <span class="small">@Html.DescriptionFor(m => m.NewznabEnabled)</span>
|
Enable <span class="small">@Html.DescriptionFor(m => m.NewznabEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
@Html.CheckBoxFor(m => m.NewznabEnabled, new { @class = "inputClass checkClass" })
|
@Html.CheckBoxFor(m => m.NewznabEnabled, new { @class = "inputClass checkClass" })
|
||||||
<p>
|
<br/>
|
||||||
</p>
|
<br/>
|
||||||
|
<p></p>
|
||||||
<a id="addItem" href="@Url.Action("AddNewznabProvider", "Settings")">
|
<a id="addItem" href="@Url.Action("AddNewznabProvider", "Settings")">
|
||||||
<img src="../../Content/Images/Plus.png" alt="Add Newznab Provider" width="20px"
|
<img src="../../Content/Images/Plus.png" alt="Add Newznab Provider" width="20px"
|
||||||
height="20px" />
|
height="20px" />
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
.notifier
|
.notifier
|
||||||
{
|
{
|
||||||
width: 560px;
|
width: 560px;
|
||||||
border:solid 2px #CCCCCD;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin-left: -8px;
|
margin-left: -8px;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notifier h4
|
.notifier h4
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="notifier clearfix">
|
<div class="notifier">
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.ProwlEnabled)
|
<label class="labelClass">@Html.LabelFor(m => m.ProwlEnabled)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.ProwlEnabled)</span>
|
<span class="small">@Html.DescriptionFor(m => m.ProwlEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -14,7 +14,7 @@ Settings
|
||||||
<div id="stylized">
|
<div id="stylized">
|
||||||
@using (Html.BeginForm("SaveQuality", "Settings", FormMethod.Post, new { id = "form", name = "form" }))
|
@using (Html.BeginForm("SaveQuality", "Settings", FormMethod.Post, new { id = "form", name = "form" }))
|
||||||
{
|
{
|
||||||
<div id="top" class="settingsForm clearfix">
|
<div id="top" class="settingsForm">
|
||||||
<h1>
|
<h1>
|
||||||
Quality</h1>
|
Quality</h1>
|
||||||
<p>
|
<p>
|
||||||
|
@ -69,14 +69,14 @@ Settings
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="bottom" class="clearfix">
|
<div id="bottom">
|
||||||
<div id="profileContainer">
|
<div id="profileContainer">
|
||||||
<div id="profileHeader">
|
<div id="profileHeader">
|
||||||
<a id="addItem" href="@Url.Action("AddProfile", "Settings")">
|
<a id="addItem" href="@Url.Action("AddProfile", "Settings")">
|
||||||
<img src="../../Content/Images/Plus.png" alt="Add New Profile" width="20px" height="20px" />
|
<img src="../../Content/Images/Plus.png" alt="Add New Profile" width="20px" height="20px" />
|
||||||
Add New Profile</a>
|
Add New Profile</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="profiles" class="clearfix">
|
<div id="profiles">
|
||||||
@foreach (var item in Model.Profiles)
|
@foreach (var item in Model.Profiles)
|
||||||
{
|
{
|
||||||
Html.RenderAction("GetQualityProfileView", item);
|
Html.RenderAction("GetQualityProfileView", item);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="notifier clearfix">
|
<div class="notifier">
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.SmtpEnabled)
|
<label class="labelClass">@Html.LabelFor(m => m.SmtpEnabled)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.SmtpEnabled)</span>
|
<span class="small">@Html.DescriptionFor(m => m.SmtpEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="notifier clearfix">
|
<div class="notifier">
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.TwitterEnabled)
|
<label class="labelClass">@Html.LabelFor(m => m.TwitterEnabled)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.TwitterEnabled)</span>
|
<span class="small">@Html.DescriptionFor(m => m.TwitterEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="notifier clearfix">
|
<div class="notifier">
|
||||||
<label class="labelClass">@Html.LabelFor(m => m.XbmcEnabled)
|
<label class="labelClass">@Html.LabelFor(m => m.XbmcEnabled)
|
||||||
<span class="small">@Html.DescriptionFor(m => m.XbmcEnabled)</span>
|
<span class="small">@Html.DescriptionFor(m => m.XbmcEnabled)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
Loading…
Reference in New Issue