Browse Source

playout template pad to next fixes (#1809)

* prevent loop

* add discard attempts and fallback to pad_to_next
pull/1811/head
Jason Dove 2 years ago committed by GitHub
parent
commit
0b29bb32b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs
  2. 40
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs
  3. 68
      ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs

5
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs

@ -8,4 +8,9 @@ public class PlayoutTemplatePadToNextItem : PlayoutTemplateItem @@ -8,4 +8,9 @@ public class PlayoutTemplatePadToNextItem : PlayoutTemplateItem
public int PadToNext { get; set; }
public bool Trim { get; set; }
public string Fallback { get; set; }
[YamlMember(Alias = "discard_attempts", ApplyNamingConventions = false)]
public int DiscardAttempts { get; set; }
}

40
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
@ -9,7 +10,8 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler @@ -9,7 +10,8 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler
Playout playout,
DateTimeOffset currentTime,
PlayoutTemplatePadToNextItem padToNext,
IMediaCollectionEnumerator enumerator)
IMediaCollectionEnumerator enumerator,
Option<IMediaCollectionEnumerator> fallbackEnumerator)
{
int currentMinute = currentTime.Minute;
@ -31,10 +33,10 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler @@ -31,10 +33,10 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler
if (targetTime <= currentTime)
targetTime = targetTime.AddMinutes(padToNext.PadToNext);
int discardAttempts = padToNext.DiscardAttempts;
bool done = false;
TimeSpan remainingToFill = targetTime - currentTime;
while (!done && enumerator.Current.IsSome && remainingToFill > TimeSpan.Zero &&
remainingToFill >= enumerator.MinimumDuration)
while (!done && enumerator.Current.IsSome && remainingToFill > TimeSpan.Zero)
{
foreach (MediaItem mediaItem in enumerator.Current)
{
@ -55,21 +57,51 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler @@ -55,21 +57,51 @@ public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateScheduler
if (remainingToFill - itemDuration >= TimeSpan.Zero)
{
remainingToFill -= itemDuration;
currentTime += itemDuration;
playout.Items.Add(playoutItem);
enumerator.MoveNext();
}
else if (discardAttempts > 0)
{
// item won't fit; try the next one
discardAttempts--;
enumerator.MoveNext();
}
else if (padToNext.Trim)
{
// trim item to exactly fit
remainingToFill = TimeSpan.Zero;
currentTime = targetTime;
playoutItem.Finish = targetTime.UtcDateTime;
playoutItem.OutPoint = playoutItem.Finish - playoutItem.Start;
playout.Items.Add(playoutItem);
enumerator.MoveNext();
}
else if (fallbackEnumerator.IsSome)
{
foreach (IMediaCollectionEnumerator fallback in fallbackEnumerator)
{
remainingToFill = TimeSpan.Zero;
done = true;
// replace with fallback content
foreach (MediaItem fallbackItem in fallback.Current)
{
playoutItem.MediaItemId = fallbackItem.Id;
playoutItem.Finish = targetTime.UtcDateTime;
playoutItem.FillerKind = FillerKind.Fallback;
playout.Items.Add(playoutItem);
fallback.MoveNext();
}
}
}
else
{
// item won't fit; we're done for now
// item won't fit; we're done
done = true;
}
}

68
ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs

@ -45,6 +45,7 @@ public class TemplatePlayoutBuilder( @@ -45,6 +45,7 @@ public class TemplatePlayoutBuilder(
// load content and content enumerators on demand
Dictionary<string, IMediaCollectionEnumerator> enumerators = new();
int itemsAfterRepeat = playout.Items.Count;
var index = 0;
while (currentTime < finish)
{
@ -60,13 +61,22 @@ public class TemplatePlayoutBuilder( @@ -60,13 +61,22 @@ public class TemplatePlayoutBuilder(
if (playoutItem is PlayoutTemplateRepeatItem)
{
index = 0;
if (playout.Items.Count == itemsAfterRepeat)
{
logger.LogWarning("Repeat encountered without adding any playout items; aborting");
break;
}
itemsAfterRepeat = playout.Items.Count;
continue;
}
if (!enumerators.TryGetValue(playoutItem.Content, out IMediaCollectionEnumerator enumerator))
{
Option<IMediaCollectionEnumerator> maybeEnumerator =
await GetEnumeratorForContent(playout, playoutItem.Content, playoutTemplate, cancellationToken);
Option<IMediaCollectionEnumerator> maybeEnumerator = await GetCachedEnumeratorForContent(
playout,
playoutTemplate,
enumerators,
playoutItem.Content,
cancellationToken);
if (maybeEnumerator.IsNone)
{
@ -74,12 +84,7 @@ public class TemplatePlayoutBuilder( @@ -74,12 +84,7 @@ public class TemplatePlayoutBuilder(
continue;
}
foreach (IMediaCollectionEnumerator e in maybeEnumerator)
{
enumerator = maybeEnumerator.ValueUnsafe();
enumerators.Add(playoutItem.Content, enumerator);
}
}
IMediaCollectionEnumerator enumerator = maybeEnumerator.ValueUnsafe();
switch (playoutItem)
{
@ -87,11 +92,18 @@ public class TemplatePlayoutBuilder( @@ -87,11 +92,18 @@ public class TemplatePlayoutBuilder(
currentTime = PlayoutTemplateSchedulerCount.Schedule(playout, currentTime, count, enumerator);
break;
case PlayoutTemplatePadToNextItem padToNext:
Option<IMediaCollectionEnumerator> fallbackEnumerator = await GetCachedEnumeratorForContent(
playout,
playoutTemplate,
enumerators,
padToNext.Fallback,
cancellationToken);
currentTime = PlayoutTemplateSchedulerPadToNext.Schedule(
playout,
currentTime,
padToNext,
enumerator);
enumerator,
fallbackEnumerator);
break;
}
@ -106,6 +118,38 @@ public class TemplatePlayoutBuilder( @@ -106,6 +118,38 @@ public class TemplatePlayoutBuilder(
.GetValue<int>(ConfigElementKey.PlayoutDaysToBuild)
.IfNoneAsync(2);
private async Task<Option<IMediaCollectionEnumerator>> GetCachedEnumeratorForContent(
Playout playout,
PlayoutTemplate playoutTemplate,
Dictionary<string, IMediaCollectionEnumerator> enumerators,
string contentKey,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(contentKey))
{
return Option<IMediaCollectionEnumerator>.None;
}
if (!enumerators.TryGetValue(contentKey, out IMediaCollectionEnumerator enumerator))
{
Option<IMediaCollectionEnumerator> maybeEnumerator =
await GetEnumeratorForContent(playout, contentKey, playoutTemplate, cancellationToken);
if (maybeEnumerator.IsNone)
{
return Option<IMediaCollectionEnumerator>.None;
}
foreach (IMediaCollectionEnumerator e in maybeEnumerator)
{
enumerator = maybeEnumerator.ValueUnsafe();
enumerators.Add(contentKey, enumerator);
}
}
return Some(enumerator);
}
private async Task<Option<IMediaCollectionEnumerator>> GetEnumeratorForContent(
Playout playout,
string contentKey,
@ -156,6 +200,4 @@ public class TemplatePlayoutBuilder( @@ -156,6 +200,4 @@ public class TemplatePlayoutBuilder(
return deserializer.Deserialize<PlayoutTemplate>(yaml);
}
}

Loading…
Cancel
Save