From eee10dee22fc1252dd02815bb9ac8b6634441f54 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Mon, 31 May 2021 07:31:15 -0500 Subject: [PATCH] skip zero duration items when building playouts (#236) --- CHANGELOG.md | 8 +++- .../Scheduling/PlayoutBuilderTests.cs | 23 ++++++++++- ErsatzTV.Core/Scheduling/PlayoutBuilder.cs | 39 ++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9f83cb6..55d4bd0fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## Unreleased +## [Unreleased] + +### Changed +- Skip zero duration items when building a playout, rather than aborting the playout build + +### Fixed +- Fix edge case where a playout rebuild would get stuck and block all other playouts and library scans ## [0.0.41-prealpha] - 2021-05-30 ### Added diff --git a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs index 4976fea10..431f677e7 100644 --- a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs @@ -39,7 +39,7 @@ namespace ErsatzTV.Core.Tests.Scheduling [Test] [Timeout(2000)] - public async Task ZeroDurationItem_Should_Abort() + public async Task OnlyZeroDurationItem_Should_Abort() { var mediaItems = new List { @@ -55,6 +55,27 @@ namespace ErsatzTV.Core.Tests.Scheduling result.Items.Should().BeNull(); } + [Test] + public async Task ZeroDurationItem_Should_BeSkipped() + { + var mediaItems = new List + { + TestMovie(1, TimeSpan.Zero, DateTime.Today), + TestMovie(2, TimeSpan.FromHours(6), DateTime.Today) + }; + + (PlayoutBuilder builder, Playout playout) = TestDataFloodForItems(mediaItems, PlaybackOrder.Random); + DateTimeOffset start = HoursAfterMidnight(0); + DateTimeOffset finish = start + TimeSpan.FromHours(6); + + Playout result = await builder.BuildPlayoutItems(playout, start, finish); + + result.Items.Count.Should().Be(1); + result.Items.Head().MediaItemId.Should().Be(2); + result.Items.Head().StartOffset.TimeOfDay.Should().Be(TimeSpan.Zero); + result.Items.Head().FinishOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(6)); + } + [Test] public async Task InitialFlood_Should_StartAtMidnight() { diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index 3506d54a1..06358254f 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -80,17 +80,52 @@ namespace ErsatzTV.Core.Scheduling playout.Channel.Number, playout.Channel.Name); + foreach ((CollectionKey _, List items) in collectionMediaItems) + { + var zeroItems = new List(); + + foreach (MediaItem item in items) + { + bool isZero = item switch + { + Movie m => await m.MediaVersions.Map(v => v.Duration).HeadOrNone().IfNoneAsync(TimeSpan.Zero) == + TimeSpan.Zero, + Episode e => await e.MediaVersions.Map(v => v.Duration).HeadOrNone() + .IfNoneAsync(TimeSpan.Zero) == + TimeSpan.Zero, + MusicVideo mv => await mv.MediaVersions.Map(v => v.Duration).HeadOrNone() + .IfNoneAsync(TimeSpan.Zero) == + TimeSpan.Zero, + _ => true + }; + + if (isZero) + { + _logger.LogWarning( + "Skipping media item with zero duration {MediaItem} - {MediaItemTitle}", + item.Id, + DisplayTitle(item)); + + zeroItems.Add(item); + } + } + + items.RemoveAll(i => zeroItems.Contains(i)); + } + + // this guard needs to be below the place where we modify the collections (by removing zero-duration items) Option emptyCollection = collectionMediaItems.Find(c => !c.Value.Any()).Map(c => c.Key); if (emptyCollection.IsSome) { _logger.LogError( - "Unable to rebuild playout; collection {@CollectionKey} has no items!", + "Unable to rebuild playout; collection {@CollectionKey} has no valid items!", emptyCollection.ValueUnsafe()); return playout; } + // leaving this guard in for a while to ensure the zero item removal is working properly Option zeroDurationCollection = collectionMediaItems.Find( c => c.Value.Any( mi => mi switch @@ -106,7 +141,7 @@ namespace ErsatzTV.Core.Scheduling if (zeroDurationCollection.IsSome) { _logger.LogError( - "Unable to rebuild playout; collection {@CollectionKey} contains items with zero duration!", + "BUG: Unable to rebuild playout; collection {@CollectionKey} contains items with zero duration!", zeroDurationCollection.ValueUnsafe()); return playout;