Browse Source

fix playout build loop that was recently introduced (#1318)

pull/1319/head
Jason Dove 2 years ago committed by GitHub
parent
commit
015f5e9798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ErsatzTV.Core/Domain/CollectionEnumeratorState.cs
  2. 2
      ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs
  3. 5
      ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs
  4. 5
      ErsatzTV.Core/Scheduling/CustomOrderCollectionEnumerator.cs
  5. 23
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs
  6. 25
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  7. 5
      ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs
  8. 5
      ErsatzTV.Core/Scheduling/SeasonEpisodeMediaCollectionEnumerator.cs
  9. 11
      ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs
  10. 11
      ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs
  11. 23
      ErsatzTV.Infrastructure/Scheduling/MultiEpisodeShuffleCollectionEnumerator.cs

2
ErsatzTV.Core/Domain/CollectionEnumeratorState.cs

@ -4,5 +4,5 @@ public class CollectionEnumeratorState
{ {
public int Seed { get; set; } public int Seed { get; set; }
public int Index { get; set; } public int Index { get; set; }
public CollectionEnumeratorState Clone() => new CollectionEnumeratorState { Seed = Seed, Index = Index }; public CollectionEnumeratorState Clone() => new() { Seed = Seed, Index = Index };
} }

2
ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs

@ -4,7 +4,7 @@ namespace ErsatzTV.Core.Interfaces.Scheduling;
public interface IMediaCollectionEnumerator public interface IMediaCollectionEnumerator
{ {
IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken); void ResetState(CollectionEnumeratorState state);
CollectionEnumeratorState State { get; } CollectionEnumeratorState State { get; }
Option<MediaItem> Current { get; } Option<MediaItem> Current { get; }
void MoveNext(); void MoveNext();

5
ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs

@ -31,9 +31,10 @@ public sealed class ChronologicalMediaCollectionEnumerator : IMediaCollectionEnu
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new ChronologicalMediaCollectionEnumerator(_sortedMediaItems, state); // seed doesn't matter in chronological
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

5
ErsatzTV.Core/Scheduling/CustomOrderCollectionEnumerator.cs

@ -35,9 +35,10 @@ public class CustomOrderCollectionEnumerator : IMediaCollectionEnumerator
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new CustomOrderCollectionEnumerator(_collection, _mediaItems, state); // seed doesn't matter here
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

23
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

@ -122,16 +122,15 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
DateTimeOffset durationFinish = nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc); DateTimeOffset durationFinish = nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc);
var enumeratorClones = new Dictionary<CollectionKey, IMediaCollectionEnumerator>(); var enumeratorStates = new Dictionary<CollectionKey, CollectionEnumeratorState>();
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators) foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{ {
IMediaCollectionEnumerator clone = enumerator.Clone(enumerator.State.Clone(), cancellationToken); enumeratorStates.Add(key, enumerator.State.Clone());
enumeratorClones.Add(key, clone);
} }
List<PlayoutItem> maybePlayoutItems = AddFiller( List<PlayoutItem> maybePlayoutItems = AddFiller(
nextState, nextState,
enumeratorClones, collectionEnumerators,
scheduleItem, scheduleItem,
playoutItem, playoutItem,
itemChapters, itemChapters,
@ -147,16 +146,6 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime); // LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
playoutItems.AddRange(maybePlayoutItems); playoutItems.AddRange(maybePlayoutItems);
// update original enumerators
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{
IMediaCollectionEnumerator clone = enumeratorClones[key];
while (enumerator.State.Seed != clone.State.Seed || enumerator.State.Index != clone.State.Index)
{
enumerator.MoveNext();
}
}
nextState = nextState with nextState = nextState with
{ {
CurrentTime = itemEndTimeWithFiller, CurrentTime = itemEndTimeWithFiller,
@ -171,6 +160,12 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
} }
else else
{ {
// reset enumerators
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{
enumerator.ResetState(enumeratorStates[key]);
}
TimeSpan durationBlock = itemEndTimeWithFiller - itemStartTime; TimeSpan durationBlock = itemEndTimeWithFiller - itemStartTime;
if (itemEndTimeWithFiller - itemStartTime > scheduleItem.PlayoutDuration) if (itemEndTimeWithFiller - itemStartTime > scheduleItem.PlayoutDuration)
{ {

25
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -74,16 +74,15 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
? GetStartTimeAfter(nextState with { InFlood = false }, peekScheduleItem) ? GetStartTimeAfter(nextState with { InFlood = false }, peekScheduleItem)
: DateTimeOffset.MaxValue; : DateTimeOffset.MaxValue;
var enumeratorClones = new Dictionary<CollectionKey, IMediaCollectionEnumerator>(); var enumeratorStates = new Dictionary<CollectionKey, CollectionEnumeratorState>();
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators) foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{ {
IMediaCollectionEnumerator clone = enumerator.Clone(enumerator.State.Clone(), cancellationToken); enumeratorStates.Add(key, enumerator.State.Clone());
enumeratorClones.Add(key, clone);
} }
List<PlayoutItem> maybePlayoutItems = AddFiller( List<PlayoutItem> maybePlayoutItems = AddFiller(
nextState, nextState,
enumeratorClones, collectionEnumerators,
scheduleItem, scheduleItem,
playoutItem, playoutItem,
itemChapters, itemChapters,
@ -102,16 +101,6 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
playoutItems.AddRange(maybePlayoutItems); playoutItems.AddRange(maybePlayoutItems);
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime); // LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
// update original enumerators
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{
IMediaCollectionEnumerator clone = enumeratorClones[key];
while (enumerator.State.Seed != clone.State.Seed || enumerator.State.Index != clone.State.Index)
{
enumerator.MoveNext();
}
}
nextState = nextState with nextState = nextState with
{ {
CurrentTime = itemEndTimeWithFiller, CurrentTime = itemEndTimeWithFiller,
@ -125,6 +114,14 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
contentEnumerator.MoveNext(); contentEnumerator.MoveNext();
} }
else
{
// reset enumerators
foreach ((CollectionKey key, IMediaCollectionEnumerator enumerator) in collectionEnumerators)
{
enumerator.ResetState(enumeratorStates[key]);
}
}
} }
// _logger.LogDebug( // _logger.LogDebug(

5
ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs

@ -27,9 +27,10 @@ public class RandomizedMediaCollectionEnumerator : IMediaCollectionEnumerator
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new RandomizedMediaCollectionEnumerator(_mediaItems, state); // seed never changes here, no need to reset
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

5
ErsatzTV.Core/Scheduling/SeasonEpisodeMediaCollectionEnumerator.cs

@ -31,9 +31,10 @@ public sealed class SeasonEpisodeMediaCollectionEnumerator : IMediaCollectionEnu
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new SeasonEpisodeMediaCollectionEnumerator(_sortedMediaItems, state); // seed doesn't matter here
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

11
ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs

@ -43,9 +43,16 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new ShuffleInOrderCollectionEnumerator(_collections, state, _randomStartPoint, cancellationToken); // only re-shuffle if needed
if (State.Seed != state.Seed)
{
_random = new Random(state.Seed);
_shuffled = Shuffle(_collections, _random);
}
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

11
ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs

@ -40,9 +40,16 @@ public class ShuffledMediaCollectionEnumerator : IMediaCollectionEnumerator
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new ShuffledMediaCollectionEnumerator(_mediaItems, state, cancellationToken); // only re-shuffle if needed
if (State.Seed != state.Seed)
{
_random = new CloneableRandom(state.Seed);
_shuffled = Shuffle(_mediaItems, _random);
}
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

23
ErsatzTV.Infrastructure/Scheduling/MultiEpisodeShuffleCollectionEnumerator.cs

@ -10,8 +10,6 @@ namespace ErsatzTV.Infrastructure.Scheduling;
public class MultiEpisodeShuffleCollectionEnumerator : IMediaCollectionEnumerator public class MultiEpisodeShuffleCollectionEnumerator : IMediaCollectionEnumerator
{ {
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
private readonly IList<MediaItem> _mediaItems;
private readonly IScriptEngine _scriptEngine;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly int _mediaItemCount; private readonly int _mediaItemCount;
private readonly Dictionary<int, List<MediaItem>> _mediaItemGroups; private readonly Dictionary<int, List<MediaItem>> _mediaItemGroups;
@ -21,15 +19,13 @@ public class MultiEpisodeShuffleCollectionEnumerator : IMediaCollectionEnumerato
private readonly Lazy<Option<TimeSpan>> _lazyMinimumDuration; private readonly Lazy<Option<TimeSpan>> _lazyMinimumDuration;
public MultiEpisodeShuffleCollectionEnumerator( public MultiEpisodeShuffleCollectionEnumerator(
IList<MediaItem> mediaItems, ICollection<MediaItem> mediaItems,
CollectionEnumeratorState state, CollectionEnumeratorState state,
IScriptEngine scriptEngine, IScriptEngine scriptEngine,
string scriptFile, string scriptFile,
ILogger logger, ILogger logger,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
_mediaItems = mediaItems;
_scriptEngine = scriptEngine;
_logger = logger; _logger = logger;
_cancellationToken = cancellationToken; _cancellationToken = cancellationToken;
@ -91,15 +87,16 @@ public class MultiEpisodeShuffleCollectionEnumerator : IMediaCollectionEnumerato
} }
} }
public IMediaCollectionEnumerator Clone(CollectionEnumeratorState state, CancellationToken cancellationToken) public void ResetState(CollectionEnumeratorState state)
{ {
return new MultiEpisodeShuffleCollectionEnumerator( // only re-shuffle if needed
_mediaItems, if (State.Seed != state.Seed)
state, {
_scriptEngine, _random = new CloneableRandom(state.Seed);
null, _shuffled = Shuffle(_random);
_logger, }
cancellationToken);
State.Index = state.Index;
} }
public CollectionEnumeratorState State { get; } public CollectionEnumeratorState State { get; }

Loading…
Cancel
Save