More Season ignore work. Already ignored seasons will be ignored.
Fix: Season Ignore is handled separately from Episode Ignore.
This commit is contained in:
parent
969f8ae5e2
commit
aac42d4882
|
@ -103,6 +103,8 @@ namespace NzbDrone.Core.Test.ProviderTests
|
||||||
[Test]
|
[Test]
|
||||||
public void IsIgnored_should_return_ignored_status_of_season()
|
public void IsIgnored_should_return_ignored_status_of_season()
|
||||||
{
|
{
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
//Setup
|
//Setup
|
||||||
var fakeSeason = Builder<Season>.CreateNew()
|
var fakeSeason = Builder<Season>.CreateNew()
|
||||||
.With(s => s.Ignored = false)
|
.With(s => s.Ignored = false)
|
||||||
|
@ -155,7 +157,7 @@ namespace NzbDrone.Core.Test.ProviderTests
|
||||||
var lastSeason = Builder<Season>.CreateNew()
|
var lastSeason = Builder<Season>.CreateNew()
|
||||||
.With(s => s.SeriesId = 10)
|
.With(s => s.SeriesId = 10)
|
||||||
.With(s => s.SeasonNumber = 4)
|
.With(s => s.SeasonNumber = 4)
|
||||||
.With(s => s.Ignored = true)
|
.With(s => s.Ignored = false)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Db.Insert(lastSeason);
|
Db.Insert(lastSeason);
|
||||||
|
@ -189,5 +191,91 @@ namespace NzbDrone.Core.Test.ProviderTests
|
||||||
result.Should().BeTrue();
|
result.Should().BeTrue();
|
||||||
Db.Fetch<Season>().Should().HaveCount(2);
|
Db.Fetch<Season>().Should().HaveCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsIgnored_should_return_false_if_not_in_db_and_previous_season_does_not_exist()
|
||||||
|
{
|
||||||
|
//Setup
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SeasonProvider>().IsIgnored(10, 5);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().BeFalse();
|
||||||
|
Db.Fetch<Season>().Should().HaveCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void All_should_return_seasons_with_episodes()
|
||||||
|
{
|
||||||
|
const int seriesId = 10;
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
var season = Builder<Season>.CreateNew()
|
||||||
|
.With(s => s.SeriesId = seriesId)
|
||||||
|
.With(s => s.SeasonNumber = 4)
|
||||||
|
.With(s => s.Ignored = true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||||
|
.All()
|
||||||
|
.With(e => e.SeriesId = seriesId)
|
||||||
|
.With(e => e.SeasonNumber = season.SeasonNumber)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Db.Insert(season);
|
||||||
|
Db.InsertMany(episodes);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SeasonProvider>().All(seriesId);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(1);
|
||||||
|
result.First().Episodes.Should().HaveCount(episodes.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void All_should_return_all_seasons_with_episodes()
|
||||||
|
{
|
||||||
|
const int seriesId = 10;
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
WithRealDb();
|
||||||
|
|
||||||
|
var seasons = Builder<Season>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(s => s.SeriesId = seriesId)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var episodes = new List<Episode>();
|
||||||
|
|
||||||
|
for (int i = 0; i < seasons.Count; i++)
|
||||||
|
{
|
||||||
|
var newEps = Builder<Episode>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(e => e.SeriesId = seriesId)
|
||||||
|
.With(e => e.SeasonNumber = i + 1)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
episodes.AddRange(newEps);
|
||||||
|
}
|
||||||
|
|
||||||
|
Db.InsertMany(seasons);
|
||||||
|
Db.InsertMany(episodes);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = Mocker.Resolve<SeasonProvider>().All(seriesId);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
result.Should().HaveCount(5);
|
||||||
|
|
||||||
|
foreach(var season in result)
|
||||||
|
{
|
||||||
|
season.Episodes.Count.Should().Be(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,13 @@ namespace NzbDrone.Core.Datastore.Migrations
|
||||||
new Column("SeasonNumber", DbType.Int32, ColumnProperty.NotNull),
|
new Column("SeasonNumber", DbType.Int32, ColumnProperty.NotNull),
|
||||||
new Column("Ignored", DbType.Boolean, ColumnProperty.NotNull)
|
new Column("Ignored", DbType.Boolean, ColumnProperty.NotNull)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Database.ExecuteNonQuery(@"INSERT INTO Seasons (SeriesId, SeasonNumber, Ignored)
|
||||||
|
SELECT SeriesId, SeasonNumber,
|
||||||
|
CASE WHEN Count(*) =
|
||||||
|
SUM(CASE WHEN Ignored = 1 THEN 1 ELSE 0 END) THEN 1 ELSE 0 END AS Ignored
|
||||||
|
FROM Episodes
|
||||||
|
GROUP BY SeriesId, SeasonNumber");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.PetaPoco
|
||||||
|
{
|
||||||
|
public class EpisodeSeasonRelator
|
||||||
|
{
|
||||||
|
public Season _current;
|
||||||
|
public Season MapIt(Season season, Episode episode)
|
||||||
|
{
|
||||||
|
// Terminating call. Since we can return null from this function
|
||||||
|
// we need to be ready for PetaPoco to callback later with null
|
||||||
|
// parameters
|
||||||
|
if (season == null)
|
||||||
|
return _current;
|
||||||
|
|
||||||
|
// Is this the same season as the current one we're processing
|
||||||
|
if (_current != null && _current.SeasonId == season.SeasonId)
|
||||||
|
{
|
||||||
|
// Yes, just add this post to the current author's collection of posts
|
||||||
|
_current.Episodes.Add(episode);
|
||||||
|
|
||||||
|
// Return null to indicate we're not done with this author yet
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is season different author to the current one, or this is the
|
||||||
|
// first time through and we don't have an season yet
|
||||||
|
|
||||||
|
// Save the current author
|
||||||
|
var prev = _current;
|
||||||
|
|
||||||
|
// Setup the new current season
|
||||||
|
_current = season;
|
||||||
|
_current.Episodes = new List<Episode>();
|
||||||
|
_current.Episodes.Add(episode);
|
||||||
|
|
||||||
|
// Return the now populated previous season (or null if first time through)
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -234,6 +234,7 @@
|
||||||
<Compile Include="Datastore\DbProviderFactory.cs" />
|
<Compile Include="Datastore\DbProviderFactory.cs" />
|
||||||
<Compile Include="Datastore\Migrations\NzbDroneMigration.cs" />
|
<Compile Include="Datastore\Migrations\NzbDroneMigration.cs" />
|
||||||
<Compile Include="Datastore\Migrations\SchemaInfo.cs" />
|
<Compile Include="Datastore\Migrations\SchemaInfo.cs" />
|
||||||
|
<Compile Include="Datastore\PetaPoco\EpisodeSeasonRelator.cs" />
|
||||||
<Compile Include="Fluent.cs" />
|
<Compile Include="Fluent.cs" />
|
||||||
<Compile Include="Helpers\EpisodeSortingHelper.cs" />
|
<Compile Include="Helpers\EpisodeSortingHelper.cs" />
|
||||||
<Compile Include="Helpers\FileSizeFormatHelper.cs" />
|
<Compile Include="Helpers\FileSizeFormatHelper.cs" />
|
||||||
|
|
|
@ -280,7 +280,7 @@ namespace NzbDrone.Core.Providers
|
||||||
var updateList = new List<Episode>();
|
var updateList = new List<Episode>();
|
||||||
var newList = new List<Episode>();
|
var newList = new List<Episode>();
|
||||||
|
|
||||||
foreach (var episode in tvDbSeriesInfo.Episodes)
|
foreach (var episode in tvDbSeriesInfo.Episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Model;
|
using NzbDrone.Core.Model;
|
||||||
using PetaPoco;
|
using PetaPoco;
|
||||||
|
|
||||||
|
@ -12,5 +13,8 @@ namespace NzbDrone.Core.Repository
|
||||||
public int SeriesId { get; set; }
|
public int SeriesId { get; set; }
|
||||||
public int SeasonNumber { get; set; }
|
public int SeasonNumber { get; set; }
|
||||||
public Boolean Ignored { get; set; }
|
public Boolean Ignored { get; set; }
|
||||||
|
|
||||||
|
[ResultColumn]
|
||||||
|
public List<Episode> Episodes { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,16 +24,19 @@ namespace NzbDrone.Web.Controllers
|
||||||
private readonly QualityProvider _qualityProvider;
|
private readonly QualityProvider _qualityProvider;
|
||||||
private readonly SeriesProvider _seriesProvider;
|
private readonly SeriesProvider _seriesProvider;
|
||||||
private readonly JobProvider _jobProvider;
|
private readonly JobProvider _jobProvider;
|
||||||
|
private readonly SeasonProvider _seasonProvider;
|
||||||
//
|
//
|
||||||
// GET: /Series/
|
// GET: /Series/
|
||||||
|
|
||||||
public SeriesController(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
|
public SeriesController(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
|
||||||
QualityProvider qualityProvider, JobProvider jobProvider)
|
QualityProvider qualityProvider, JobProvider jobProvider,
|
||||||
|
SeasonProvider seasonProvider)
|
||||||
{
|
{
|
||||||
_seriesProvider = seriesProvider;
|
_seriesProvider = seriesProvider;
|
||||||
_episodeProvider = episodeProvider;
|
_episodeProvider = episodeProvider;
|
||||||
_qualityProvider = qualityProvider;
|
_qualityProvider = qualityProvider;
|
||||||
_jobProvider = jobProvider;
|
_jobProvider = jobProvider;
|
||||||
|
_seasonProvider = seasonProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult Index()
|
public ActionResult Index()
|
||||||
|
@ -117,25 +120,14 @@ namespace NzbDrone.Web.Controllers
|
||||||
model.SeriesId = series.SeriesId;
|
model.SeriesId = series.SeriesId;
|
||||||
model.HasBanner = !String.IsNullOrEmpty(series.BannerUrl);
|
model.HasBanner = !String.IsNullOrEmpty(series.BannerUrl);
|
||||||
|
|
||||||
var seasons = new List<SeasonModel>();
|
var seasons = _seasonProvider.All(seriesId).Select(s => new SeasonModel
|
||||||
var episodes = _episodeProvider.GetEpisodeBySeries(seriesId);
|
{
|
||||||
|
SeriesId = seriesId,
|
||||||
foreach (var season in episodes.Select(s => s.SeasonNumber).Distinct())
|
SeasonNumber = s.SeasonNumber,
|
||||||
{
|
Ignored = s.Ignored,
|
||||||
var episodesInSeason = episodes.Where(e => e.SeasonNumber == season).ToList();
|
Episodes = GetEpisodeModels(s.Episodes).OrderByDescending(e => e.EpisodeNumber).ToList(),
|
||||||
var commonStatusList = episodesInSeason.Select(s => s.Status).Distinct().ToList();
|
CommonStatus = GetCommonStatus(s.Episodes)
|
||||||
var commonStatus = commonStatusList.Count > 1 ? "Missing" : commonStatusList.First().ToString();
|
}).ToList();
|
||||||
|
|
||||||
seasons.Add(new SeasonModel
|
|
||||||
{
|
|
||||||
SeriesId = seriesId,
|
|
||||||
SeasonNumber = season,
|
|
||||||
Episodes = GetEpisodeModels(episodesInSeason).OrderByDescending(e=> e.EpisodeNumber).ToList(),
|
|
||||||
AnyWanted = episodesInSeason.Any(e => !e.Ignored),
|
|
||||||
CommonStatus = commonStatus
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
model.Seasons = seasons;
|
model.Seasons = seasons;
|
||||||
|
|
||||||
return View(model);
|
return View(model);
|
||||||
|
@ -254,5 +246,12 @@ namespace NzbDrone.Web.Controllers
|
||||||
|
|
||||||
return episodes;
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetCommonStatus(IList<Episode> episodes)
|
||||||
|
{
|
||||||
|
var commonStatusList = episodes.Select(s => s.Status).Distinct().ToList();
|
||||||
|
var commonStatus = commonStatusList.Count > 1 ? "Missing" : commonStatusList.First().ToString();
|
||||||
|
return commonStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,5 +9,6 @@ namespace NzbDrone.Web.Models
|
||||||
public List<EpisodeModel> Episodes { get; set; }
|
public List<EpisodeModel> Episodes { get; set; }
|
||||||
public bool AnyWanted { get; set; }
|
public bool AnyWanted { get; set; }
|
||||||
public string CommonStatus { get; set; }
|
public string CommonStatus { get; set; }
|
||||||
|
public bool Ignored { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,9 +40,7 @@ $(".ignoreEpisode").live("click", function () {
|
||||||
|
|
||||||
else {
|
else {
|
||||||
//Check to see if this is the last one ignored or the first not ignored
|
//Check to see if this is the last one ignored or the first not ignored
|
||||||
seasonNumber = toggle.attr('class').split(/\s+/)[1].replace('ignoreEpisode_', '');
|
|
||||||
var episodeId = toggle.attr('id');
|
var episodeId = toggle.attr('id');
|
||||||
toggleMaster(seasonNumber, ignored);
|
|
||||||
saveEpisodeIgnore(episodeId, ignored);
|
saveEpisodeIgnore(episodeId, ignored);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -68,26 +66,6 @@ function toggleChildren(seasonNumber, ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMaster(seasonNumber) {
|
|
||||||
//Toggles all master toggles when the childen changes
|
|
||||||
|
|
||||||
var ignoreEpisodes = $('.ignoreEpisode_' + seasonNumber);
|
|
||||||
var ignoredCount = ignoreEpisodes.filter('.ignored').length;
|
|
||||||
var masters = $('.ignoreSeason_' + seasonNumber);
|
|
||||||
|
|
||||||
masters.each(function (index) {
|
|
||||||
if (ignoreEpisodes.length == ignoredCount) {
|
|
||||||
$(this).attr('src', ignoredImage);
|
|
||||||
$(this).addClass('ignored');
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
$(this).attr('src', notIgnoredImage);
|
|
||||||
$(this).removeClass('ignored');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleMasters(seasonNumber, ignored) {
|
function toggleMasters(seasonNumber, ignored) {
|
||||||
//Toggles the other master(s) to match the one that was just changed
|
//Toggles the other master(s) to match the one that was just changed
|
||||||
var masters = $('.ignoreSeason_' + seasonNumber);
|
var masters = $('.ignoreSeason_' + seasonNumber);
|
||||||
|
|
|
@ -79,8 +79,8 @@
|
||||||
{
|
{
|
||||||
var ignoreSeason = "ignoreSeason_" + season.SeasonNumber;
|
var ignoreSeason = "ignoreSeason_" + season.SeasonNumber;
|
||||||
<div class="seasonToggleTop">
|
<div class="seasonToggleTop">
|
||||||
<img src='../../Content/Images/@(season.AnyWanted ? "notIgnored" : "ignored").png'
|
<img src='../../Content/Images/@(season.Ignored ? "ignored" : "notIgnored").png'
|
||||||
class='ignoredEpisodesMaster ignoreEpisode @ignoreSeason@(season.AnyWanted ? " " : " ignored") gridImage'
|
class='ignoredEpisodesMaster ignoreEpisode @ignoreSeason@(season.Ignored ? " ignored" : " ") gridImage'
|
||||||
title='Click to toggle season ignore status' />
|
title='Click to toggle season ignore status' />
|
||||||
<a href="@string.Format("#SeasonSection_{0}", season.SeasonNumber)" class="seasonToggleLabel">@(season.SeasonNumber == 0 ? "Specials" : "Season " + season.SeasonNumber)</a>
|
<a href="@string.Format("#SeasonSection_{0}", season.SeasonNumber)" class="seasonToggleLabel">@(season.SeasonNumber == 0 ? "Specials" : "Season " + season.SeasonNumber)</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
@*Commands Column*@
|
@*Commands Column*@
|
||||||
<th>
|
<th>
|
||||||
<img src='../../Content/Images/@(Model.AnyWanted ? "notIgnored" : "ignored").png' class='ignoredEpisodesMaster ignoreEpisode ignoreSeason_@(Model.SeasonNumber) @(Model.AnyWanted ? "" : "ignored") gridImage' title='Click to toggle season ignore status' />
|
<img src='../../Content/Images/@(Model.Ignored ? "ignored" : "notIgnored").png' class='ignoredEpisodesMaster ignoreEpisode ignoreSeason_@(Model.SeasonNumber)@(Model.Ignored ? " ignored" : " ") gridImage' title='Click to toggle season ignore status' />
|
||||||
<img src='../../Content/Images/@(Model.CommonStatus).png' alt='Status' title='Season Status' class='gridImage' />
|
<img src='../../Content/Images/@(Model.CommonStatus).png' alt='Status' title='Season Status' class='gridImage' />
|
||||||
@Ajax.ImageActionLink("../../Content/Images/Search.png", new { Alt = "Search", Title = "Search for all episodes in this season", @class = "gridImage" }, "SearchSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null)
|
@Ajax.ImageActionLink("../../Content/Images/Search.png", new { Alt = "Search", Title = "Search for all episodes in this season", @class = "gridImage" }, "SearchSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null)
|
||||||
@Ajax.ImageActionLink("../../Content/Images/Rename.png", new { Alt = "Rename", Title = "Rename all episodes in this season", @class = "gridImage" }, "RenameSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null)
|
@Ajax.ImageActionLink("../../Content/Images/Rename.png", new { Alt = "Rename", Title = "Rename all episodes in this season", @class = "gridImage" }, "RenameSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null)
|
||||||
|
|
Loading…
Reference in New Issue