Merge pull request #6677 from Bond-009/shuffle2

Remove duplicate Fisher–Yates shuffle impl
This commit is contained in:
Claus Vium 2021-10-08 15:51:51 +02:00 committed by GitHub
commit 098b598293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 76 deletions

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Model.SyncPlay; using MediaBrowser.Model.SyncPlay;
namespace MediaBrowser.Controller.SyncPlay.Queue namespace MediaBrowser.Controller.SyncPlay.Queue
@ -19,10 +20,16 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
private const int NoPlayingItemIndex = -1; private const int NoPlayingItemIndex = -1;
/// <summary> /// <summary>
/// Random number generator used to shuffle lists. /// The sorted playlist.
/// </summary> /// </summary>
/// <value>The random number generator.</value> /// <value>The sorted playlist, or play queue of the group.</value>
private readonly Random _randomNumberGenerator = new Random(); private List<QueueItem> _sortedPlaylist = new List<QueueItem>();
/// <summary>
/// The shuffled playlist.
/// </summary>
/// <value>The shuffled playlist, or play queue of the group.</value>
private List<QueueItem> _shuffledPlaylist = new List<QueueItem>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PlayQueueManager" /> class. /// Initializes a new instance of the <see cref="PlayQueueManager" /> class.
@ -56,18 +63,6 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// <value>The repeat mode.</value> /// <value>The repeat mode.</value>
public GroupRepeatMode RepeatMode { get; private set; } = GroupRepeatMode.RepeatNone; public GroupRepeatMode RepeatMode { get; private set; } = GroupRepeatMode.RepeatNone;
/// <summary>
/// Gets or sets the sorted playlist.
/// </summary>
/// <value>The sorted playlist, or play queue of the group.</value>
private List<QueueItem> SortedPlaylist { get; set; } = new List<QueueItem>();
/// <summary>
/// Gets or sets the shuffled playlist.
/// </summary>
/// <value>The shuffled playlist, or play queue of the group.</value>
private List<QueueItem> ShuffledPlaylist { get; set; } = new List<QueueItem>();
/// <summary> /// <summary>
/// Checks if an item is playing. /// Checks if an item is playing.
/// </summary> /// </summary>
@ -92,14 +87,14 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// <param name="items">The new items of the playlist.</param> /// <param name="items">The new items of the playlist.</param>
public void SetPlaylist(IReadOnlyList<Guid> items) public void SetPlaylist(IReadOnlyList<Guid> items)
{ {
SortedPlaylist.Clear(); _sortedPlaylist.Clear();
ShuffledPlaylist.Clear(); _shuffledPlaylist.Clear();
SortedPlaylist = CreateQueueItemsFromArray(items); _sortedPlaylist = CreateQueueItemsFromArray(items);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist); _shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
Shuffle(ShuffledPlaylist); _shuffledPlaylist.Shuffle();
} }
PlayingItemIndex = NoPlayingItemIndex; PlayingItemIndex = NoPlayingItemIndex;
@ -114,10 +109,10 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
var newItems = CreateQueueItemsFromArray(items); var newItems = CreateQueueItemsFromArray(items);
SortedPlaylist.AddRange(newItems); _sortedPlaylist.AddRange(newItems);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
ShuffledPlaylist.AddRange(newItems); _shuffledPlaylist.AddRange(newItems);
} }
LastChange = DateTime.UtcNow; LastChange = DateTime.UtcNow;
@ -130,26 +125,26 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
if (PlayingItemIndex == NoPlayingItemIndex) if (PlayingItemIndex == NoPlayingItemIndex)
{ {
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist); _shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
Shuffle(ShuffledPlaylist); _shuffledPlaylist.Shuffle();
} }
else if (ShuffleMode.Equals(GroupShuffleMode.Sorted)) else if (ShuffleMode.Equals(GroupShuffleMode.Sorted))
{ {
// First time shuffle. // First time shuffle.
var playingItem = SortedPlaylist[PlayingItemIndex]; var playingItem = _sortedPlaylist[PlayingItemIndex];
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist); _shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
ShuffledPlaylist.RemoveAt(PlayingItemIndex); _shuffledPlaylist.RemoveAt(PlayingItemIndex);
Shuffle(ShuffledPlaylist); _shuffledPlaylist.Shuffle();
ShuffledPlaylist.Insert(0, playingItem); _shuffledPlaylist.Insert(0, playingItem);
PlayingItemIndex = 0; PlayingItemIndex = 0;
} }
else else
{ {
// Re-shuffle playlist. // Re-shuffle playlist.
var playingItem = ShuffledPlaylist[PlayingItemIndex]; var playingItem = _shuffledPlaylist[PlayingItemIndex];
ShuffledPlaylist.RemoveAt(PlayingItemIndex); _shuffledPlaylist.RemoveAt(PlayingItemIndex);
Shuffle(ShuffledPlaylist); _shuffledPlaylist.Shuffle();
ShuffledPlaylist.Insert(0, playingItem); _shuffledPlaylist.Insert(0, playingItem);
PlayingItemIndex = 0; PlayingItemIndex = 0;
} }
@ -164,11 +159,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
if (PlayingItemIndex != NoPlayingItemIndex) if (PlayingItemIndex != NoPlayingItemIndex)
{ {
var playingItem = ShuffledPlaylist[PlayingItemIndex]; var playingItem = _shuffledPlaylist[PlayingItemIndex];
PlayingItemIndex = SortedPlaylist.IndexOf(playingItem); PlayingItemIndex = _sortedPlaylist.IndexOf(playingItem);
} }
ShuffledPlaylist.Clear(); _shuffledPlaylist.Clear();
ShuffleMode = GroupShuffleMode.Sorted; ShuffleMode = GroupShuffleMode.Sorted;
LastChange = DateTime.UtcNow; LastChange = DateTime.UtcNow;
@ -181,16 +176,16 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
public void ClearPlaylist(bool clearPlayingItem) public void ClearPlaylist(bool clearPlayingItem)
{ {
var playingItem = GetPlayingItem(); var playingItem = GetPlayingItem();
SortedPlaylist.Clear(); _sortedPlaylist.Clear();
ShuffledPlaylist.Clear(); _shuffledPlaylist.Clear();
LastChange = DateTime.UtcNow; LastChange = DateTime.UtcNow;
if (!clearPlayingItem && playingItem != null) if (!clearPlayingItem && playingItem != null)
{ {
SortedPlaylist.Add(playingItem); _sortedPlaylist.Add(playingItem);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
ShuffledPlaylist.Add(playingItem); _shuffledPlaylist.Add(playingItem);
} }
PlayingItemIndex = 0; PlayingItemIndex = 0;
@ -212,14 +207,14 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
var playingItem = GetPlayingItem(); var playingItem = GetPlayingItem();
var sortedPlayingItemIndex = SortedPlaylist.IndexOf(playingItem); var sortedPlayingItemIndex = _sortedPlaylist.IndexOf(playingItem);
// Append items to sorted and shuffled playlist as they are. // Append items to sorted and shuffled playlist as they are.
SortedPlaylist.InsertRange(sortedPlayingItemIndex + 1, newItems); _sortedPlaylist.InsertRange(sortedPlayingItemIndex + 1, newItems);
ShuffledPlaylist.InsertRange(PlayingItemIndex + 1, newItems); _shuffledPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
} }
else else
{ {
SortedPlaylist.InsertRange(PlayingItemIndex + 1, newItems); _sortedPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
} }
LastChange = DateTime.UtcNow; LastChange = DateTime.UtcNow;
@ -298,8 +293,8 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
var playingItem = GetPlayingItem(); var playingItem = GetPlayingItem();
SortedPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId)); _sortedPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
ShuffledPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId)); _shuffledPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
LastChange = DateTime.UtcNow; LastChange = DateTime.UtcNow;
@ -313,7 +308,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
// Was first element, picking next if available. // Was first element, picking next if available.
// Default to no playing item otherwise. // Default to no playing item otherwise.
PlayingItemIndex = SortedPlaylist.Count > 0 ? 0 : NoPlayingItemIndex; PlayingItemIndex = _sortedPlaylist.Count > 0 ? 0 : NoPlayingItemIndex;
} }
return true; return true;
@ -363,8 +358,8 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
SortedPlaylist.Clear(); _sortedPlaylist.Clear();
ShuffledPlaylist.Clear(); _shuffledPlaylist.Clear();
PlayingItemIndex = NoPlayingItemIndex; PlayingItemIndex = NoPlayingItemIndex;
ShuffleMode = GroupShuffleMode.Sorted; ShuffleMode = GroupShuffleMode.Sorted;
RepeatMode = GroupRepeatMode.RepeatNone; RepeatMode = GroupRepeatMode.RepeatNone;
@ -460,7 +455,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
} }
PlayingItemIndex++; PlayingItemIndex++;
if (PlayingItemIndex >= SortedPlaylist.Count) if (PlayingItemIndex >= _sortedPlaylist.Count)
{ {
if (RepeatMode.Equals(GroupRepeatMode.RepeatAll)) if (RepeatMode.Equals(GroupRepeatMode.RepeatAll))
{ {
@ -468,7 +463,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
} }
else else
{ {
PlayingItemIndex = SortedPlaylist.Count - 1; PlayingItemIndex = _sortedPlaylist.Count - 1;
return false; return false;
} }
} }
@ -494,7 +489,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
if (RepeatMode.Equals(GroupRepeatMode.RepeatAll)) if (RepeatMode.Equals(GroupRepeatMode.RepeatAll))
{ {
PlayingItemIndex = SortedPlaylist.Count - 1; PlayingItemIndex = _sortedPlaylist.Count - 1;
} }
else else
{ {
@ -507,23 +502,6 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
return true; return true;
} }
/// <summary>
/// Shuffles a given list.
/// </summary>
/// <param name="list">The list to shuffle.</param>
private void Shuffle<T>(IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = _randomNumberGenerator.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
/// <summary> /// <summary>
/// Creates a list from the array of items. Each item is given an unique playlist identifier. /// Creates a list from the array of items. Each item is given an unique playlist identifier.
/// </summary> /// </summary>
@ -548,11 +526,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{ {
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
return ShuffledPlaylist; return _shuffledPlaylist;
} }
else else
{ {
return SortedPlaylist; return _sortedPlaylist;
} }
} }
@ -568,11 +546,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
} }
else if (ShuffleMode.Equals(GroupShuffleMode.Shuffle)) else if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{ {
return ShuffledPlaylist[PlayingItemIndex]; return _shuffledPlaylist[PlayingItemIndex];
} }
else else
{ {
return SortedPlaylist[PlayingItemIndex]; return _sortedPlaylist[PlayingItemIndex];
} }
} }
} }

View File

@ -8,8 +8,6 @@ namespace Jellyfin.Extensions
/// </summary> /// </summary>
public static class ShuffleExtensions public static class ShuffleExtensions
{ {
private static readonly Random _rng = new Random();
/// <summary> /// <summary>
/// Shuffles the items in a list. /// Shuffles the items in a list.
/// </summary> /// </summary>
@ -17,7 +15,7 @@ namespace Jellyfin.Extensions
/// <typeparam name="T">The type.</typeparam> /// <typeparam name="T">The type.</typeparam>
public static void Shuffle<T>(this IList<T> list) public static void Shuffle<T>(this IList<T> list)
{ {
list.Shuffle(_rng); list.Shuffle(Random.Shared);
} }
/// <summary> /// <summary>