BacklogStatus added to individually control which series are included in backlog searches. Applies to Backlog and RecentBacklog jobs. Editable in Series/MassEdit and Series Edit.

pull/3113/head
Mark McDowall 13 years ago
parent fb17765d3a
commit 9eb022fdf4

@ -2,9 +2,11 @@
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
@ -53,7 +55,15 @@ namespace NzbDrone.Core.Test.JobTests
//Setup //Setup
var notification = new ProgressNotification("Backlog Search Job Test"); var notification = new ProgressNotification("Backlog Search Job Test");
var episodes = Builder<Episode>.CreateListOfSize(1).Build(); var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(1)
.All()
.With(e => e.Series = series)
.Build();
WithStrictMocker(); WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
@ -81,7 +91,15 @@ namespace NzbDrone.Core.Test.JobTests
//Setup //Setup
var notification = new ProgressNotification("Backlog Search Job Test"); var notification = new ProgressNotification("Backlog Search Job Test");
var episodes = Builder<Episode>.CreateListOfSize(5).Build(); var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(5)
.All()
.With(e => e.Series = series)
.Build();
WithStrictMocker(); WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
@ -109,9 +127,14 @@ namespace NzbDrone.Core.Test.JobTests
//Setup //Setup
var notification = new ProgressNotification("Backlog Search Job Test"); var notification = new ProgressNotification("Backlog Search Job Test");
var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(5) var episodes = Builder<Episode>.CreateListOfSize(5)
.All() .All()
.With(e => e.SeriesId = 1) .With(e => e.Series = series)
.With(e => e.SeasonNumber = 1) .With(e => e.SeasonNumber = 1)
.Build(); .Build();
@ -144,9 +167,15 @@ namespace NzbDrone.Core.Test.JobTests
//Setup //Setup
var notification = new ProgressNotification("Backlog Search Job Test"); var notification = new ProgressNotification("Backlog Search Job Test");
var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(5) var episodes = Builder<Episode>.CreateListOfSize(5)
.All() .All()
.With(e => e.SeriesId = 1) .With(e => e.Series = series)
.With(e => e.SeriesId = series.SeriesId)
.With(e => e.SeasonNumber = 1) .With(e => e.SeasonNumber = 1)
.Build(); .Build();
@ -179,10 +208,23 @@ namespace NzbDrone.Core.Test.JobTests
//Setup //Setup
var notification = new ProgressNotification("Backlog Search Job Test"); var notification = new ProgressNotification("Backlog Search Job Test");
var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var series2 = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(10) var episodes = Builder<Episode>.CreateListOfSize(10)
.TheFirst(5) .TheFirst(5)
.With(e => e.SeriesId = 1) .With(e => e.Series = series)
.With(e => e.SeriesId = series.SeriesId)
.With(e => e.SeasonNumber = 1) .With(e => e.SeasonNumber = 1)
.TheNext(5)
.With(e => e.Series = series2)
.Build(); .Build();
WithStrictMocker(); WithStrictMocker();
@ -210,5 +252,120 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
Times.Exactly(5)); Times.Exactly(5));
} }
[Test]
public void GetMissingForEnabledSeries_should_only_return_episodes_for_monitored_series()
{
//Setup
var series = Builder<Series>.CreateListOfSize(2)
.TheFirst(1)
.With(s => s.Monitored = false)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(11)
.TheFirst(5)
.With(e => e.Series = series[0])
.With(e => e.SeasonNumber = 1)
.TheLast(6)
.With(e => e.Series = series[1])
.Build();
WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<BacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.Monitored);
result.Should().NotContain(s => !s.Series.Monitored);
}
[Test]
public void GetMissingForEnabledSeries_should_only_return_explicity_enabled_series_when_backlog_searching_is_ignored()
{
//Setup
var series = Builder<Series>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Disable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Inherit)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(12)
.TheFirst(3)
.With(e => e.Series = series[0])
.TheNext(4)
.With(e => e.Series = series[1])
.TheNext(5)
.With(e => e.Series = series[2])
.Build();
//WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<BacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Enable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Disable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Inherit);
}
[Test]
public void GetMissingForEnabledSeries_should_return_explicity_enabled_and_inherit_series_when_backlog_searching_is_enabled()
{
//Setup
var series = Builder<Series>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Disable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Inherit)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(12)
.TheFirst(3)
.With(e => e.Series = series[0])
.TheNext(4)
.With(e => e.Series = series[1])
.TheNext(5)
.With(e => e.Series = series[2])
.Build();
WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<BacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Enable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Disable);
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Inherit);
}
} }
} }

@ -3,9 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
@ -51,8 +53,15 @@ namespace NzbDrone.Core.Test.JobTests
{ {
WithEnableBacklogSearching(); WithEnableBacklogSearching();
var series = Builder<Series>.CreateNew()
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
//Setup //Setup
var episodes = Builder<Episode>.CreateListOfSize(50) var episodes = Builder<Episode>.CreateListOfSize(50)
.All()
.With(e => e.Series = series)
.TheFirst(5) .TheFirst(5)
.With(e => e.AirDate = DateTime.Today) .With(e => e.AirDate = DateTime.Today)
.TheNext(5) .TheNext(5)
@ -87,5 +96,121 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(It.IsAny<ProgressNotification>(), It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(It.IsAny<ProgressNotification>(), It.IsAny<int>(), 0),
Times.Exactly(40)); Times.Exactly(40));
} }
[Test]
public void GetMissingForEnabledSeries_should_only_return_episodes_for_monitored_series()
{
//Setup
var series = Builder<Series>.CreateListOfSize(2)
.TheFirst(1)
.With(s => s.Monitored = false)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(11)
.TheFirst(5)
.With(e => e.Series = series[0])
.With(e => e.SeasonNumber = 1)
.TheLast(6)
.With(e => e.Series = series[1])
.Build();
WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<RecentBacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.Monitored);
result.Should().NotContain(s => !s.Series.Monitored);
}
[Test]
public void GetMissingForEnabledSeries_should_only_return_explicity_enabled_series_when_backlog_searching_is_ignored()
{
//Setup
var series = Builder<Series>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Disable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Inherit)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(12)
.TheFirst(3)
.With(e => e.Series = series[0])
.TheNext(4)
.With(e => e.Series = series[1])
.TheNext(5)
.With(e => e.Series = series[2])
.Build();
//WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<RecentBacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Enable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Disable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Inherit);
}
[Test]
public void GetMissingForEnabledSeries_should_return_explicity_enabled_and_inherit_series_when_backlog_searching_is_enabled()
{
//Setup
var series = Builder<Series>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Disable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Enable)
.TheNext(1)
.With(s => s.Monitored = true)
.With(s => s.BacklogStatus = BacklogStatusType.Inherit)
.Build();
var episodes = Builder<Episode>.CreateListOfSize(12)
.TheFirst(3)
.With(e => e.Series = series[0])
.TheNext(4)
.With(e => e.Series = series[1])
.TheNext(5)
.With(e => e.Series = series[2])
.Build();
WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act
var result = Mocker.Resolve<RecentBacklogSearchJob>().GetMissingForEnabledSeries();
//Assert
result.Should().NotBeEmpty();
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Enable);
result.Should().NotContain(s => s.Series.BacklogStatus == BacklogStatusType.Disable);
result.Should().Contain(s => s.Series.BacklogStatus == BacklogStatusType.Inherit);
}
} }
} }

@ -0,0 +1,15 @@
using System.Data;
using Migrator.Framework;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20120123)]
public class Migration20120123 : NzbDroneMigration
{
protected override void MainDbUpgrade()
{
Database.AddColumn("Series", "BacklogStatus", DbType.Int32, ColumnProperty.Null);
Database.ExecuteNonQuery("UPDATE Series SET BacklogStatus = 2");
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
@ -39,14 +40,7 @@ namespace NzbDrone.Core.Jobs
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
{ {
if (!_configProvider.EnableBacklogSearching) var missingEpisodes = GetMissingForEnabledSeries().GroupBy(e => new { e.SeriesId, e.SeasonNumber });
{
Logger.Trace("Backlog searching is not enabled, aborting job.");
return;
}
var missingEpisodes = _episodeProvider.EpisodesWithoutFiles(true)
.GroupBy(e => new { e.SeriesId, e.SeasonNumber });
var individualEpisodes = new List<Episode>(); var individualEpisodes = new List<Episode>();
@ -91,5 +85,26 @@ namespace NzbDrone.Core.Jobs
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); _episodeSearchJob.Start(notification, episode.EpisodeId, 0);
} }
} }
public List<Episode> GetMissingForEnabledSeries()
{
if (!_configProvider.EnableBacklogSearching)
{
Logger.Trace("Backlog searching is not enabled, only running for explicitly enabled series.");
return _episodeProvider.EpisodesWithoutFiles(true).Where(e =>
e.Series.BacklogStatus == BacklogStatusType.Enable &&
e.Series.Monitored
).ToList();
}
else
{
Logger.Trace("Backlog searching is enabled, skipping explicity disabled series.");
return _episodeProvider.EpisodesWithoutFiles(true).Where(e =>
e.Series.BacklogStatus != BacklogStatusType.Disable &&
e.Series.Monitored
).ToList();
}
}
} }
} }

@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs namespace NzbDrone.Core.Jobs
{ {
@ -35,20 +38,35 @@ namespace NzbDrone.Core.Jobs
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, int targetId, int secondaryTargetId)
{ {
if (!_configProvider.EnableBacklogSearching) var missingEpisodes = GetMissingForEnabledSeries();
Logger.Debug("Processing missing episodes from the last 30 days, count: {0}", missingEpisodes.Count);
foreach (var episode in missingEpisodes)
{ {
Logger.Trace("Backlog searching is not enabled, aborting job."); _episodeSearchJob.Start(notification, episode.EpisodeId, 0);
return;
} }
}
//Get episodes that are considered missing and aired in the last 30 days public List<Episode> GetMissingForEnabledSeries()
var missingEpisodes = _episodeProvider.EpisodesWithoutFiles(true).Where(e => e.AirDate >= DateTime.Today.AddDays(-30)); {
if (!_configProvider.EnableBacklogSearching)
{
Logger.Trace("Backlog searching is not enabled, only running for explicitly enabled series.");
return _episodeProvider.EpisodesWithoutFiles(true).Where(e =>
e.AirDate >= DateTime.Today.AddDays(-30) &&
e.Series.BacklogStatus == BacklogStatusType.Enable &&
e.Series.Monitored
).ToList();
}
Logger.Debug("Processing missing episodes from the last 30 days"); else
//Process the list of remaining episodes, 1 by 1
foreach (var episode in missingEpisodes)
{ {
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); Logger.Trace("Backlog searching is enabled, skipping explicity disabled series.");
return _episodeProvider.EpisodesWithoutFiles(true).Where(e =>
e.AirDate >= DateTime.Today.AddDays(-30) &&
e.Series.BacklogStatus != BacklogStatusType.Disable &&
e.Series.Monitored
).ToList();
} }
} }
} }

@ -0,0 +1,9 @@
namespace NzbDrone.Core.Model
{
public enum BacklogStatusType
{
Disable = 0,
Enable = 1,
Inherit = 2
}
}

@ -208,6 +208,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\Migration20120123.cs" />
<Compile Include="Datastore\Migrations\Migration20120118.cs" /> <Compile Include="Datastore\Migrations\Migration20120118.cs" />
<Compile Include="Datastore\Migrations\Migration20111125.cs" /> <Compile Include="Datastore\Migrations\Migration20111125.cs" />
<Compile Include="Datastore\Migrations\Migration20111112.cs" /> <Compile Include="Datastore\Migrations\Migration20111112.cs" />
@ -228,6 +229,7 @@
<Compile Include="Datastore\PetaPoco\PetaPoco.cs" /> <Compile Include="Datastore\PetaPoco\PetaPoco.cs" />
<Compile Include="Model\AtomicParsleyTitleType.cs" /> <Compile Include="Model\AtomicParsleyTitleType.cs" />
<Compile Include="Model\ConnectionInfoModel.cs" /> <Compile Include="Model\ConnectionInfoModel.cs" />
<Compile Include="Model\BacklogStatusType.cs" />
<Compile Include="Model\PostDownloadStatusType.cs" /> <Compile Include="Model\PostDownloadStatusType.cs" />
<Compile Include="Model\JobQueueItem.cs" /> <Compile Include="Model\JobQueueItem.cs" />
<Compile Include="Model\LanguageType.cs" /> <Compile Include="Model\LanguageType.cs" />

@ -4,6 +4,7 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
@ -45,7 +46,7 @@ namespace NzbDrone.Core.Providers
{ {
var series = _database var series = _database
.Fetch<Series, QualityProfile>(@"SELECT Series.SeriesId, Series.Title, Series.CleanTitle, Series.Status, Series.Overview, Series.AirsDayOfWeek,Series.AirTimes, .Fetch<Series, QualityProfile>(@"SELECT Series.SeriesId, Series.Title, Series.CleanTitle, Series.Status, Series.Overview, Series.AirsDayOfWeek,Series.AirTimes,
Series.Language, Series.Path, Series.Monitored, Series.QualityProfileId, Series.SeasonFolder, Series.Language, Series.Path, Series.Monitored, Series.QualityProfileId, Series.SeasonFolder, Series.BacklogStatus,
SUM(CASE WHEN Ignored = 0 AND Airdate <= @0 THEN 1 ELSE 0 END) AS EpisodeCount, SUM(CASE WHEN Ignored = 0 AND Airdate <= @0 THEN 1 ELSE 0 END) AS EpisodeCount,
SUM(CASE WHEN Episodes.Ignored = 0 AND Episodes.EpisodeFileId > 0 AND Episodes.AirDate <= @0 THEN 1 ELSE 0 END) as EpisodeFileCount, SUM(CASE WHEN Episodes.Ignored = 0 AND Episodes.EpisodeFileId > 0 AND Episodes.AirDate <= @0 THEN 1 ELSE 0 END) as EpisodeFileCount,
MAX(Episodes.SeasonNumber) as SeasonCount, MIN(CASE WHEN AirDate < @0 OR Ignored = 1 THEN NULL ELSE AirDate END) as NextAiring, MAX(Episodes.SeasonNumber) as SeasonCount, MIN(CASE WHEN AirDate < @0 OR Ignored = 1 THEN NULL ELSE AirDate END) as NextAiring,
@ -55,7 +56,7 @@ namespace NzbDrone.Core.Providers
LEFT JOIN Episodes ON Series.SeriesId = Episodes.SeriesId LEFT JOIN Episodes ON Series.SeriesId = Episodes.SeriesId
WHERE Series.LastInfoSync IS NOT NULL WHERE Series.LastInfoSync IS NOT NULL
GROUP BY Series.SeriesId, Series.Title, Series.CleanTitle, Series.Status, Series.Overview, Series.AirsDayOfWeek,Series.AirTimes, GROUP BY Series.SeriesId, Series.Title, Series.CleanTitle, Series.Status, Series.Overview, Series.AirsDayOfWeek,Series.AirTimes,
Series.Language, Series.Path, Series.Monitored, Series.QualityProfileId, Series.SeasonFolder, Series.Language, Series.Path, Series.Monitored, Series.QualityProfileId, Series.SeasonFolder, Series.BacklogStatus,
QualityProfiles.QualityProfileId, QualityProfiles.Name, QualityProfiles.Cutoff, QualityProfiles.SonicAllowed", DateTime.Today); QualityProfiles.QualityProfileId, QualityProfiles.Name, QualityProfiles.Cutoff, QualityProfiles.SonicAllowed", DateTime.Today);
return series; return series;
@ -119,6 +120,7 @@ namespace NzbDrone.Core.Providers
repoSeries.QualityProfileId = _configProvider.DefaultQualityProfile; repoSeries.QualityProfileId = _configProvider.DefaultQualityProfile;
repoSeries.SeasonFolder = _configProvider.UseSeasonFolder; repoSeries.SeasonFolder = _configProvider.UseSeasonFolder;
repoSeries.BacklogStatus = BacklogStatusType.Inherit;
_database.Insert(repoSeries); _database.Insert(repoSeries);
} }
@ -210,6 +212,7 @@ namespace NzbDrone.Core.Providers
series.QualityProfileId = edited.QualityProfileId; series.QualityProfileId = edited.QualityProfileId;
series.Monitored = edited.Monitored; series.Monitored = edited.Monitored;
series.SeasonFolder = edited.SeasonFolder; series.SeasonFolder = edited.SeasonFolder;
series.BacklogStatus = edited.BacklogStatus;
series.Path = edited.Path; series.Path = edited.Path;
} }

@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using NzbDrone.Core.Model;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
using PetaPoco; using PetaPoco;
@ -43,6 +44,8 @@ namespace NzbDrone.Core.Repository
public bool IsDaily { get; set; } public bool IsDaily { get; set; }
public BacklogStatusType BacklogStatus { 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>

@ -4,9 +4,11 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMiniProfiler; using MvcMiniProfiler;
using NzbDrone.Common.Model;
using NzbDrone.Core; using NzbDrone.Core;
using NzbDrone.Core.Helpers; using NzbDrone.Core.Helpers;
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
@ -47,6 +49,15 @@ namespace NzbDrone.Web.Controllers
var profiles = _qualityProvider.All(); var profiles = _qualityProvider.All();
ViewData["SelectList"] = new SelectList(profiles, "QualityProfileId", "Name"); ViewData["SelectList"] = new SelectList(profiles, "QualityProfileId", "Name");
var backlogStatusTypes = new List<KeyValuePair<int, string>>();
foreach (BacklogStatusType backlogStatusType in Enum.GetValues(typeof(BacklogStatusType)))
{
backlogStatusTypes.Add(new KeyValuePair<int, string>((int)backlogStatusType, backlogStatusType.ToString()));
}
ViewData["BacklogStatusSelectList"] = new SelectList(backlogStatusTypes, "Key", "Value");
return View(); return View();
} }
@ -59,13 +70,14 @@ namespace NzbDrone.Web.Controllers
[AcceptVerbs(HttpVerbs.Post)] [AcceptVerbs(HttpVerbs.Post)]
[GridAction] [GridAction]
public ActionResult _SaveAjaxSeriesEditing(int id, string path, bool monitored, bool seasonFolder, int qualityProfileId) public ActionResult _SaveAjaxSeriesEditing(int id, string path, bool monitored, bool seasonFolder, int qualityProfileId, int backlogStatus)
{ {
var oldSeries = _seriesProvider.GetSeries(id); var oldSeries = _seriesProvider.GetSeries(id);
oldSeries.Monitored = monitored; oldSeries.Monitored = monitored;
oldSeries.SeasonFolder = seasonFolder; oldSeries.SeasonFolder = seasonFolder;
oldSeries.QualityProfileId = qualityProfileId; oldSeries.QualityProfileId = qualityProfileId;
oldSeries.Path = path; oldSeries.Path = path;
oldSeries.BacklogStatus = (BacklogStatusType)backlogStatus;
_seriesProvider.UpdateSeries(oldSeries); _seriesProvider.UpdateSeries(oldSeries);
@ -167,6 +179,19 @@ namespace NzbDrone.Web.Controllers
}, "Key", "Value" }, "Key", "Value"
); );
var backlogStatusTypes = new List<KeyValuePair<int, string>>();
foreach (BacklogStatusType backlogStatusType in Enum.GetValues(typeof(BacklogStatusType)))
{
backlogStatusTypes.Add(new KeyValuePair<int, string>((int)backlogStatusType, backlogStatusType.ToString()));
}
ViewData["BacklogStatusTypes"] = backlogStatusTypes;
var masterBacklogList = backlogStatusTypes.ToList();
masterBacklogList.Insert(0, new KeyValuePair<int, string>(-10, "Unchanged"));
ViewData["MasterBacklogStatusSelectList"] = new SelectList(masterBacklogList, "Key", "Value");
var series = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)); var series = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title));
return View(series); return View(series);
@ -196,6 +221,7 @@ namespace NzbDrone.Web.Controllers
QualityProfileId = s.QualityProfileId, QualityProfileId = s.QualityProfileId,
QualityProfileName = s.QualityProfile.Name, QualityProfileName = s.QualityProfile.Name,
SeasonFolder = s.SeasonFolder, SeasonFolder = s.SeasonFolder,
BacklogStatus = (int)s.BacklogStatus,
Status = s.Status, Status = s.Status,
SeasonsCount = s.SeasonCount, SeasonsCount = s.SeasonCount,
EpisodeCount = s.EpisodeCount, EpisodeCount = s.EpisodeCount,

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Web; using System.Web;
using NzbDrone.Core.Model;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
namespace NzbDrone.Web.Models namespace NzbDrone.Web.Models
@ -42,5 +43,9 @@ namespace NzbDrone.Web.Models
[DisplayName("Monitored")] [DisplayName("Monitored")]
[Description("Should NzbDrone download episodes for this series?")] [Description("Should NzbDrone download episodes for this series?")]
public bool Monitored { get; set; } public bool Monitored { get; set; }
[DisplayName("Backlog Status")]
[Description("Should NzbDrone download past missing episodes?")]
public int BacklogStatus { get; set; }
} }
} }

@ -30,5 +30,9 @@
<span class="small">@Html.DescriptionFor(m => m.Path)</span> <span class="small">@Html.DescriptionFor(m => m.Path)</span>
</label> </label>
@Html.TextBoxFor(m => m.Path, new { @class = "inputClass" }) @Html.TextBoxFor(m => m.Path, new { @class = "inputClass" })
<label class="labelClass">@Html.LabelFor(m => m.BacklogStatus)
<span class="small">@Html.DescriptionFor(m => m.BacklogStatus)</span>
</label>
@Html.DropDownListFor(m => m.BacklogStatus, (SelectList)ViewData["BacklogStatusSelectList"], new { @class = "inputClass" })
</div> </div>
</div> </div>

@ -30,6 +30,10 @@
width: 300px; width: 300px;
} }
td .backlogStatus {
width: 90px;
}
table { table {
width: 100%; width: 100%;
border-width: 1px; border-width: 1px;
@ -67,6 +71,7 @@
<th width="210px">Quality</th> <th width="210px">Quality</th>
<th class="checkboxColumn">Monitored</th> <th class="checkboxColumn">Monitored</th>
<th class="checkboxColumn">Season Folder</th> <th class="checkboxColumn">Season Folder</th>
<th width="100px">Backlog Status</th>
<th width="310px">Path</th> <th width="310px">Path</th>
</tr> </tr>
@ -91,6 +96,10 @@
<span class="small">Should downloaded episodes be stored in season folders?</span> <span class="small">Should downloaded episodes be stored in season folders?</span>
</label> </label>
@Html.DropDownList("masterSeasonFolder", (SelectList)ViewData["BoolSelectList"], new { @class = "inputClass" }) @Html.DropDownList("masterSeasonFolder", (SelectList)ViewData["BoolSelectList"], new { @class = "inputClass" })
<label class="labelClass">Backlog Status
<span class="small">Should NzbDrone perform backlog searches for this series?</span>
</label>
@Html.DropDownList("masterBacklogStatus", (SelectList)ViewData["MasterBacklogStatusSelectList"], new { @class = "inputClass" })
</div> </div>
</div> </div>
</div> </div>
@ -118,6 +127,7 @@
var profileId = $('#masterQualitySelector').val(); var profileId = $('#masterQualitySelector').val();
var monitored = $('#masterMonitored').val(); var monitored = $('#masterMonitored').val();
var seasonFolder = $('#masterSeasonFolder').val(); var seasonFolder = $('#masterSeasonFolder').val();
var backlogStatus = $('#masterBacklogStatus').val();
var selected = $('.editToggle:checked'); var selected = $('.editToggle:checked');
@ -141,6 +151,10 @@
$(this).parent('td').parent('.seriesEditRow').find('.seasonFolder').prop('checked', seasonFolderBool); $(this).parent('td').parent('.seriesEditRow').find('.seasonFolder').prop('checked', seasonFolderBool);
} }
if (backlogStatus != -10) {
$(this).parent('td').parent('.seriesEditRow').find('.backlogStatus').val(backlogStatus);
}
}); });
}); });

@ -1,4 +1,5 @@
@model NzbDrone.Core.Repository.Series @model NzbDrone.Core.Repository.Series
@using NzbDrone.Core.Model
@using NzbDrone.Core.Repository.Quality @using NzbDrone.Core.Repository.Quality
@using NzbDrone.Web.Helpers @using NzbDrone.Web.Helpers
@ -18,6 +19,7 @@
<td>@Html.DropDownListFor(m => m.QualityProfileId, new SelectList((List<QualityProfile>)ViewData["QualityProfiles"], "QualityProfileId", "Name", Model.QualityProfileId), new { @class = "quality" })</td> <td>@Html.DropDownListFor(m => m.QualityProfileId, new SelectList((List<QualityProfile>)ViewData["QualityProfiles"], "QualityProfileId", "Name", Model.QualityProfileId), new { @class = "quality" })</td>
<td class="checkboxColumn">@Html.CheckBoxFor(m => m.Monitored, new {@class = "seriesCheckbox monitored"})</td> <td class="checkboxColumn">@Html.CheckBoxFor(m => m.Monitored, new {@class = "seriesCheckbox monitored"})</td>
<td class="checkboxColumn">@Html.CheckBoxFor(m => m.SeasonFolder, new {@class = "seriesCheckbox seasonFolder"})</td> <td class="checkboxColumn">@Html.CheckBoxFor(m => m.SeasonFolder, new {@class = "seriesCheckbox seasonFolder"})</td>
<td>@Html.DropDownListFor(m => m.BacklogStatus, new SelectList((List<KeyValuePair<int, string>>)ViewData["BacklogStatusTypes"], "Key", "Value", (int)Model.BacklogStatus), new { @class = "backlogStatus" })</td>
<td>@Html.TextBoxFor(m => m.Path, new { @class = "path" })</td> <td>@Html.TextBoxFor(m => m.Path, new { @class = "path" })</td>
</tr> </tr>
} }
Loading…
Cancel
Save