removed Season/SeasonProvider, updated dbBenchmark tests.

pull/3113/head
kay.one 13 years ago
parent 2ecd5ddb98
commit d3be516fb2

@ -9,13 +9,14 @@ 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;
using NzbDrone.Core.Test.Framework;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
public class DownloadProviderTest public class DownloadProviderTest : TestBase
{ {
[Test] [Test]
public void Download_report_should_send_to_sab_and_add_to_history() public void Download_report_should_send_to_sab_and_add_to_history()

@ -60,40 +60,6 @@ namespace NzbDrone.Core.Test
} }
[Test]
public void EnsureSeason_is_called_once_per_season()
{
const int seriesId = 71663;
var fakeEpisodes = Builder<TvdbSeries>.CreateNew()
.With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(6).
WhereAll().Have(
l => l.Language = new TvdbLanguage(0, "eng", "a"))
.WhereTheFirst(3).Have(d => d.SeasonNumber = 1).And(
d => d.SeasonId = 11)
.AndTheRemaining().Have(d => d.SeasonNumber = 2).And(
d => d.SeasonId = 22)
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
var mocker = new AutoMoqer();
mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true))
.Returns(fakeEpisodes);
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
mocker.GetMock<SeasonProvider>().Verify(c => c.EnsureSeason(seriesId, 11, 1), Times.Once());
mocker.GetMock<SeasonProvider>().Verify(c => c.EnsureSeason(seriesId, 22, 2), Times.Once());
mocker.VerifyAllMocks();
}
[Test] [Test]
public void new_episodes_only_calls_AddMany() public void new_episodes_only_calls_AddMany()
{ {

@ -21,8 +21,6 @@ namespace NzbDrone.Core.Test
public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatusType status) public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatusType status)
{ {
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Season = Builder<Season>.CreateNew()
.With(s => s.Monitored = true).Build())
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored) .With(e => e.Ignored = ignored)
.With(e => e.EpisodeFileId = 0) .With(e => e.EpisodeFileId = 0)
@ -39,7 +37,7 @@ namespace NzbDrone.Core.Test
[Test] [Test]
[TestCase(1, false, false, EpisodeStatusType.NotAired)] [TestCase(1, false, false, EpisodeStatusType.Missing)]
[TestCase(-2, false, false, EpisodeStatusType.Missing)] [TestCase(-2, false, false, EpisodeStatusType.Missing)]
[TestCase(1, true, false, EpisodeStatusType.Ready)] [TestCase(1, true, false, EpisodeStatusType.Ready)]
[TestCase(1, false, true, EpisodeStatusType.Ignored)] [TestCase(1, false, true, EpisodeStatusType.Ignored)]
@ -47,10 +45,7 @@ namespace NzbDrone.Core.Test
EpisodeStatusType status) EpisodeStatusType status)
{ {
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Season = Builder<Season>.CreateNew() .With(e => e.Ignored = ignored)
.With(s => s.Monitored = true).Build()).With(
e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored)
.With(e => e.EpisodeFileId = 0) .With(e => e.EpisodeFileId = 0)
.With(e => e.GrabDate = DateTime.Now.AddDays(-1).AddHours(-1)) .With(e => e.GrabDate = DateTime.Now.AddDays(-1).AddHours(-1))
.Build(); .Build();
@ -74,9 +69,7 @@ namespace NzbDrone.Core.Test
EpisodeStatusType status) EpisodeStatusType status)
{ {
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Season = Builder<Season>.CreateNew() .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(s => s.Monitored = true).Build())
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored) .With(e => e.Ignored = ignored)
.With(e => e.EpisodeFileId = 0) .With(e => e.EpisodeFileId = 0)
.With(e => e.GrabDate = DateTime.Now.AddDays(-1)) .With(e => e.GrabDate = DateTime.Now.AddDays(-1))
@ -91,19 +84,16 @@ namespace NzbDrone.Core.Test
} }
[Test] [Test]
[TestCase(1, false, false, EpisodeStatusType.Ignored)] [TestCase(1, true, false, EpisodeStatusType.Ignored)]
[TestCase(-2, false, false, EpisodeStatusType.Ignored)] [TestCase(-2, true, false, EpisodeStatusType.Ignored)]
[TestCase(1, false, true, EpisodeStatusType.Ignored)] [TestCase(1, true, true, EpisodeStatusType.Ready)]
public void skipped_season(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatusType status) public void ignored_episode(int offsetDays, bool ignored, bool hasEpisodes, EpisodeStatusType status)
{ {
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored) .With(e => e.Ignored = ignored)
.With(e => e.EpisodeFileId = 0) .With(e => e.EpisodeFileId = 0)
.With(e => e.GrabDate = null) .With(e => e.GrabDate = null)
.With(e => e.Season = Builder<Season>.CreateNew()
.With(s => s.Monitored == false).Build())
.Build(); .Build();
if (hasEpisodes) if (hasEpisodes)
@ -123,8 +113,6 @@ namespace NzbDrone.Core.Test
.With(e => e.Ignored = false) .With(e => e.Ignored = false)
.With(e => e.EpisodeFileId = 0) .With(e => e.EpisodeFileId = 0)
.With(e => e.GrabDate = null) .With(e => e.GrabDate = null)
.With(e => e.Season = Builder<Season>.CreateNew()
.With(s => s.Monitored = true).Build())
.Build(); .Build();

@ -3,6 +3,7 @@ using AutoMoq;
using Moq; using Moq;
using System; using System;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
@ -103,7 +104,7 @@ namespace NzbDrone.Core.Test
//Arrange //Arrange
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
var constant = new VirtualDependency {PropValue = Guid.NewGuid().ToString()}; var constant = new VirtualDependency { PropValue = Guid.NewGuid().ToString() };
mocker.SetConstant(constant); mocker.SetConstant(constant);

@ -99,7 +99,6 @@ namespace NzbDrone.Core.Test.Framework
private static void ForceMigration(IRepository repository) private static void ForceMigration(IRepository repository)
{ {
repository.All<Series>().Count(); repository.All<Series>().Count();
repository.All<Season>().Count();
repository.All<Episode>().Count(); repository.All<Episode>().Count();
repository.All<EpisodeFile>().Count(); repository.All<EpisodeFile>().Count();
repository.All<QualityProfile>().Count(); repository.All<QualityProfile>().Count();

@ -23,7 +23,6 @@ namespace NzbDrone.Core.Test
public void AllItems() public void AllItems()
{ {
//Setup //Setup
Season season = new Season { SeasonId = 4321, SeasonNumber = 1, SeriesId = 5656, Monitored = true };
var episode = new Episode var episode = new Episode
{ {
AirDate = DateTime.Today.AddDays(-1), AirDate = DateTime.Today.AddDays(-1),
@ -31,8 +30,6 @@ namespace NzbDrone.Core.Test
EpisodeNumber = 5, EpisodeNumber = 5,
Overview = "This is an Overview", Overview = "This is an Overview",
SeasonNumber = 1, SeasonNumber = 1,
SeasonId = 4321,
Season = season,
SeriesId = 5656 SeriesId = 5656
}; };

@ -116,28 +116,7 @@ namespace NzbDrone.Core.Test
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
} }
[Test]
public void ignored_season_should_be_skipped()
{
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.FindSeries(It.IsAny<String>()))
.Returns(series);
mocker.GetMock<SeasonProvider>()
.Setup(p => p.IsIgnored(series.SeriesId, parseResultMulti.SeasonNumber))
.Returns(true);
//Act
var result = mocker.Resolve<InventoryProvider>().IsMonitored(parseResultMulti);
//Assert
Assert.IsFalse(result);
Assert.AreSame(series, parseResultMulti.Series);
mocker.VerifyAllMocks();
}
[Test] [Test]
public void IsMonitored_dailyshow_should_do_daily_lookup() public void IsMonitored_dailyshow_should_do_daily_lookup()
{ {
@ -155,12 +134,6 @@ namespace NzbDrone.Core.Test
.Setup(p => p.GetEpisode(episode.SeriesId, episode.AirDate)) .Setup(p => p.GetEpisode(episode.SeriesId, episode.AirDate))
.Returns(episode); .Returns(episode);
mocker.GetMock<SeasonProvider>()
.Setup(p => p.IsIgnored(series.SeriesId, parseResultSingle.SeasonNumber))
.Returns(false);
var result = mocker.Resolve<InventoryProvider>().IsMonitored(parseResultSingle); var result = mocker.Resolve<InventoryProvider>().IsMonitored(parseResultSingle);
//Assert //Assert
@ -178,10 +151,6 @@ namespace NzbDrone.Core.Test
.Setup(p => p.FindSeries(It.IsAny<String>())) .Setup(p => p.FindSeries(It.IsAny<String>()))
.Returns(series); .Returns(series);
mocker.GetMock<SeasonProvider>()
.Setup(p => p.IsIgnored(series.SeriesId, parseResultSingle.SeasonNumber))
.Returns(false);
mocker.GetMock<EpisodeProvider>() mocker.GetMock<EpisodeProvider>()
.Setup(p => p.GetEpisode(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber)) .Setup(p => p.GetEpisode(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber))
.Returns<Episode>(null); .Returns<Episode>(null);
@ -191,8 +160,7 @@ namespace NzbDrone.Core.Test
.Returns<Episode>(null); .Returns<Episode>(null);
mocker.GetMock<EpisodeProvider>() mocker.GetMock<EpisodeProvider>()
.Setup(p => p.AddEpisode(It.IsAny<Episode>())) .Setup(p => p.AddEpisode(It.IsAny<Episode>()));
.Returns(12);
//Act //Act
var result = mocker.Resolve<InventoryProvider>().IsMonitored(parseResultSingle); var result = mocker.Resolve<InventoryProvider>().IsMonitored(parseResultSingle);

@ -38,7 +38,10 @@ namespace NzbDrone.Core.Test
//Fakes //Fakes
var fakeSeries = Builder<Series>.CreateNew().Build(); var fakeSeries = Builder<Series>.CreateNew().Build();
var fakeEpisode = Builder<Episode>.CreateNew().With(c => c.SeriesId = fakeSeries.SeriesId).Build(); var fakeEpisode = Builder<Episode>.CreateNew()
.With(c => c.SeriesId = fakeSeries.SeriesId)
.With(c => c.SeasonNumber = seasonNumber)
.Build();
//Mocks //Mocks
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
@ -66,6 +69,8 @@ namespace NzbDrone.Core.Test
mocker.GetMock<IRepository>().Verify(r => r.Add(result), Times.Once()); mocker.GetMock<IRepository>().Verify(r => r.Add(result), Times.Once());
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
result.SeasonNumber.Should().Be(fakeEpisode.SeasonNumber);
Assert.AreEqual(fakeEpisode.SeriesId, result.SeriesId); Assert.AreEqual(fakeEpisode.SeriesId, result.SeriesId);
Assert.AreEqual(QualityTypes.DVD, result.Quality); Assert.AreEqual(QualityTypes.DVD, result.Quality);
Assert.AreEqual(Parser.NormalizePath(fileName), result.Path); Assert.AreEqual(Parser.NormalizePath(fileName), result.Path);
@ -148,10 +153,6 @@ namespace NzbDrone.Core.Test
mocker.GetMock<IRepository>(MockBehavior.Strict) mocker.GetMock<IRepository>(MockBehavior.Strict)
.Setup(r => r.Exists(It.IsAny<Expression<Func<EpisodeFile, Boolean>>>())).Returns(true).Verifiable(); .Setup(r => r.Exists(It.IsAny<Expression<Func<EpisodeFile, Boolean>>>())).Returns(true).Verifiable();
//mocker.GetMock<EpisodeProvider>()
// .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(fakeEpisode)
// .Verifiable();
mocker.GetMock<DiskProvider>() mocker.GetMock<DiskProvider>()
.Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable();
@ -161,7 +162,7 @@ namespace NzbDrone.Core.Test
//Assert //Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
Assert.IsNull(result); result.Should().BeNull();
} }
@ -341,30 +342,24 @@ namespace NzbDrone.Core.Test
} }
[Test] [Test]
public void get_season_files() public void get_series_files()
{ {
var episodes = Builder<Episode>.CreateListOfSize(20) var firstSeriesFiles = Builder<EpisodeFile>.CreateListOfSize(10)
.WhereTheFirst(8) .WhereAll().Have(s => s.SeriesId = 12).Build();
.Has(c => c.EpisodeFile = new EpisodeFile())
.AndTheRemaining()
.Has(c => c.EpisodeFile = null)
.Build().ToList();
var mocker = new AutoMoqer(); var secondSeriesFiles = Builder<EpisodeFile>.CreateListOfSize(10)
mocker.GetMock<SeasonProvider>() .WhereAll().Have(s => s.SeriesId = 20).Build();
.Setup(c => c.GetSeason(12))
.Returns(Builder<Season>.CreateNew().With(c => c.Episodes = episodes).Build())
.Verifiable();
var result = mocker.Resolve<MediaFileProvider>().GetSeasonFiles(12);
var mocker = new AutoMoqer();
var repo = MockLib.GetEmptyRepository(true);
repo.AddMany(firstSeriesFiles);
repo.AddMany(secondSeriesFiles);
mocker.SetConstant(repo);
result.Should().HaveCount(8); var result = mocker.Resolve<MediaFileProvider>().GetSeriesFiles(12);
result.Should().NotContainNulls();
mocker.VerifyAllMocks();
result.Should().HaveSameCount(firstSeriesFiles);
} }
} }
} }

@ -5,12 +5,13 @@ using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class QualityTest public class QualityTest : TestBase
{ {
[Test] [Test]
[Ignore("No supported asserts are available")] [Ignore("No supported asserts are available")]

@ -95,7 +95,6 @@ namespace NzbDrone.Core.Test
public void enteties_toString() public void enteties_toString()
{ {
Console.WriteLine(new Episode().ToString()); Console.WriteLine(new Episode().ToString());
Console.WriteLine(new Season().ToString());
Console.WriteLine(new Series().ToString()); Console.WriteLine(new Series().ToString());
Console.WriteLine(new EpisodeFile().ToString()); Console.WriteLine(new EpisodeFile().ToString());
} }

@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class RepositoryProviderTest public class RepositoryProviderTest : TestBase
{ {
[Test] [Test]
public void Get_Assembly_repos() public void Get_Assembly_repos()
@ -36,8 +36,6 @@ namespace NzbDrone.Core.Test
types.Should().Contain(typeof(IndexerSetting)); types.Should().Contain(typeof(IndexerSetting));
types.Should().Contain(typeof(JobSetting)); types.Should().Contain(typeof(JobSetting));
types.Should().Contain(typeof(RootDir)); types.Should().Contain(typeof(RootDir));
types.Should().Contain(typeof(Season));
types.Should().Contain(typeof(Season));
types.Should().Contain(typeof(Series)); types.Should().Contain(typeof(Series));
types.Should().Contain(typeof(QualityProfile)); types.Should().Contain(typeof(QualityProfile));

@ -1,117 +1,153 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using SubSonic.Repository;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class DbBenchmark public class DbBenchmark : TestBase
{ {
const int COUNT = 10000; const int Episodes_Per_Season = 20;
private List<Episode> episodes; private readonly List<int> seasonsNumbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
private List<EpisodeFile> files; private readonly List<int> seriesIds = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
private readonly List<Episode> episodes = new List<Episode>();
private readonly List<EpisodeFile> files = new List<EpisodeFile>();
[SetUp] private readonly IRepository repo = MockLib.GetEmptyRepository();
public void Setup()
[TestFixtureSetUp]
public new void Setup()
{ {
episodes = new List<Episode>(COUNT); base.Setup();
files = new List<EpisodeFile>(COUNT);
for (int i = 10; i < COUNT + 10; i++) foreach (var _seriesId in seriesIds)
{ {
var file = Builder<EpisodeFile>.CreateNew().With(c => c.EpisodeFileId = i).Build(); int seriesId = _seriesId;
files.Add(file); var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = seriesId)
var episode = Builder<Episode>.CreateNew() .With(s => s.Monitored = true)
.With(c => c.EpisodeId = i) .Build();
.And(c => c.EpisodeFileId = i)
.And(c => c.Title = DateTime.Now.ToLongTimeString()) repo.Add(series);
.And(
c => foreach (var _seasonNumber in seasonsNumbers)
c.Overview = {
@"This adds support for silverlight. Both the 3.5 CLR and a Silverlight 3 for (int i = 1; i <= Episodes_Per_Season; i++)
version are included in the zip file. Also includes some other very minor bug fixes.").Build(); {
var episode = Builder<Episode>.CreateNew()
episodes.Add(episode); .With(e => e.SeriesId = seriesId)
.And(e => e.SeasonNumber = _seasonNumber)
.And(e => e.EpisodeNumber = i)
.And(e => e.Ignored = false)
.And(e => e.TvDbEpisodeId = episodes.Count + 1)
.And(e => e.AirDate = DateTime.Today.AddDays(-20))
.Build();
episodes.Add(episode);
if (i < 10)
{
var epFile = Builder<EpisodeFile>.CreateNew()
.With(e => e.SeriesId = seriesId)
.And(e => e.SeasonNumber = _seasonNumber)
.And(e => e.Path = Guid.NewGuid().ToString())
.Build();
files.Add(epFile);
}
}
}
repo.AddMany(episodes);
repo.AddMany(files);
} }
} }
[Test] [Test]
public void Insert_into_episodes() public void get_episode_by_series_seasons_episode_x1000()
{ {
var repo = MockLib.GetEmptyRepository(); var epProvider = new EpisodeProvider(repo, null);
Thread.Sleep(1000); Thread.Sleep(1000);
var random = new Random();
Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
repo.AddMany(episodes); for (int i = 0; i < 1000; i++)
{
epProvider.GetEpisode(6, random.Next(2, 5), random.Next(2, Episodes_Per_Season - 10)).Should().NotBeNull();
}
sw.Stop(); sw.Stop();
Console.WriteLine("Adding " + COUNT + " items at once took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
} }
[Test] [Test]
public void Insert_into_episodes_single() public void get_episode_by_series_seasons_x500()
{ {
var repo = MockLib.GetEmptyRepository(); var epProvider = new EpisodeProvider(repo, null);
Thread.Sleep(1000); Thread.Sleep(1000);
var sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
var random = new Random();
Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew();
for (int i = 0; i < 500; i++)
{ {
repo.Add(episodes[i]); epProvider.GetEpisodesBySeason(6, random.Next(2, 5)).Should().NotBeNull();
} }
sw.Stop(); sw.Stop();
Console.WriteLine("Adding " + 100 + " single items took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
} }
[Test] [Test]
public void get_episode_file() public void get_episode_file_count_x50()
{ {
var repo = MockLib.GetEmptyRepository(); var mocker = new AutoMoq.AutoMoqer();
mocker.SetConstant(repo);
repo.AddMany(episodes); mocker.SetConstant(mocker.Resolve<EpisodeProvider>());
repo.AddMany(files); var mediaProvider = mocker.Resolve<MediaFileProvider>();
//var repoEpisodes = repo.All<Episode>().ToList();
Thread.Sleep(1000); Thread.Sleep(1000);
var count = 0;
var random = new Random(); var random = new Random();
Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
for (int i = 0; i < 50; i++)
for (int i = 5000; i < 5000 + 1000; i++)
{ {
count++; mediaProvider.GetEpisodeFilesCount(random.Next(1, 5)).Should().NotBeNull();
var file = repo.Single<Episode>(random.Next(10, COUNT - 100)).EpisodeFile;
} }
sw.Stop(); sw.Stop();
Console.WriteLine("Getting " + count + " episode files took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
} }
} }
} }

@ -78,7 +78,6 @@ namespace NzbDrone.Core
_kernel.Bind<TvDbProvider>().ToSelf().InTransientScope(); _kernel.Bind<TvDbProvider>().ToSelf().InTransientScope();
_kernel.Bind<HttpProvider>().ToSelf().InSingletonScope(); _kernel.Bind<HttpProvider>().ToSelf().InSingletonScope();
_kernel.Bind<SeriesProvider>().ToSelf().InSingletonScope(); _kernel.Bind<SeriesProvider>().ToSelf().InSingletonScope();
_kernel.Bind<SeasonProvider>().ToSelf().InSingletonScope();
_kernel.Bind<EpisodeProvider>().ToSelf().InSingletonScope(); _kernel.Bind<EpisodeProvider>().ToSelf().InSingletonScope();
_kernel.Bind<UpcomingEpisodesProvider>().ToSelf().InSingletonScope(); _kernel.Bind<UpcomingEpisodesProvider>().ToSelf().InSingletonScope();
_kernel.Bind<DiskProvider>().ToSelf().InSingletonScope(); _kernel.Bind<DiskProvider>().ToSelf().InSingletonScope();
@ -138,7 +137,6 @@ namespace NzbDrone.Core
private static void ForceMigration(IRepository repository) private static void ForceMigration(IRepository repository)
{ {
repository.All<Series>().Count(); repository.All<Series>().Count();
repository.All<Season>().Count();
repository.All<Episode>().Count(); repository.All<Episode>().Count();
repository.All<EpisodeFile>().Count(); repository.All<EpisodeFile>().Count();
repository.All<QualityProfile>().Count(); repository.All<QualityProfile>().Count();

@ -98,6 +98,23 @@ namespace NzbDrone.Core.Datastore
var jobTable = repoProvider.GetSchemaFromType(typeof(JobSetting)); var jobTable = repoProvider.GetSchemaFromType(typeof(JobSetting));
Database.RemoveTable(jobTable.Name); Database.RemoveTable(jobTable.Name);
}
public override void Down()
{
throw new NotImplementedException();
}
}
[Migration(20110603)]
public class Migration20110603 : Migration
{
public override void Up()
{
if(Database.TableExists("Seasons"))
{
Database.RemoveTable("Seasons");
}
Migrations.RemoveDeletedColumns(Database); Migrations.RemoveDeletedColumns(Database);
Migrations.AddNewColumns(Database); Migrations.AddNewColumns(Database);

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Instrumentation
private static void DbAction(string value) private static void DbAction(string value)
{ {
Logger.Trace(value); Logger.Trace(value.Replace("`t0`.", ""));
} }
} }
} }

@ -231,14 +231,12 @@
<Compile Include="Providers\EpisodeProvider.cs" /> <Compile Include="Providers\EpisodeProvider.cs" />
<Compile Include="Providers\Core\HttpProvider.cs" /> <Compile Include="Providers\Core\HttpProvider.cs" />
<Compile Include="Providers\SabProvider.cs" /> <Compile Include="Providers\SabProvider.cs" />
<Compile Include="Providers\SeasonProvider.cs" />
<Compile Include="Repository\Episode.cs" /> <Compile Include="Repository\Episode.cs" />
<Compile Include="Instrumentation\Log.cs" /> <Compile Include="Instrumentation\Log.cs" />
<Compile Include="Repository\History.cs" /> <Compile Include="Repository\History.cs" />
<Compile Include="Repository\Config.cs" /> <Compile Include="Repository\Config.cs" />
<Compile Include="Repository\Quality\QualityProfile.cs" /> <Compile Include="Repository\Quality\QualityProfile.cs" />
<Compile Include="Repository\RootDir.cs" /> <Compile Include="Repository\RootDir.cs" />
<Compile Include="Repository\Season.cs" />
<Compile Include="Repository\Quality\QualityTypes.cs" /> <Compile Include="Repository\Quality\QualityTypes.cs" />
<Compile Include="Repository\Series.cs" /> <Compile Include="Repository\Series.cs" />
<Compile Include="CentralDispatch.cs" /> <Compile Include="CentralDispatch.cs" />

@ -10,16 +10,14 @@ namespace NzbDrone.Core.Providers
public class InventoryProvider public class InventoryProvider
{ {
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly SeasonProvider _seasonProvider;
private readonly EpisodeProvider _episodeProvider; private readonly EpisodeProvider _episodeProvider;
private readonly HistoryProvider _historyProvider; private readonly HistoryProvider _historyProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public InventoryProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, EpisodeProvider episodeProvider, HistoryProvider historyProvider) public InventoryProvider(SeriesProvider seriesProvider, EpisodeProvider episodeProvider, HistoryProvider historyProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
_episodeProvider = episodeProvider; _episodeProvider = episodeProvider;
_historyProvider = historyProvider; _historyProvider = historyProvider;
} }
@ -49,12 +47,6 @@ namespace NzbDrone.Core.Providers
return false; return false;
} }
if (_seasonProvider.IsIgnored(series.SeriesId, parseResult.SeasonNumber))
{
Logger.Debug("Season {0} is currently set to ignore. skipping.", parseResult.SeasonNumber);
return false;
}
foreach (var episodeNumber in parseResult.EpisodeNumbers) foreach (var episodeNumber in parseResult.EpisodeNumbers)
{ {
var episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, episodeNumber); var episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, episodeNumber);

@ -16,7 +16,6 @@ namespace NzbDrone.Core.Providers.Jobs
{ {
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
private readonly SeasonProvider _seasonProvider;
private readonly UpdateInfoJob _updateInfoJob; private readonly UpdateInfoJob _updateInfoJob;
private readonly DiskScanJob _diskScanJob; private readonly DiskScanJob _diskScanJob;
@ -24,13 +23,12 @@ namespace NzbDrone.Core.Providers.Jobs
private List<int> _attemptedSeries; private List<int> _attemptedSeries;
public ImportNewSeriesJob(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public ImportNewSeriesJob(SeriesProvider seriesProvider,
MediaFileProvider mediaFileProvider, UpdateInfoJob updateInfoJob, DiskScanJob diskScanJob) MediaFileProvider mediaFileProvider, UpdateInfoJob updateInfoJob, DiskScanJob diskScanJob)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
_seasonProvider = seasonProvider; _updateInfoJob = updateInfoJob;
_updateInfoJob = updateInfoJob;
_diskScanJob = diskScanJob; _diskScanJob = diskScanJob;
} }
@ -84,9 +82,22 @@ namespace NzbDrone.Core.Providers.Jobs
private void AutoIgnoreSeasons(Series updatedSeries) private void AutoIgnoreSeasons(Series updatedSeries)
{ {
if (_mediaFileProvider.GetSeriesFiles(updatedSeries.SeriesId).Count() != 0) var episodeFiles = _mediaFileProvider.GetSeriesFiles(updatedSeries.SeriesId);
var episodes = updatedSeries.Episodes;
if (episodeFiles.Count() != 0)
{ {
Logger.Debug("Looking for seasons to ignore"); var seasons = episodes.Select(c => c.SeasonNumber).Distinct();
var currentSeasons = seasons.Max();
foreach (var season in seasons)
{
if (season!=currentSeasons )
{
}
}
/* Logger.Debug("Looking for seasons to ignore");
foreach (var season in updatedSeries.Seasons) foreach (var season in updatedSeries.Seasons)
{ {
if (season.SeasonNumber != updatedSeries.Seasons.Max(s => s.SeasonNumber) && _mediaFileProvider.GetSeasonFiles(season.SeasonId).Count() == 0) if (season.SeasonNumber != updatedSeries.Seasons.Max(s => s.SeasonNumber) && _mediaFileProvider.GetSeasonFiles(season.SeasonId).Count() == 0)
@ -95,7 +106,7 @@ namespace NzbDrone.Core.Providers.Jobs
season.Monitored = false; season.Monitored = false;
_seasonProvider.SaveSeason(season); _seasonProvider.SaveSeason(season);
} }
} }*/
} }
} }
} }

@ -16,17 +16,15 @@ namespace NzbDrone.Core.Providers
private readonly DiskProvider _diskProvider; private readonly DiskProvider _diskProvider;
private readonly EpisodeProvider _episodeProvider; private readonly EpisodeProvider _episodeProvider;
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly SeasonProvider _seasonProvider;
private readonly IRepository _repository; private readonly IRepository _repository;
public MediaFileProvider(IRepository repository, DiskProvider diskProvider, public MediaFileProvider(IRepository repository, DiskProvider diskProvider,
EpisodeProvider episodeProvider, SeriesProvider seriesProvider, SeasonProvider seasonProvider) EpisodeProvider episodeProvider, SeriesProvider seriesProvider)
{ {
_repository = repository; _repository = repository;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_episodeProvider = episodeProvider; _episodeProvider = episodeProvider;
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
} }
public MediaFileProvider() { } public MediaFileProvider() { }
@ -125,6 +123,7 @@ namespace NzbDrone.Core.Providers
episodeFile.Size = size; episodeFile.Size = size;
episodeFile.Quality = parseResult.Quality.QualityType; episodeFile.Quality = parseResult.Quality.QualityType;
episodeFile.Proper = parseResult.Quality.Proper; episodeFile.Proper = parseResult.Quality.Proper;
episodeFile.SeasonNumber = parseResult.SeasonNumber;
var fileId = (int)_repository.Add(episodeFile); var fileId = (int)_repository.Add(episodeFile);
//This is for logging + updating the episodes that are linked to this EpisodeFile //This is for logging + updating the episodes that are linked to this EpisodeFile
@ -183,25 +182,19 @@ namespace NzbDrone.Core.Providers
return _repository.All<EpisodeFile>().ToList(); return _repository.All<EpisodeFile>().ToList();
} }
public virtual IEnumerable<EpisodeFile> GetSeasonFiles(int seasonId)
{
return _seasonProvider.GetSeason(seasonId).Episodes.Where(c => c.EpisodeFile != null).Select(c => c.EpisodeFile);
}
public virtual IEnumerable<EpisodeFile> GetSeriesFiles(int seriesId) public virtual IEnumerable<EpisodeFile> GetSeriesFiles(int seriesId)
{ {
return _seriesProvider.GetSeries(seriesId).Episodes.Where(c => c.EpisodeFile != null).Select(c => c.EpisodeFile); return _repository.All<EpisodeFile>().Where(c => c.SeriesId == seriesId);
} }
public virtual Tuple<int, int> GetEpisodeFilesCount(int seriesId) public virtual Tuple<int, int> GetEpisodeFilesCount(int seriesId)
{ {
var series = _seriesProvider.GetSeries(seriesId); var allEpisodes = _episodeProvider.GetEpisodeBySeries(seriesId);
var monitoredSeasons = series.Seasons.Where(e => e.Monitored).Select(e => e.SeasonId); var episodeTotal = allEpisodes.Where(e => !e.Ignored && e.AirDate <= DateTime.Today && e.AirDate.Year > 1900).ToList();
var episodeTotal = series.Episodes.Where(e => monitoredSeasons.Contains(e.SeasonId) && e.AirDate <= DateTime.Today && e.AirDate > new DateTime(1899, 12, 31)); var avilableEpisodes = episodeTotal.Where(e => e.EpisodeFileId > 0);
var episodes = episodeTotal.Where(e => e.EpisodeFileId > 0);
return new Tuple<int, int>(episodeTotal.Count(), episodes.Count()); return new Tuple<int, int>(episodeTotal.Count, avilableEpisodes.Count());
} }
private List<string> GetMediaFileList(string path) private List<string> GetMediaFileList(string path)

@ -19,19 +19,17 @@ namespace NzbDrone.Core.Providers
private readonly DiskProvider _diskProvider; private readonly DiskProvider _diskProvider;
private readonly EpisodeProvider _episodeProvider; private readonly EpisodeProvider _episodeProvider;
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
private readonly SeasonProvider _seasonProvider;
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly List<EpisodeRenameModel> _epsToRename = new List<EpisodeRenameModel>(); private readonly List<EpisodeRenameModel> _epsToRename = new List<EpisodeRenameModel>();
private Thread _renameThread; private Thread _renameThread;
public RenameProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public RenameProvider(SeriesProvider seriesProvider,
EpisodeProvider episodeProvider, MediaFileProvider mediaFileProvider, EpisodeProvider episodeProvider, MediaFileProvider mediaFileProvider,
DiskProvider diskProvider, ConfigProvider configProvider) DiskProvider diskProvider, ConfigProvider configProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
_episodeProvider = episodeProvider; _episodeProvider = episodeProvider;
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
_diskProvider = diskProvider; _diskProvider = diskProvider;
@ -45,7 +43,7 @@ namespace NzbDrone.Core.Providers
foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles()) foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles())
{ {
var series = _seriesProvider.GetSeries(episodeFile.SeriesId); var series = _seriesProvider.GetSeries(episodeFile.SeriesId);
var erm = new EpisodeRenameModel {SeriesName = series.Title, Folder = series.Path}; var erm = new EpisodeRenameModel { SeriesName = series.Title, Folder = series.Path };
if (series.SeasonFolder) if (series.SeasonFolder)
erm.Folder += Path.DirectorySeparatorChar + erm.Folder += Path.DirectorySeparatorChar +
@ -68,7 +66,7 @@ namespace NzbDrone.Core.Providers
foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles().Where(s => s.SeriesId == seriesId)) foreach (var episodeFile in _mediaFileProvider.GetEpisodeFiles().Where(s => s.SeriesId == seriesId))
{ {
var erm = new EpisodeRenameModel {SeriesName = series.Title, Folder = series.Path}; var erm = new EpisodeRenameModel { SeriesName = series.Title, Folder = series.Path };
if (series.SeasonFolder) if (series.SeasonFolder)
erm.Folder += Path.DirectorySeparatorChar + erm.Folder += Path.DirectorySeparatorChar +
@ -85,26 +83,7 @@ namespace NzbDrone.Core.Providers
public virtual void RenameSeason(int seasonId) public virtual void RenameSeason(int seasonId)
{ {
//Get a list of all applicable episode files/episodes and rename them throw new NotImplementedException();
var season = _seasonProvider.GetSeason(seasonId);
var series = _seriesProvider.GetSeries(season.SeriesId);
foreach (
var episodeFile in _mediaFileProvider.GetEpisodeFiles().Where(s => s.Episodes[0].SeasonId == seasonId))
{
var erm = new EpisodeRenameModel {SeriesName = series.Title, Folder = series.Path};
if (series.SeasonFolder)
erm.Folder += Path.DirectorySeparatorChar +
EpisodeRenameHelper.GetSeasonFolder(episodeFile.Episodes[0].SeasonNumber,
_configProvider.GetValue(
"Sorting_SeasonFolderFormat", "Season %s",
true));
erm.EpisodeFile = episodeFile;
_epsToRename.Add(erm);
StartRename();
}
} }
public virtual void RenameEpisode(int episodeId) public virtual void RenameEpisode(int episodeId)
@ -116,7 +95,7 @@ namespace NzbDrone.Core.Providers
var episodeFile = var episodeFile =
_mediaFileProvider.GetEpisodeFiles().Where(s => s.Episodes.Contains(episode)).FirstOrDefault(); _mediaFileProvider.GetEpisodeFiles().Where(s => s.Episodes.Contains(episode)).FirstOrDefault();
var erm = new EpisodeRenameModel {SeriesName = series.Title, Folder = series.Path}; var erm = new EpisodeRenameModel { SeriesName = series.Title, Folder = series.Path };
if (series.SeasonFolder) if (series.SeasonFolder)
erm.Folder += Path.DirectorySeparatorChar + erm.Folder += Path.DirectorySeparatorChar +
@ -135,7 +114,7 @@ namespace NzbDrone.Core.Providers
var episodeFile = _mediaFileProvider.GetEpisodeFile(episodeFileId); var episodeFile = _mediaFileProvider.GetEpisodeFile(episodeFileId);
var series = _seriesProvider.GetSeries(episodeFile.Series.SeriesId); var series = _seriesProvider.GetSeries(episodeFile.Series.SeriesId);
var erm = new EpisodeRenameModel {SeriesName = series.Title, Folder = series.Path}; var erm = new EpisodeRenameModel { SeriesName = series.Title, Folder = series.Path };
if (series.SeasonFolder) if (series.SeasonFolder)
erm.Folder += Path.DirectorySeparatorChar + erm.Folder += Path.DirectorySeparatorChar +

@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Repository;
using SubSonic.Repository;
namespace NzbDrone.Core.Providers
{
public class SeasonProvider
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IRepository _repository;
public SeasonProvider(IRepository repository)
{
_repository = repository;
}
public SeasonProvider()
{
}
public virtual Season GetSeason(int seasonId)
{
return _repository.Single<Season>(seasonId);
}
public virtual Season GetSeason(int seriesId, int seasonNumber)
{
return _repository.Single<Season>(s => s.SeriesId == seriesId && s.SeasonNumber == seasonNumber);
}
public virtual List<Season> GetSeasons(int seriesId)
{
return _repository.All<Season>().Where(s => s.SeriesId == seriesId).ToList();
}
public virtual Season GetLatestSeason(int seriesId)
{
return _repository.All<Season>().Where(s => s.SeriesId == seriesId).OrderBy(s => s.SeasonNumber).Last();
}
public virtual void EnsureSeason(int seriesId, int seasonId, int seasonNumber)
{
if (_repository.Exists<Season>(s => s.SeasonId == seasonId))
return;
//TODO: Calculate Season Folder
Logger.Trace("Adding Season To DB. [SeriesID:{0} SeasonID:{1} SeasonNumber:{2}]", seriesId, seasonId,
seasonNumber, "????");
var newSeason = new Season
{
Monitored = true,
SeasonId = seasonId,
SeasonNumber = seasonNumber,
SeriesId = seriesId
};
_repository.Add(newSeason);
}
public virtual int SaveSeason(Season season)
{
if (_repository.Exists<Season>(s => s.SeasonId == season.SeasonId))
{
return _repository.Update(season);
}
return (int)_repository.Add(season);
}
public virtual bool IsIgnored(int seasonId)
{
if (_repository.Single<Season>(seasonId).Monitored)
return false;
Logger.Debug("Season {0} is not wanted.");
return true;
}
public virtual bool IsIgnored(int seriesId, int seasonNumber)
{
var season = _repository.Single<Season>(s => s.SeriesId == seriesId && s.SeasonNumber == seasonNumber);
return !season.Monitored;
}
public void DeleteSeason(int seasonId)
{
_repository.Delete<Season>(seasonId);
}
}
}

@ -41,7 +41,7 @@ namespace NzbDrone.Core.Providers
public virtual Series GetSeries(int seriesId) public virtual Series GetSeries(int seriesId)
{ {
return _repository.Single<Series>(s => s.SeriesId == seriesId); return _repository.Single<Series>(seriesId);
} }
/// <summary> /// <summary>
@ -124,7 +124,7 @@ namespace NzbDrone.Core.Providers
Logger.Warn("Deleting Series [{0}]", seriesId); Logger.Warn("Deleting Series [{0}]", seriesId);
var series = _repository.Single<Series>(seriesId); var series = _repository.Single<Series>(seriesId);
//Delete Files, Episdes, Seasons then the Series //Delete Files, Episodes, Seasons then the Series
//Can't use providers because episode provider needs series provider - Cyclic Dependency Injection, this will work //Can't use providers because episode provider needs series provider - Cyclic Dependency Injection, this will work
//Delete History Items for any episodes that belong to this series //Delete History Items for any episodes that belong to this series
@ -140,10 +140,6 @@ namespace NzbDrone.Core.Providers
Logger.Debug("Deleting Episodes from DB for Series: {0}", series.SeriesId); Logger.Debug("Deleting Episodes from DB for Series: {0}", series.SeriesId);
_repository.DeleteMany(series.Episodes); _repository.DeleteMany(series.Episodes);
//Delete seasons for this series from the DB
Logger.Debug("Deleting Seasons from DB for Series: {0}", series.SeriesId);
_repository.DeleteMany(series.Seasons);
//Delete the Series //Delete the Series
Logger.Debug("Deleting Series from DB {0}", series.Title); Logger.Debug("Deleting Series from DB {0}", series.Title);
_repository.Delete<Series>(seriesId); _repository.Delete<Series>(seriesId);

@ -6,7 +6,7 @@ using SubSonic.SqlGeneration.Schema;
namespace NzbDrone.Core.Repository namespace NzbDrone.Core.Repository
{ {
public class Episode public class Episode
{ {
[SubSonicPrimaryKey] [SubSonicPrimaryKey]
public virtual int EpisodeId { get; set; } public virtual int EpisodeId { get; set; }
@ -15,7 +15,6 @@ namespace NzbDrone.Core.Repository
public virtual int SeriesId { get; set; } public virtual int SeriesId { get; set; }
public virtual int EpisodeFileId { get; set; } public virtual int EpisodeFileId { get; set; }
public virtual int SeasonId { get; set; }
public virtual int SeasonNumber { get; set; } public virtual int SeasonNumber { get; set; }
public virtual int EpisodeNumber { get; set; } public virtual int EpisodeNumber { get; set; }
public virtual string Title { get; set; } public virtual string Title { get; set; }
@ -56,10 +55,9 @@ namespace NzbDrone.Core.Repository
if (EpisodeFileId != 0) return EpisodeStatusType.Ready; if (EpisodeFileId != 0) return EpisodeStatusType.Ready;
var season = Season;
if (Ignored || (season != null && !season.Monitored)) return EpisodeStatusType.Ignored; if (Ignored) return EpisodeStatusType.Ignored;
if (AirDate.Date.Year > 1900 && DateTime.Now.Date >= AirDate.Date) if (AirDate.Date.Year > 1900 && DateTime.Now.Date >= AirDate.Date)
{ {
return EpisodeStatusType.Missing; return EpisodeStatusType.Missing;
@ -69,9 +67,6 @@ namespace NzbDrone.Core.Repository
} }
} }
[SubSonicToOneRelation(ThisClassContainsJoinKey = true)]
public virtual Season Season { get; set; }
[SubSonicToOneRelation(ThisClassContainsJoinKey = true)] [SubSonicToOneRelation(ThisClassContainsJoinKey = true)]
public virtual Series Series { get; set; } public virtual Series Series { get; set; }

@ -11,6 +11,7 @@ namespace NzbDrone.Core.Repository
public virtual int EpisodeFileId { get; set; } public virtual int EpisodeFileId { get; set; }
public virtual int SeriesId { get; set; } public virtual int SeriesId { get; set; }
public virtual int SeasonNumber { get; set; }
public string Path { get; set; } public string Path { get; set; }
public QualityTypes Quality { get; set; } public QualityTypes Quality { get; set; }
public bool Proper { get; set; } public bool Proper { get; set; }

@ -16,8 +16,6 @@ namespace NzbDrone.Core.Repository.Quality
[DisplayFormat(ConvertEmptyStringToNull = false)] [DisplayFormat(ConvertEmptyStringToNull = false)]
public string Name { get; set; } public string Name { get; set; }
public bool UserProfile { get; set; } //Allows us to tell the difference between default and user profiles
[SubSonicIgnore] [SubSonicIgnore]
[DisplayName("Allowed Qualities")] [DisplayName("Allowed Qualities")]
public List<QualityTypes> Allowed { get; set; } public List<QualityTypes> Allowed { get; set; }

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using SubSonic.SqlGeneration.Schema;
namespace NzbDrone.Core.Repository
{
public class Season
{
[SubSonicPrimaryKey(false)]
public virtual int SeasonId { get; set; }
public virtual int SeriesId { get; set; }
public virtual int SeasonNumber { get; set; }
public bool Monitored { get; set; }
public DayOfWeek? LastInfoSync { get; set; }
public DayOfWeek? LastDiskSync { get; set; }
[SubSonicToManyRelation]
public virtual IList<Episode> Episodes { get; set; }
[SubSonicToOneRelation(ThisClassContainsJoinKey = true)]
public virtual Series Series { get; set; }
}
}

@ -56,9 +56,6 @@ namespace NzbDrone.Core.Repository
[SubSonicToOneRelation(ThisClassContainsJoinKey = true, JoinKeyName = "QualityProfileId")] [SubSonicToOneRelation(ThisClassContainsJoinKey = true, JoinKeyName = "QualityProfileId")]
public virtual QualityProfile QualityProfile { get; set; } public virtual QualityProfile QualityProfile { get; set; }
[SubSonicToManyRelation]
public virtual IList<Season> Seasons { get; protected set; }
[SubSonicToManyRelation] [SubSonicToManyRelation]
public virtual IList<Episode> Episodes { get; set; } public virtual IList<Episode> Episodes { get; set; }

@ -20,7 +20,6 @@ namespace NzbDrone.Web.Controllers
private readonly SeriesProvider _seriesProvider; private readonly SeriesProvider _seriesProvider;
private readonly TvDbProvider _tvDbProvider; private readonly TvDbProvider _tvDbProvider;
private readonly JobProvider _jobProvider; private readonly JobProvider _jobProvider;
private readonly SeasonProvider _seasonProvider;
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
// //
// GET: /Series/ // GET: /Series/
@ -31,7 +30,6 @@ namespace NzbDrone.Web.Controllers
RenameProvider renameProvider, RenameProvider renameProvider,
TvDbProvider tvDbProvider, TvDbProvider tvDbProvider,
JobProvider jobProvider, JobProvider jobProvider,
SeasonProvider seasonProvider,
MediaFileProvider mediaFileProvider) MediaFileProvider mediaFileProvider)
{ {
_seriesProvider = seriesProvider; _seriesProvider = seriesProvider;
@ -40,7 +38,6 @@ namespace NzbDrone.Web.Controllers
_renameProvider = renameProvider; _renameProvider = renameProvider;
_tvDbProvider = tvDbProvider; _tvDbProvider = tvDbProvider;
_jobProvider = jobProvider; _jobProvider = jobProvider;
_seasonProvider = seasonProvider;
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
} }
@ -60,14 +57,21 @@ namespace NzbDrone.Web.Controllers
public ActionResult SeasonEditor(int seriesId) public ActionResult SeasonEditor(int seriesId)
{ {
var model = var model = new List<SeasonEditModel>();
_seriesProvider.GetSeries(seriesId).Seasons.Select(s => new SeasonEditModel
{ var seasons = _episodeProvider.GetSeasons(seriesId);
SeasonId = s.SeasonId,
SeasonNumber = s.SeasonNumber, foreach (var season in seasons)
SeasonString = GetSeasonString(s.SeasonNumber), {
Monitored = s.Monitored var seasonEdit = new SeasonEditModel();
}).OrderBy(s => s.SeasonNumber).ToList(); seasonEdit.Monitored = !_episodeProvider.IsIgnored(seriesId, season);
seasonEdit.SeasonNumber = season;
seasonEdit.SeriesId = seriesId;
seasonEdit.SeasonString = GetSeasonString(season);
model.Add(seasonEdit);
}
return View(model); return View(model);
} }
@ -117,9 +121,9 @@ namespace NzbDrone.Web.Controllers
} }
[GridAction] [GridAction]
public ActionResult _AjaxSeasonGrid(int seasonId) public ActionResult _AjaxSeasonGrid(int seriesId, int seasonNumber)
{ {
var episodes = _episodeProvider.GetEpisodeBySeason(seasonId).Select(c => new EpisodeModel var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber).Select(c => new EpisodeModel
{ {
EpisodeId = c.EpisodeId, EpisodeId = c.EpisodeId,
EpisodeNumber = c.EpisodeNumber, EpisodeNumber = c.EpisodeNumber,
@ -190,9 +194,10 @@ namespace NzbDrone.Web.Controllers
{ {
foreach (var season in seasons) foreach (var season in seasons)
{ {
var seasonInDb = _seasonProvider.GetSeason(season.SeasonId); if (_episodeProvider.IsIgnored(season.SeriesId, season.SeasonNumber) != !season.Monitored)
seasonInDb.Monitored = season.Monitored; {
_seasonProvider.SaveSeason(seasonInDb); _episodeProvider.SetSeasonIgnore(season.SeriesId, season.SeasonNumber, !season.Monitored);
}
} }
return Content("Saved"); return Content("Saved");
@ -201,7 +206,23 @@ namespace NzbDrone.Web.Controllers
public ActionResult Details(int seriesId) public ActionResult Details(int seriesId)
{ {
var series = _seriesProvider.GetSeries(seriesId); var series = _seriesProvider.GetSeries(seriesId);
return View(series);
var model = new SeriesModel();
if (series.AirsDayOfWeek != null)
{
model.AirsDayOfWeek = series.AirsDayOfWeek.Value.ToString();
}
else
{
model.AirsDayOfWeek = "N/A";
}
model.Overview = series.Overview;
model.Seasons = _episodeProvider.GetSeasons(seriesId);
model.Title = series.Status;
model.SeriesId = series.SeriesId;
return View(model);
} }
public ActionResult SyncEpisodesOnDisk(int seriesId) public ActionResult SyncEpisodesOnDisk(int seriesId)
@ -261,11 +282,8 @@ namespace NzbDrone.Web.Controllers
Path = s.Path, Path = s.Path,
QualityProfileId = s.QualityProfileId, QualityProfileId = s.QualityProfileId,
QualityProfileName = s.QualityProfile.Name, QualityProfileName = s.QualityProfile.Name,
SeasonsCount = s.Seasons.Where(x => x.SeasonNumber > 0).Count(),
SeasonFolder = s.SeasonFolder, SeasonFolder = s.SeasonFolder,
Status = s.Status, Status = s.Status,
Episodes = 0,
EpisodeTotal = 0
}); });
} }

@ -7,7 +7,7 @@ namespace NzbDrone.Web.Models
{ {
public class SeasonEditModel public class SeasonEditModel
{ {
public int SeasonId { get; set; } public int SeriesId { get; set; }
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public string SeasonString { get; set; } public string SeasonString { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }

@ -19,7 +19,8 @@ namespace NzbDrone.Web.Models
public string QualityProfileName { get; set; } public string QualityProfileName { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public int Episodes { get; set; } public int Episodes { get; set; }
public int EpisodeTotal { get; set; }
public IList<int> Seasons { get; set; }
//View & Edit //View & Edit
[DisplayName("Path")] [DisplayName("Path")]

@ -1,4 +1,4 @@
@model NzbDrone.Core.Repository.Series @model NzbDrone.Web.Models.SeriesModel
@using NzbDrone.Core.Repository @using NzbDrone.Core.Repository
@using NzbDrone.Web.Models @using NzbDrone.Web.Models
@section TitleContent{ @section TitleContent{
@ -31,68 +31,66 @@
<div class="display-label"> <div class="display-label">
AirTimes</div> AirTimes</div>
<div class="display-field"> <div class="display-field">
@Model.AirTimes</div> @Model.AirsDayOfWeek.ToString()</div>
<div class="display-label"> <div class="display-label">
Language</div> Language</div>
<div class="display-field">
@Model.Language.ToUpper()</div>
<div class="display-label"> <div class="display-label">
Location</div> Location</div>
<div class="display-field"> <div class="display-field">
@Model.Path</div> @Model.Path</div>
</fieldset> </fieldset>
@*Todo: This breaks when using SQLServer... thoughts?*@ @*Todo: This breaks when using SQLServer... thoughts?*@ @*Easy, don't use SQL Server!!!*@
@foreach (var season in Model.Seasons.Where(s => s.SeasonNumber > 0).Reverse()) @foreach (var season in Model.Seasons.Where(s => s > 0).Reverse())
{ {
<br /> <br />
<h3> <h3>
Season @season.SeasonNumber</h3> Season @season</h3>
<div class="grid-container"> <div class="grid-container">
@{Season season1 = season; @{
Html.Telerik().Grid<EpisodeModel>().Name("seasons_" + season.SeasonNumber) Html.Telerik().Grid<EpisodeModel>().Name("seasons_" + season)
.TableHtmlAttributes(new { @class = "Grid" }) .TableHtmlAttributes(new { @class = "Grid" })
.Columns(columns => .Columns(columns =>
{ {
columns.Bound(o => o.EpisodeId) columns.Bound(o => o.EpisodeId)
.ClientTemplate( .ClientTemplate(
"<input type='checkbox' name='checkedEpisodes' value='<#= EpisodeId #>' />") "<input type='checkbox' name='checkedEpisodes' value='<#= EpisodeId #>' />")
.Title("") .Title("")
.Width(1) .Width(1)
.HtmlAttributes(new { style = "text-align:center" }); .HtmlAttributes(new { style = "text-align:center" });
columns.Bound(c => c.EpisodeNumber).Width(0).Title("Episode"); columns.Bound(c => c.EpisodeNumber).Width(0).Title("Episode");
columns.Bound(c => c.Title).Title("Title"); columns.Bound(c => c.Title).Title("Title");
columns.Bound(c => c.AirDate).Format("{0:d}").Width(0); columns.Bound(c => c.AirDate).Format("{0:d}").Width(0);
columns.Bound(c => c.Quality).Width(0); columns.Bound(c => c.Quality).Width(0);
columns.Bound(c => c.Status).Width(0); columns.Bound(c => c.Status).Width(0);
columns.Bound(o => o.EpisodeId).Title("") columns.Bound(o => o.EpisodeId).Title("")
.ClientTemplate("<a href='#Search' onClick=\"searchForEpisode('<#= EpisodeId #>'); return false;\" >Search</a>"); .ClientTemplate("<a href='#Search' onClick=\"searchForEpisode('<#= EpisodeId #>'); return false;\" >Search</a>");
}) })
.DetailView(detailView => detailView.ClientTemplate("<div><#= Overview #> </br><#= Path #> </div>")) .DetailView(detailView => detailView.ClientTemplate("<div><#= Overview #> </br><#= Path #> </div>"))
.ClientEvents(clientEvents => .ClientEvents(clientEvents =>
{ {
clientEvents.OnDataBinding("grid_bind"); clientEvents.OnDataBinding("grid_bind");
clientEvents.OnDataBound("grid_bound"); clientEvents.OnDataBound("grid_bound");
}) })
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.EpisodeNumber).Descending()).Enabled(true)) .Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.EpisodeNumber).Descending()).Enabled(true))
.Footer(true) .Footer(true)
.DataBinding( .DataBinding(
d => d =>
d.Ajax().Select("_AjaxSeasonGrid", "Series", d.Ajax().Select("_AjaxSeasonGrid", "Series",
new RouteValueDictionary { { "seasonId", season1.SeasonId.ToString() } })) new RouteValueDictionary { { "seriesId", Model.SeriesId }, { "seasonNumber", season } }))
.ToolBar( .ToolBar(
c => c =>
c.Custom().Text("Rename Season").Action("RenameSeason", "Series", new { seasonId = season1.SeasonId }) c.Custom().Text("Rename Season").Action("RenameSeason", "Series", new { seasonId = season })
.ButtonType(GridButtonType.Text)) .ButtonType(GridButtonType.Text))
.Render();} .Render();}
<span class="grid-loader"> <span class="grid-loader">
<img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/> <img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/>
Loading...</span> Loading...</span>
</div> </div>
} }
@{var specialSeasons = Model.Seasons.Where(s => s.SeasonNumber == 0).FirstOrDefault();} @{var specialSeason = Model.Seasons.Where(s => s == 0).FirstOrDefault();}
@if (specialSeasons != null) @if (specialSeason != null)
{ {
<br /> <br />
@ -127,8 +125,8 @@
.DataBinding( .DataBinding(
d => d =>
d.Ajax().Select("_AjaxSeasonGrid", "Series", d.Ajax().Select("_AjaxSeasonGrid", "Series",
new RouteValueDictionary { { "seasonId", specialSeasons.SeasonId.ToString() } })) new RouteValueDictionary { { "seriesId", Model.SeriesId }, { "seasonNumber", specialSeason } }
.Render(); } )).Render(); }
<span class="grid-loader"> <span class="grid-loader">
<img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/> <img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/>
Loading...</span> Loading...</span>

@ -8,7 +8,7 @@
@Html.DisplayFor(m => m.SeasonString) @Html.DisplayFor(m => m.SeasonString)
<span style="float: right;">@Html.CheckBoxFor(m => m.Monitored, new { @class = "chkbox" })</span> <span style="float: right;">@Html.CheckBoxFor(m => m.Monitored, new { @class = "chkbox" })</span>
@Html.HiddenFor(m => m.SeasonId) @Html.HiddenFor(m => m.SeasonNumber)
@Html.HiddenFor(m => m.SeasonNumber) @Html.HiddenFor(m => m.SeasonNumber)
</fieldset> </fieldset>
} }

@ -2,17 +2,30 @@
@using System.Collections @using System.Collections
@using NzbDrone.Core.Repository.Quality @using NzbDrone.Core.Repository.Quality
@using NzbDrone.Web.Helpers @using NzbDrone.Web.Helpers
@{ @{
Layout = null; Layout = null;
} }
<style> <style>
.quality-selectee { width: 75px; padding: 1px; padding-left: 3px; padding-right: 3px; margin: 2px; float: left; cursor: default; } .quality-selectee
.quality-selecting { background: #85AEF9; } {
.quality-selected { background: #065EFE; color: white; } width: 75px;
padding: 1px;
padding-left: 3px;
padding-right: 3px;
margin: 2px;
float: left;
cursor: default;
}
.quality-selecting
{
background: #85AEF9;
}
.quality-selected
{
background: #065EFE;
color: white;
}
</style> </style>
@using (Html.BeginCollectionItem("Profiles")) @using (Html.BeginCollectionItem("Profiles"))
{ {
var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_'); var idClean = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_');
@ -25,27 +38,26 @@
string cutoff = String.Format("{0}_Cutoff", idClean); string cutoff = String.Format("{0}_Cutoff", idClean);
<div class="profileSectionEditor" id="profile_@(ViewData["ProfileId"])" style="float: left; height: 175px; width: 285px; margin-bottom: -14px;"> <div class="profileSectionEditor" id="profile_@(ViewData["ProfileId"])" style="float: left; height: 175px; width: 285px; margin-bottom: -14px;">
<fieldset style="width: 264px; margin: 5px; margin-top: 0px; border-color: #CCCCCD">
<fieldset style="width:264px; margin:5px; margin-top: 0px; border-color:#CCCCCD">
<div class="header"> <div class="header">
<div id="qualityHeader" style="padding-bottom: 5px; margin: 0px;"> <div id="qualityHeader" style="padding-bottom: 5px; margin: 0px;">
<h2 style="display:inline; padding-right: 4px; margin-left: 4px;" id="@title">@{Html.DisplayTextFor(m => m.Name);}</h2> <h2 style="display:inline; padding-right: 4px; margin-left: 4px;" id="@title">
<a href="#" id="@Model.QualityProfileId" class="deleteRow" onclick="deleteProfile('@ViewData["ProfileId"]'); return false;" style="float:right; padding-top:8px; padding-right: 5px;"><img src="../../Content/Images/X.png" alt="Delete" width="20px" height="20px"/></a> @{Html.DisplayTextFor(m => m.Name);}
</h2>
<a href="#" id="@Model.QualityProfileId" class="deleteRow" onclick="deleteProfile('@ViewData["ProfileId"]'); return false;" style="float:right; padding-top:8px; padding-right: 5px;">
<img src="../../Content/Images/X.png" alt="Delete" width="20px" height="20px" /></a>
</div> </div>
<div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;"> <div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;">
<div class="config-title">@Html.LabelFor(x => x.Name)</div> <div class="config-title">@Html.LabelFor(x => x.Name)</div>
<div class="config-value">@Html.TextBoxFor(x => x.Name, new { maxlength = 15 })</div> <div class="config-value">@Html.TextBoxFor(x => x.Name, new { maxlength = 15 })</div>
<div class="config-validation">@Html.ValidationMessageFor(x => x.Name)</div> <div class="config-validation">@Html.ValidationMessageFor(x => x.Name)</div>
</div> </div>
<div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;"> <div class="config-group" style="width: 255px; margin-bottom: 5px; margin-left: 5px;">
<div class="config-title">@Html.LabelFor(x => x.Cutoff)</div> <div class="config-title">@Html.LabelFor(x => x.Cutoff)</div>
<div class="config-value">@Html.DropDownListFor(m => m.Cutoff, new SelectList(Model.Allowed, Model.Cutoff))</div> <div class="config-value">@Html.DropDownListFor(m => m.Cutoff, new SelectList(Model.Allowed, Model.Cutoff))</div>
<div class="config-validation">@Html.ValidationMessageFor(x => x.Cutoff)</div> <div class="config-validation">@Html.ValidationMessageFor(x => x.Cutoff)</div>
</div> </div>
</div> </div>
<div class="selectableDiv" style="margin-top: 30px;"> <div class="selectableDiv" style="margin-top: 30px;">
<div id="@selectable"> <div id="@selectable">
@{var qualitiesList = (List<QualityTypes>)ViewData["Qualities"];} @{var qualitiesList = (List<QualityTypes>)ViewData["Qualities"];}
@ -55,12 +67,12 @@
{ {
continue; continue;
} }
if (Model.Allowed != null) if (Model.Allowed != null)
{ {
if (Model.Allowed.Contains(qualitiesList[i])) if (Model.Allowed.Contains(qualitiesList[i]))
{ {
<fieldset class="quality-selectee quality-selected">@qualitiesList[i].ToString()</fieldset> <fieldset class="quality-selectee quality-selected">@qualitiesList[i].ToString()</fieldset>
continue; continue;
} }
} }
@ -69,10 +81,8 @@
} }
</div> </div>
</div> </div>
<div class="hiddenProfileDetails"> <div class="hiddenProfileDetails">
@Html.HiddenFor(x => x.QualityProfileId) @Html.HiddenFor(x => x.QualityProfileId)
@Html.HiddenFor(x => x.UserProfile)
@Html.HiddenFor(m => m.AllowedString) @Html.HiddenFor(m => m.AllowedString)
</div> </div>
</fieldset> </fieldset>
@ -100,13 +110,12 @@
}).keyup(); }).keyup();
$('#@selectable .quality-selectee').click(function () { $('#@selectable .quality-selectee').click(function () {
if ($(this).hasClass('quality-selected')) if ($(this).hasClass('quality-selected')) {
{
$(this).removeClass('quality-selected'); $(this).removeClass('quality-selected');
var toRemove = this.firstChild.data; var toRemove = this.firstChild.data;
$('#@cutoff option').each(function () { if ($(this).text().indexOf(toRemove) > -1) $('#@cutoff option').remove(':contains("' + $(this).text() + '")'); }); $('#@cutoff option').each(function () { if ($(this).text().indexOf(toRemove) > -1) $('#@cutoff option').remove(':contains("' + $(this).text() + '")'); });
} }
else { else {
$(this).addClass('quality-selected'); $(this).addClass('quality-selected');
$('<option>' + this.firstChild.data + '</option>').appendTo('#@cutoff'); $('<option>' + this.firstChild.data + '</option>').appendTo('#@cutoff');

Loading…
Cancel
Save