Browse Source

fix: randomize start points with classic playlists

pull/2948/head
Jason Dove 2 weeks ago
parent
commit
fea9b3225e
No known key found for this signature in database
  1. 2
      CHANGELOG.md
  2. 5
      ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs
  3. 1
      ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs
  4. 2
      ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs
  5. 1
      ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs
  6. 1
      ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs
  7. 20
      ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs
  8. 1
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  9. 1
      ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs

2
CHANGELOG.md

@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Update Plex movie and other video titles when changed from Plex
- The first library scan after updating will act like a deep scan due to adding title to the Plex etag calculation
- Future periodic scans will update titles in ETV automatically (deep scans will not be required to update titles)
- Randomize start points on playlist items in classic schedules when setting is enabled
- Playlists ignored this setting in earlier builds
## [26.6.0] - 2026-07-09
### Added

5
ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs

@ -62,6 +62,7 @@ public class PlaylistEnumeratorTests @@ -62,6 +62,7 @@ public class PlaylistEnumeratorTests
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
var items = new List<int>();
@ -130,6 +131,7 @@ public class PlaylistEnumeratorTests @@ -130,6 +131,7 @@ public class PlaylistEnumeratorTests
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
var items = new List<int>();
@ -200,6 +202,7 @@ public class PlaylistEnumeratorTests @@ -200,6 +202,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
var items = new List<int>();
@ -270,6 +273,7 @@ public class PlaylistEnumeratorTests @@ -270,6 +273,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
var items = new List<int>();
@ -352,6 +356,7 @@ public class PlaylistEnumeratorTests @@ -352,6 +356,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
enumerator.CountForFiller.ShouldBe(7);

1
ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs

@ -168,6 +168,7 @@ public static class BlockPlayoutEnumerator @@ -168,6 +168,7 @@ public static class BlockPlayoutEnumerator
state,
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
cancellationToken);
DateTime historyTime = currentTime.UtcDateTime;

2
ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs

@ -66,6 +66,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository @@ -66,6 +66,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
state,
marathonShuffleGroups,
marathonBatchSize,
randomStartPoint: false,
cancellationToken);
}
@ -136,6 +137,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository @@ -136,6 +137,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
state,
shuffleGroups,
batchSize: Option<int>.None,
randomStartPoint: false,
cancellationToken);
return new PlaylistContentResult(

1
ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs

@ -58,6 +58,7 @@ public class PlaylistHelper(IMediaCollectionRepository mediaCollectionRepository @@ -58,6 +58,7 @@ public class PlaylistHelper(IMediaCollectionRepository mediaCollectionRepository
state,
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
cancellationToken);
return new PlaylistContentResult(

1
ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs

@ -257,6 +257,7 @@ public class SchedulingEngine( @@ -257,6 +257,7 @@ public class SchedulingEngine(
state,
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
CancellationToken.None);
string historyKey = HistoryDetails.KeyForSchedulingContent(key, PlaybackOrder.None);

20
ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs

@ -121,6 +121,7 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator @@ -121,6 +121,7 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
CollectionEnumeratorState state,
bool shufflePlaylistItems,
Option<int> batchSize,
bool randomStartPoint,
CancellationToken cancellationToken)
{
var result = new PlaylistEnumerator
@ -131,6 +132,10 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator @@ -131,6 +132,10 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
_batchSize = batchSize
};
// random start points only apply to a fresh build with no saved state
var random = new Random(state.Seed);
randomStartPoint = randomStartPoint && state.Index == 0;
// collections should share enumerators
var enumeratorMap = new Dictionary<CollectionKey, IMediaCollectionEnumerator>();
result._allMediaItemIds = [];
@ -166,6 +171,11 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator @@ -166,6 +171,11 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
switch (playlistItem.PlaybackOrder)
{
case PlaybackOrder.Chronological:
if (randomStartPoint)
{
initState.Index = random.Next(0, items.Count - 1);
}
enumerator = new ChronologicalMediaCollectionEnumerator(items, initState);
break;
// TODO: fix multi episode shuffle?
@ -187,18 +197,22 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator @@ -187,18 +197,22 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
CollectionKey.ForPlaylistItem(playlistItem),
cancellationToken),
initState,
// TODO: fix this
false,
randomStartPoint,
cancellationToken);
break;
case PlaybackOrder.SeasonEpisode:
// TODO: check random start point?
if (randomStartPoint)
{
initState.Index = random.Next(0, items.Count - 1);
}
enumerator = new SeasonEpisodeMediaCollectionEnumerator(items, initState);
// season, episode will filter out season 0, so we may get an empty enumerator back
if (enumerator.Count == 0)
{
enumerator = null;
}
break;
case PlaybackOrder.Random:
enumerator = new RandomizedMediaCollectionEnumerator(items, initState);

1
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -1325,6 +1325,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -1325,6 +1325,7 @@ public class PlayoutBuilder : IPlayoutBuilder
state,
marathonShuffleGroups,
batchSize: Option<int>.None,
randomStartPoint,
cancellationToken);
}
}

1
ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs

@ -175,6 +175,7 @@ public class EnumeratorCache(IMediaCollectionRepository mediaCollectionRepositor @@ -175,6 +175,7 @@ public class EnumeratorCache(IMediaCollectionRepository mediaCollectionRepositor
state,
shufflePlaylistItems: false,
batchSize: Option<int>.None,
randomStartPoint: false,
cancellationToken);
}

Loading…
Cancel
Save