Browse Source

fix mid-roll filler scheduling bug (#675)

pull/676/head
Jason Dove 4 years ago committed by GitHub
parent
commit
6c06fbe621
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 113
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs
  3. 10
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs

2
CHANGELOG.md

@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix playback of interlaced mpeg2video content with NVIDIA acceleration
- Fix playback of all interlaced content with QSV acceleration
- Fix adding songs to collections from search results page
- Fix bug scheduling mid-roll filler with content that contains one chapter
- No mid-roll filler will be inserted for content with zero or one chapters
### Added
- Add automated error reporting via Bugsnag

113
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs

@ -3,15 +3,20 @@ using ErsatzTV.Core.Domain.Filler; @@ -3,15 +3,20 @@ using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
namespace ErsatzTV.Core.Tests.Scheduling;
[TestFixture]
public class PlayoutModeSchedulerBaseTests
public class PlayoutModeSchedulerBaseTests : SchedulerTestBase
{
[TestFixture]
public class CalculateEndTimeWithFiller
{
[Test]
public void CalculateEndTimeWithFiller_Should_Not_Touch_Enumerator()
public void Should_Not_Touch_Enumerator()
{
var collection = new Collection
{
@ -58,7 +63,7 @@ public class PlayoutModeSchedulerBaseTests @@ -58,7 +63,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_15_Minutes_15()
public void Should_Pad_To_15_Minutes_15()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -80,7 +85,7 @@ public class PlayoutModeSchedulerBaseTests @@ -80,7 +85,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_15_Minutes_30()
public void Should_Pad_To_15_Minutes_30()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -102,7 +107,7 @@ public class PlayoutModeSchedulerBaseTests @@ -102,7 +107,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_15_Minutes_45()
public void Should_Pad_To_15_Minutes_45()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -124,7 +129,7 @@ public class PlayoutModeSchedulerBaseTests @@ -124,7 +129,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_15_Minutes_00()
public void Should_Pad_To_15_Minutes_00()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -146,7 +151,7 @@ public class PlayoutModeSchedulerBaseTests @@ -146,7 +151,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_30_Minutes_30()
public void Should_Pad_To_30_Minutes_30()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -168,7 +173,7 @@ public class PlayoutModeSchedulerBaseTests @@ -168,7 +173,7 @@ public class PlayoutModeSchedulerBaseTests
}
[Test]
public void CalculateEndTimeWithFiller_Should_Pad_To_30_Minutes_00()
public void Should_Pad_To_30_Minutes_00()
{
DateTimeOffset result = PlayoutModeSchedulerBase<ProgramScheduleItem>
.CalculateEndTimeWithFiller(
@ -188,6 +193,98 @@ public class PlayoutModeSchedulerBaseTests @@ -188,6 +193,98 @@ public class PlayoutModeSchedulerBaseTests
result.Should().Be(new DateTimeOffset(2020, 2, 1, 13, 0, 0, TimeSpan.FromHours(-5)));
}
}
[TestFixture]
public class AddFiller
{
[Test]
public void Should_Not_Crash_Mid_Roll_Zero_Chapters()
{
Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1));
var scheduleItem = new ProgramScheduleItemOne
{
MidRollFiller = new FillerPreset
{
FillerKind = FillerKind.MidRoll,
FillerMode = FillerMode.Pad,
PadToNearestMinute = 15
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
List<PlayoutItem> playoutItems = PlayoutModeSchedulerBase<ProgramScheduleItem>
.AddFiller(
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
new PlayoutItem(),
new List<MediaChapter>());
playoutItems.Count.Should().Be(1);
}
[Test]
public void Should_Not_Crash_Mid_Roll_One_Chapter()
{
Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1));
var scheduleItem = new ProgramScheduleItemOne
{
Id = 1,
Index = 1,
Collection = collectionOne,
CollectionId = collectionOne.Id,
StartTime = null,
PlaybackOrder = PlaybackOrder.Chronological,
TailFiller = null,
FallbackFiller = null,
MidRollFiller = new FillerPreset
{
FillerKind = FillerKind.MidRoll,
FillerMode = FillerMode.Pad,
PadToNearestMinute = 15
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
Dictionary<CollectionKey, IMediaCollectionEnumerator> enumerators = CollectionEnumerators(
scheduleItem,
enumerator);
// too lazy to make another enumerator for the filler that we don't want
enumerators.Add(CollectionKey.ForFillerPreset(scheduleItem.MidRollFiller), enumerator);
List<PlayoutItem> playoutItems = PlayoutModeSchedulerBase<ProgramScheduleItem>
.AddFiller(
startState,
enumerators,
scheduleItem,
new PlayoutItem(),
new List<MediaChapter> { new() });
playoutItems.Count.Should().Be(1);
}
}
private static Movie TestMovie(int id, TimeSpan duration, DateTime aired) =>
new()

10
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs

@ -310,7 +310,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -310,7 +310,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
return itemStartTime + totalDuration;
}
protected List<PlayoutItem> AddFiller(
internal static List<PlayoutItem> AddFiller(
PlayoutBuilderState playoutBuilderState,
Dictionary<CollectionKey, IMediaCollectionEnumerator> enumerators,
ProgramScheduleItem scheduleItem,
@ -333,7 +333,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -333,7 +333,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
}
List<MediaChapter> effectiveChapters = chapters;
if (allFiller.All(fp => fp.FillerKind != FillerKind.MidRoll))
if (allFiller.All(fp => fp.FillerKind != FillerKind.MidRoll) || effectiveChapters.Count <= 1)
{
effectiveChapters = new List<MediaChapter>();
}
@ -356,7 +356,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -356,7 +356,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
}
}
if (!effectiveChapters.Any())
if (effectiveChapters.Count <= 1)
{
result.Add(playoutItem);
}
@ -493,7 +493,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -493,7 +493,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
? remainingToFill
: remainingToFill / (effectiveChapters.Count - 1);
TimeSpan filled = TimeSpan.Zero;
for (var i = 0; i < chapters.Count; i++)
for (var i = 0; i < effectiveChapters.Count; i++)
{
result.Add(playoutItem.ForChapter(effectiveChapters[i]));
if (i < effectiveChapters.Count - 1)
@ -650,7 +650,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -650,7 +650,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
return result;
}
private Option<PlayoutItem> FallbackFillerForPad(
private static Option<PlayoutItem> FallbackFillerForPad(
PlayoutBuilderState playoutBuilderState,
Dictionary<CollectionKey, IMediaCollectionEnumerator> enumerators,
ProgramScheduleItem scheduleItem,

Loading…
Cancel
Save