Browse Source

fix playlist playouts (#1709)

* fix playlist playouts

* remove some logging
pull/1710/head
Jason Dove 2 years ago committed by GitHub
parent
commit
85eb7623da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 59
      ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs
  2. 2
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  3. 2
      ErsatzTV/Pages/ScheduleItemsEditor.razor

59
ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs

@ -7,6 +7,8 @@ namespace ErsatzTV.Core.Scheduling;
public class PlaylistEnumerator : IMediaCollectionEnumerator public class PlaylistEnumerator : IMediaCollectionEnumerator
{ {
private readonly System.Collections.Generic.HashSet<int> _remainingMediaItemIds = [];
private System.Collections.Generic.HashSet<int> _allMediaItemIds;
private int _enumeratorIndex; private int _enumeratorIndex;
private System.Collections.Generic.HashSet<int> _idsToIncludeInEPG; private System.Collections.Generic.HashSet<int> _idsToIncludeInEPG;
private IList<bool> _playAll; private IList<bool> _playAll;
@ -37,12 +39,17 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
} }
} }
public int Count { get; private set; } public int Count => throw new NotSupportedException("Count isn't used for playlist enumeration");
public Option<TimeSpan> MinimumDuration { get; private set; } public Option<TimeSpan> MinimumDuration { get; private set; }
public void MoveNext() public void MoveNext()
{ {
foreach (MediaItem maybeMediaItem in _sortedEnumerators[_enumeratorIndex].Current)
{
_remainingMediaItemIds.Remove(maybeMediaItem.Id);
}
_sortedEnumerators[_enumeratorIndex].MoveNext(); _sortedEnumerators[_enumeratorIndex].MoveNext();
// if we aren't playing all, or if we just finished playing all, move to the next enumerator // if we aren't playing all, or if we just finished playing all, move to the next enumerator
@ -51,7 +58,12 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
_enumeratorIndex = (_enumeratorIndex + 1) % _sortedEnumerators.Count; _enumeratorIndex = (_enumeratorIndex + 1) % _sortedEnumerators.Count;
} }
State.Index = (State.Index + 1) % Count; State.Index += 1;
if (_remainingMediaItemIds.Count == 0)
{
State.Index = 0;
_remainingMediaItemIds.UnionWith(_allMediaItemIds);
}
} }
public static async Task<PlaylistEnumerator> Create( public static async Task<PlaylistEnumerator> Create(
@ -64,19 +76,21 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
{ {
_sortedEnumerators = [], _sortedEnumerators = [],
_playAll = [], _playAll = [],
_idsToIncludeInEPG = [], _idsToIncludeInEPG = []
Count = LCM(playlistItemMap.Values.Map(v => v.Count)) * playlistItemMap.Count
}; };
// collections should share enumerators // collections should share enumerators
var enumeratorMap = new Dictionary<CollectionKey, IMediaCollectionEnumerator>(); var enumeratorMap = new Dictionary<CollectionKey, IMediaCollectionEnumerator>();
result._allMediaItemIds = [];
foreach (PlaylistItem playlistItem in playlistItemMap.Keys.OrderBy(i => i.Index)) foreach (PlaylistItem playlistItem in playlistItemMap.Keys.OrderBy(i => i.Index))
{ {
List<MediaItem> items = playlistItemMap[playlistItem]; List<MediaItem> items = playlistItemMap[playlistItem];
if (playlistItem.IncludeInProgramGuide) foreach (MediaItem mediaItem in items)
{ {
foreach (MediaItem mediaItem in items) result._allMediaItemIds.Add(mediaItem.Id);
if (playlistItem.IncludeInProgramGuide)
{ {
result._idsToIncludeInEPG.Add(mediaItem.Id); result._idsToIncludeInEPG.Add(mediaItem.Id);
} }
@ -141,6 +155,8 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
} }
} }
result._remainingMediaItemIds.UnionWith(result._allMediaItemIds);
result.MinimumDuration = playlistItemMap.Values result.MinimumDuration = playlistItemMap.Values
.Flatten() .Flatten()
.Bind(i => i.GetNonZeroDuration()) .Bind(i => i.GetNonZeroDuration())
@ -150,34 +166,17 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
result.State = new CollectionEnumeratorState { Seed = state.Seed }; result.State = new CollectionEnumeratorState { Seed = state.Seed };
result._enumeratorIndex = 0; result._enumeratorIndex = 0;
// TODO: how do we end up with index > count? // this was a bug when playlist enumerators were first added; shouldn't happen anymore
if (state.Index < result.Count) if (state.Index < 0)
{ {
while (result.State.Index < state.Index) state.Index = 0;
{
result.MoveNext();
}
} }
return result; while (result.State.Index < state.Index)
}
private static int LCM(IEnumerable<int> numbers) => numbers.Aggregate(lcm);
private static int lcm(int a, int b) => Math.Abs(a * b) / GCD(a, b);
private static int GCD(int a, int b)
{
while (true)
{ {
if (b == 0) result.MoveNext();
{
return a;
}
int a1 = a;
a = b;
b = a1 % b;
} }
return result;
} }
} }

2
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -481,7 +481,7 @@ public class PlayoutBuilder : IPlayoutBuilder
.ToList(); .ToList();
List<ProgramScheduleItem> fakeScheduleItems = []; List<ProgramScheduleItem> fakeScheduleItems = [];
// this will be used to clone a schedule item // this will be used to clone a schedule item
MethodInfo generic = typeof(JsonConvert).GetMethods() MethodInfo generic = typeof(JsonConvert).GetMethods()
.FirstOrDefault( .FirstOrDefault(
x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) && x.IsGenericMethod && x => x.Name.Equals("DeserializeObject", StringComparison.OrdinalIgnoreCase) && x.IsGenericMethod &&

2
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -647,7 +647,7 @@
{ {
_selectedItem = vm; _selectedItem = vm;
foreach (int playlistGroupId in Optional(_selectedItem.Playlist?.Id)) foreach (int playlistGroupId in Optional(_selectedItem.Playlist?.PlaylistGroupId))
{ {
foreach (PlaylistGroupViewModel group in Optional(_playlistGroups.Find(g => g.Id == playlistGroupId))) foreach (PlaylistGroupViewModel group in Optional(_playlistGroups.Find(g => g.Id == playlistGroupId)))
{ {

Loading…
Cancel
Save