diff --git a/NzbDrone.Core.Test/EpisodeProviderTest.cs b/NzbDrone.Core.Test/EpisodeProviderTest.cs index 75c99977d..6b39034fc 100644 --- a/NzbDrone.Core.Test/EpisodeProviderTest.cs +++ b/NzbDrone.Core.Test/EpisodeProviderTest.cs @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); } [Test] @@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); } [Test] @@ -107,7 +107,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); episode.EpisodeFile.Should().NotBeNull(); } @@ -769,7 +769,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); episode.EpisodeFile.Should().NotBeNull(); } @@ -792,7 +792,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); episode.EpisodeFile.Should().BeNull(); } @@ -817,7 +817,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); episode.EpisodeFile.Should().NotBeNull(); } @@ -840,7 +840,7 @@ namespace NzbDrone.Core.Test //Assert episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First()); - episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount).EqualTo(fakeSeries); + episode.Series.ShouldHave().AllPropertiesBut(s => s.EpisodeCount, s => s.EpisodeFileCount, s => s.SeasonCount, s => s.NextAiring).EqualTo(fakeSeries); episode.EpisodeFile.Should().BeNull(); } diff --git a/NzbDrone.Core.Test/SeriesProviderTest.cs b/NzbDrone.Core.Test/SeriesProviderTest.cs index d2b271695..088db987b 100644 --- a/NzbDrone.Core.Test/SeriesProviderTest.cs +++ b/NzbDrone.Core.Test/SeriesProviderTest.cs @@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test var series = mocker.Resolve().GetSeries(1); //Assert - series.ShouldHave().AllPropertiesBut(s => s.QualityProfile, s => s.SeriesId).EqualTo(fakeSeries); + series.ShouldHave().AllPropertiesBut(s => s.QualityProfile, s => s.SeriesId, s => s.NextAiring).EqualTo(fakeSeries); series.QualityProfile.Should().NotBeNull(); series.QualityProfile.ShouldHave().Properties(q => q.Name, q => q.SonicAllowed, q => q.Cutoff, q => q.SonicAllowed).EqualTo(fakeQuality); @@ -475,5 +475,126 @@ namespace NzbDrone.Core.Test //Assert result.Should().BeFalse(); } + + [Test] + public void Get_Series_NextAiring_Today() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.SeriesId = fakeSeries.SeriesId) + .WhereTheFirst(1) + .Have(e => e.AirDate = DateTime.Today) + .AndTheRemaining() + .Have(e => e.AirDate = DateTime.Today.AddDays(1)) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(); + + //Assert + series.Should().HaveCount(1); + series[0].NextAiring.Should().Be(DateTime.Today); + } + + [Test] + public void Get_Series_NextAiring_Tomorrow_Last_Aired_Yesterday() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.SeriesId = fakeSeries.SeriesId) + .WhereTheFirst(1) + .Have(e => e.AirDate = DateTime.Today.AddDays(-1)) + .AndTheRemaining() + .Have(e => e.AirDate = DateTime.Today.AddDays(1)) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(); + + //Assert + series.Should().HaveCount(1); + series[0].NextAiring.Should().Be(DateTime.Today.AddDays(1)); + } + + [Test] + public void Get_Series_NextAiring_Unknown() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.SeriesId = fakeSeries.SeriesId) + .Have(e => e.AirDate = null) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(); + + //Assert + series.Should().HaveCount(1); + series[0].NextAiring.Should().NotHaveValue(); + } + + [Test] + public void Get_Series_NextAiring_1_month() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(2) + .WhereAll() + .Have(e => e.SeriesId = fakeSeries.SeriesId) + .WhereTheFirst(1) + .Have(e => e.AirDate = DateTime.Today.AddDays(-1)) + .AndTheRemaining() + .Have(e => e.AirDate = DateTime.Today.AddMonths(1)) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(); + + //Assert + series.Should().HaveCount(1); + series[0].NextAiring.Should().Be(DateTime.Today.AddMonths(1)); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index 4141b2b8d..3805b82bc 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Providers Series.Language, Series.Path, Series.Monitored, Series.QualityProfileId, Series.SeasonFolder, 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, - MAX(Episodes.SeasonNumber) as SeasonCount, + MAX(Episodes.SeasonNumber) as SeasonCount, MIN(CASE WHEN AirDate < @0 THEN NULL ELSE AirDate END) as NextAiring, QualityProfiles.QualityProfileId, QualityProfiles.Name, QualityProfiles.Cutoff, QualityProfiles.SonicAllowed FROM Series INNER JOIN QualityProfiles ON Series.QualityProfileId = QualityProfiles.QualityProfileId diff --git a/NzbDrone.Core/Repository/Series.cs b/NzbDrone.Core/Repository/Series.cs index 63ef62179..1d6a702c9 100644 --- a/NzbDrone.Core/Repository/Series.cs +++ b/NzbDrone.Core/Repository/Series.cs @@ -61,5 +61,8 @@ namespace NzbDrone.Core.Repository [ResultColumn] public int SeasonCount { get; set; } + + [ResultColumn] + public DateTime? NextAiring { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Web/Controllers/SeriesController.cs b/NzbDrone.Web/Controllers/SeriesController.cs index d96ad4387..52a7ebc99 100644 --- a/NzbDrone.Web/Controllers/SeriesController.cs +++ b/NzbDrone.Web/Controllers/SeriesController.cs @@ -174,7 +174,8 @@ namespace NzbDrone.Web.Controllers Status = s.Status, SeasonsCount = s.SeasonCount, EpisodeCount = s.EpisodeCount, - EpisodeFileCount = s.EpisodeFileCount + EpisodeFileCount = s.EpisodeFileCount, + NextAiring = s.NextAiring == null ? String.Empty : s.NextAiring.Value.ToBestDateString() }).ToList(); return series; diff --git a/NzbDrone.Web/Models/SeriesModel.cs b/NzbDrone.Web/Models/SeriesModel.cs index 7df0d4c5a..2a2bed978 100644 --- a/NzbDrone.Web/Models/SeriesModel.cs +++ b/NzbDrone.Web/Models/SeriesModel.cs @@ -21,6 +21,7 @@ namespace NzbDrone.Web.Models public string Overview { get; set; } public int Episodes { get; set; } public bool HasBanner { get; set; } + public string NextAiring { get; set; } public IList Seasons { get; set; } diff --git a/NzbDrone.Web/Views/Series/Index.cshtml b/NzbDrone.Web/Views/Series/Index.cshtml index dae828415..258c31584 100644 --- a/NzbDrone.Web/Views/Series/Index.cshtml +++ b/NzbDrone.Web/Views/Series/Index.cshtml @@ -72,7 +72,8 @@ NZBDrone columns.Bound(o => o.SeasonsCount).Title("Seasons"); columns.Bound(o => o.QualityProfileName).Title("Quality"); columns.Bound(o => o.Status); - columns.Bound(o => o.AirsDayOfWeek); + //columns.Bound(o => o.AirsDayOfWeek); + columns.Bound(o => o.NextAiring); columns.Bound(o => o.Episodes).Title("Episodes").Width(125) .ClientTemplate("
\" class=\"progressbar\">" + "
" + @@ -89,7 +90,12 @@ NZBDrone }) .Editable(editor => editor.Mode(GridEditMode.PopUp)) //.Sortable(sort => sort.OrderBy(order => order.Add(o => o.Title).Ascending()).Enabled(true)) - .DetailView(detailView => detailView.ClientTemplate("<#= Overview #>")) + .DetailView(detailView => detailView.ClientTemplate( + "Airs Day of Week: " + "<#= AirsDayOfWeek #>" + + "
" + + "Overview: " + + "<#= Overview #>" + )) .ClientEvents(clientEvents => { clientEvents.OnEdit("grid_edit");