瀏覽代碼

Don't shuffle some types by default

Bond_009 5 年之前
父節點
當前提交
bbc0875387

+ 15 - 15
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -425,10 +425,10 @@ namespace Emby.Dlna.ContentDirectory
         {
         {
             var folder = (Folder)item;
             var folder = (Folder)item;
 
 
-            var sortOrders = new List<string>();
+            var sortOrders = new List<(string, SortOrder)>();
             if (!folder.IsPreSorted)
             if (!folder.IsPreSorted)
             {
             {
-                sortOrders.Add(ItemSortBy.SortName);
+                sortOrders.Add((ItemSortBy.SortName, sort.SortOrder));
             }
             }
 
 
             var mediaTypes = new List<string>();
             var mediaTypes = new List<string>();
@@ -464,7 +464,7 @@ namespace Emby.Dlna.ContentDirectory
             {
             {
                 Limit = limit,
                 Limit = limit,
                 StartIndex = startIndex,
                 StartIndex = startIndex,
-                OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray(),
+                OrderBy = sortOrders,
                 User = user,
                 User = user,
                 Recursive = true,
                 Recursive = true,
                 IsMissing = false,
                 IsMissing = false,
@@ -872,10 +872,10 @@ namespace Emby.Dlna.ContentDirectory
             query.Parent = parent;
             query.Parent = parent;
             query.SetUser(user);
             query.SetUser(user);
 
 
-            query.OrderBy = new ValueTuple<string, SortOrder>[]
+            query.OrderBy = new[]
             {
             {
-                new ValueTuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
-                new ValueTuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
+                (ItemSortBy.DatePlayed, SortOrder.Descending),
+                (ItemSortBy.SortName, SortOrder.Ascending)
             };
             };
 
 
             query.IsResumable = true;
             query.IsResumable = true;
@@ -1121,7 +1121,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private QueryResult<ServerItem> GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
-            query.OrderBy = new ValueTuple<string, SortOrder>[] { };
+            query.OrderBy = Array.Empty<(string, SortOrder)>();
 
 
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             {
             {
@@ -1138,7 +1138,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
-            query.OrderBy = new ValueTuple<string, SortOrder>[] { };
+            query.OrderBy = Array.Empty<(string, SortOrder)>();
 
 
             var result = _tvSeriesManager.GetNextUp(new NextUpQuery
             var result = _tvSeriesManager.GetNextUp(new NextUpQuery
             {
             {
@@ -1153,7 +1153,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
-            query.OrderBy = new ValueTuple<string, SortOrder>[] { };
+            query.OrderBy = Array.Empty<(string, SortOrder)>();
 
 
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             {
             {
@@ -1170,7 +1170,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
         private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
         {
         {
-            query.OrderBy = new ValueTuple<string, SortOrder>[] { };
+            query.OrderBy = Array.Empty<(string, SortOrder)>();
 
 
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             var items = _userViewManager.GetLatestItems(new LatestItemsQuery
             {
             {
@@ -1274,13 +1274,13 @@ namespace Emby.Dlna.ContentDirectory
 
 
         private void SetSorting(InternalItemsQuery query, SortCriteria sort, bool isPreSorted)
         private void SetSorting(InternalItemsQuery query, SortCriteria sort, bool isPreSorted)
         {
         {
-            var sortOrders = new List<string>();
-            if (!isPreSorted)
+            if (isPreSorted)
             {
             {
-                sortOrders.Add(ItemSortBy.SortName);
+                query.OrderBy = Array.Empty<(string, SortOrder)>();
+            }
+            {
+                query.OrderBy = new[] { (ItemSortBy.SortName, sort.SortOrder) };
             }
             }
-
-            query.OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray();
         }
         }
 
 
         private QueryResult<ServerItem> ApplyPaging(QueryResult<ServerItem> result, int? startIndex, int? limit)
         private QueryResult<ServerItem> ApplyPaging(QueryResult<ServerItem> result, int? startIndex, int? limit)

+ 5 - 5
Emby.Server.Implementations/Channels/ChannelManager.cs

@@ -510,7 +510,7 @@ namespace Emby.Server.Implementations.Channels
             return _libraryManager.GetItemIds(new InternalItemsQuery
             return _libraryManager.GetItemIds(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Channel).Name },
                 IncludeItemTypes = new[] { typeof(Channel).Name },
-                OrderBy = new ValueTuple<string, SortOrder>[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
+                OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }
 
 
             }).Select(i => GetChannelFeatures(i.ToString("N", CultureInfo.InvariantCulture))).ToArray();
             }).Select(i => GetChannelFeatures(i.ToString("N", CultureInfo.InvariantCulture))).ToArray();
         }
         }
@@ -618,16 +618,16 @@ namespace Emby.Server.Implementations.Channels
             {
             {
                 query.OrderBy = new[]
                 query.OrderBy = new[]
                 {
                 {
-                    new ValueTuple<string, SortOrder>(ItemSortBy.PremiereDate, SortOrder.Descending),
-                    new ValueTuple<string, SortOrder>(ItemSortBy.ProductionYear, SortOrder.Descending),
-                    new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending)
+                    (ItemSortBy.PremiereDate, SortOrder.Descending),
+                    (ItemSortBy.ProductionYear, SortOrder.Descending),
+                    (ItemSortBy.DateCreated, SortOrder.Descending)
                 };
                 };
             }
             }
             else
             else
             {
             {
                 query.OrderBy = new[]
                 query.OrderBy = new[]
                 {
                 {
-                    new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending)
+                    (ItemSortBy.DateCreated, SortOrder.Descending)
                 };
                 };
             }
             }
 
 

+ 0 - 1
Emby.Server.Implementations/Collections/CollectionImageProvider.cs

@@ -76,7 +76,6 @@ namespace Emby.Server.Implementations.Collections
                 .Where(i => i != null)
                 .Where(i => i != null)
                 .GroupBy(x => x.Id)
                 .GroupBy(x => x.Id)
                 .Select(x => x.First())
                 .Select(x => x.First())
-                .OrderBy(i => Guid.NewGuid())
                 .ToList();
                 .ToList();
         }
         }
 
 

+ 10 - 18
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -3,12 +3,11 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
-using System.Runtime.Serialization;
 using System.Text;
 using System.Text;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
 using System.Threading;
 using System.Threading;
 using Emby.Server.Implementations.Playlists;
 using Emby.Server.Implementations.Playlists;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Json;
 using MediaBrowser.Common.Json;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
@@ -2832,8 +2831,8 @@ namespace Emby.Server.Implementations.Data
                             BindSimilarParams(query, statement);
                             BindSimilarParams(query, statement);
                             BindSearchParams(query, statement);
                             BindSearchParams(query, statement);
 
 
-                                // Running this again will bind the params
-                                GetWhereClauses(query, statement);
+                            // Running this again will bind the params
+                            GetWhereClauses(query, statement);
 
 
                             var hasEpisodeAttributes = HasEpisodeAttributes(query);
                             var hasEpisodeAttributes = HasEpisodeAttributes(query);
                             var hasServiceName = HasServiceName(query);
                             var hasServiceName = HasServiceName(query);
@@ -2882,14 +2881,14 @@ namespace Emby.Server.Implementations.Data
 
 
         private string GetOrderByText(InternalItemsQuery query)
         private string GetOrderByText(InternalItemsQuery query)
         {
         {
+            var orderBy = query.OrderBy;
             if (string.IsNullOrEmpty(query.SearchTerm))
             if (string.IsNullOrEmpty(query.SearchTerm))
             {
             {
-                int oldLen = query.OrderBy.Length;
-
-                if (query.SimilarTo != null && oldLen == 0)
+                int oldLen = orderBy.Count;
+                if (oldLen == 0 && query.SimilarTo != null)
                 {
                 {
                     var arr = new (string, SortOrder)[oldLen + 2];
                     var arr = new (string, SortOrder)[oldLen + 2];
-                    query.OrderBy.CopyTo(arr, 0);
+                    orderBy.CopyTo(arr, 0);
                     arr[oldLen] = ("SimilarityScore", SortOrder.Descending);
                     arr[oldLen] = ("SimilarityScore", SortOrder.Descending);
                     arr[oldLen + 1] = (ItemSortBy.Random, SortOrder.Ascending);
                     arr[oldLen + 1] = (ItemSortBy.Random, SortOrder.Ascending);
                     query.OrderBy = arr;
                     query.OrderBy = arr;
@@ -2897,16 +2896,15 @@ namespace Emby.Server.Implementations.Data
             }
             }
             else
             else
             {
             {
-                query.OrderBy = new []
+                query.OrderBy = new[]
                 {
                 {
                     ("SearchScore", SortOrder.Descending),
                     ("SearchScore", SortOrder.Descending),
                     (ItemSortBy.SortName, SortOrder.Ascending)
                     (ItemSortBy.SortName, SortOrder.Ascending)
                 };
                 };
             }
             }
 
 
-            var orderBy = query.OrderBy;
 
 
-            if (orderBy.Length == 0)
+            if (orderBy.Count == 0)
             {
             {
                 return string.Empty;
                 return string.Empty;
             }
             }
@@ -2914,14 +2912,8 @@ namespace Emby.Server.Implementations.Data
             return " ORDER BY " + string.Join(",", orderBy.Select(i =>
             return " ORDER BY " + string.Join(",", orderBy.Select(i =>
             {
             {
                 var columnMap = MapOrderByField(i.Item1, query);
                 var columnMap = MapOrderByField(i.Item1, query);
-                var columnAscending = i.Item2 == SortOrder.Ascending;
-                const bool enableOrderInversion = false;
-                if (columnMap.Item2 && enableOrderInversion)
-                {
-                    columnAscending = !columnAscending;
-                }
 
 
-                var sortOrder = columnAscending ? "ASC" : "DESC";
+                var sortOrder = i.Item2 == SortOrder.Ascending ? "ASC" : "DESC";
 
 
                 return columnMap.Item1 + " " + sortOrder;
                 return columnMap.Item1 + " " + sortOrder;
             }));
             }));

+ 2 - 2
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -829,7 +829,7 @@ namespace Emby.Server.Implementations.Library
             {
             {
                 Path = path,
                 Path = path,
                 IsFolder = isFolder,
                 IsFolder = isFolder,
-                OrderBy = new[] { ItemSortBy.DateCreated }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
+                OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
                 Limit = 1,
                 Limit = 1,
                 DtoOptions = new DtoOptions(true)
                 DtoOptions = new DtoOptions(true)
             };
             };
@@ -1257,7 +1257,7 @@ namespace Emby.Server.Implementations.Library
 
 
         public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
         public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
         {
         {
-            if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
+            if (query.Recursive && query.ParentId != Guid.Empty)
             {
             {
                 var parent = GetItemById(query.ParentId);
                 var parent = GetItemById(query.ParentId);
                 if (parent != null)
                 if (parent != null)

+ 1 - 2
Emby.Server.Implementations/Library/MusicManager.cs

@@ -89,10 +89,9 @@ namespace Emby.Server.Implementations.Library
 
 
                 Limit = 200,
                 Limit = 200,
 
 
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
 
 
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
-
             });
             });
         }
         }
 
 

+ 1 - 1
Emby.Server.Implementations/Library/SearchEngine.cs

@@ -162,7 +162,7 @@ namespace Emby.Server.Implementations.Library
                 Limit = query.Limit,
                 Limit = query.Limit,
                 IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
                 IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
                 ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),
                 ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
                 Recursive = true,
                 Recursive = true,
 
 
                 IsKids = query.IsKids,
                 IsKids = query.IsKids,

+ 1 - 1
Emby.Server.Implementations/Library/UserViewManager.cs

@@ -340,7 +340,7 @@ namespace Emby.Server.Implementations.Library
             var query = new InternalItemsQuery(user)
             var query = new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = includeItemTypes,
                 IncludeItemTypes = includeItemTypes,
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
+                OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
                 IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
                 IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
                 ExcludeItemTypes = excludeItemTypes,
                 ExcludeItemTypes = excludeItemTypes,
                 IsVirtualItem = false,
                 IsVirtualItem = false,

+ 4 - 4
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -1580,15 +1580,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                     return;
                     return;
                 }
                 }
 
 
-                var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery
+                var episodesToDelete = librarySeries.GetItemList(new InternalItemsQuery
                 {
                 {
-                    OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
+                    OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
                     IsVirtualItem = false,
                     IsVirtualItem = false,
                     IsFolder = false,
                     IsFolder = false,
                     Recursive = true,
                     Recursive = true,
                     DtoOptions = new DtoOptions(true)
                     DtoOptions = new DtoOptions(true)
 
 
-                }))
+                })
                     .Where(i => i.IsFileProtocol && File.Exists(i.Path))
                     .Where(i => i.IsFileProtocol && File.Exists(i.Path))
                     .Skip(seriesTimer.KeepUpTo - 1)
                     .Skip(seriesTimer.KeepUpTo - 1)
                     .ToList();
                     .ToList();
@@ -2258,7 +2258,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                 },
                 },
                 MinStartDate = startDateUtc.AddMinutes(-3),
                 MinStartDate = startDateUtc.AddMinutes(-3),
                 MaxStartDate = startDateUtc.AddMinutes(3),
                 MaxStartDate = startDateUtc.AddMinutes(3),
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) }
+                OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) }
             };
             };
 
 
             if (!string.IsNullOrWhiteSpace(channelId))
             if (!string.IsNullOrWhiteSpace(channelId))

+ 11 - 11
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -209,16 +209,16 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var orderBy = internalQuery.OrderBy.ToList();
             var orderBy = internalQuery.OrderBy.ToList();
 
 
-            orderBy.AddRange(query.SortBy.Select(i => new ValueTuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending)));
+            orderBy.AddRange(query.SortBy.Select(i => (i, query.SortOrder ?? SortOrder.Ascending)));
 
 
             if (query.EnableFavoriteSorting)
             if (query.EnableFavoriteSorting)
             {
             {
-                orderBy.Insert(0, new ValueTuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending));
+                orderBy.Insert(0, (ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending));
             }
             }
 
 
             if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase)))
             if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase)))
             {
             {
-                orderBy.Add(new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
+                orderBy.Add((ItemSortBy.SortName, SortOrder.Ascending));
             }
             }
 
 
             internalQuery.OrderBy = orderBy.ToArray();
             internalQuery.OrderBy = orderBy.ToArray();
@@ -772,22 +772,22 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var topFolder = GetInternalLiveTvFolder(cancellationToken);
             var topFolder = GetInternalLiveTvFolder(cancellationToken);
 
 
-            if (query.OrderBy.Length == 0)
+            if (query.OrderBy.Count == 0)
             {
             {
                 if (query.IsAiring ?? false)
                 if (query.IsAiring ?? false)
                 {
                 {
                     // Unless something else was specified, order by start date to take advantage of a specialized index
                     // Unless something else was specified, order by start date to take advantage of a specialized index
-                    query.OrderBy = new ValueTuple<string, SortOrder>[]
+                    query.OrderBy = new[]
                     {
                     {
-                        new ValueTuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending)
+                        (ItemSortBy.StartDate, SortOrder.Ascending)
                     };
                     };
                 }
                 }
                 else
                 else
                 {
                 {
                     // Unless something else was specified, order by start date to take advantage of a specialized index
                     // Unless something else was specified, order by start date to take advantage of a specialized index
-                    query.OrderBy = new ValueTuple<string, SortOrder>[]
+                    query.OrderBy = new[]
                     {
                     {
-                        new ValueTuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending)
+                        (ItemSortBy.StartDate, SortOrder.Ascending)
                     };
                     };
                 }
                 }
             }
             }
@@ -871,7 +871,7 @@ namespace Emby.Server.Implementations.LiveTv
                 IsSports = query.IsSports,
                 IsSports = query.IsSports,
                 IsKids = query.IsKids,
                 IsKids = query.IsKids,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
                 TopParentIds = new[] { topFolder.Id },
                 TopParentIds = new[] { topFolder.Id },
                 DtoOptions = options,
                 DtoOptions = options,
                 GenreIds = query.GenreIds
                 GenreIds = query.GenreIds
@@ -1393,7 +1393,7 @@ namespace Emby.Server.Implementations.LiveTv
                 IsVirtualItem = false,
                 IsVirtualItem = false,
                 Limit = limit,
                 Limit = limit,
                 StartIndex = query.StartIndex,
                 StartIndex = query.StartIndex,
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
+                OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 IncludeItemTypes = includeItemTypes.ToArray(),
                 IncludeItemTypes = includeItemTypes.ToArray(),
                 ExcludeItemTypes = excludeItemTypes.ToArray(),
                 ExcludeItemTypes = excludeItemTypes.ToArray(),
@@ -1891,7 +1891,7 @@ namespace Emby.Server.Implementations.LiveTv
                 MaxStartDate = now,
                 MaxStartDate = now,
                 MinEndDate = now,
                 MinEndDate = now,
                 Limit = channelIds.Length,
                 Limit = channelIds.Length,
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
                 DtoOptions = options
                 DtoOptions = options
 
 

+ 2 - 3
Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs

@@ -62,7 +62,6 @@ namespace Emby.Server.Implementations.Playlists
                     return null;
                     return null;
                 })
                 })
                 .Where(i => i != null)
                 .Where(i => i != null)
-                .OrderBy(i => Guid.NewGuid())
                 .GroupBy(x => x.Id)
                 .GroupBy(x => x.Id)
                 .Select(x => x.First())
                 .Select(x => x.First())
                 .ToList();
                 .ToList();
@@ -84,7 +83,7 @@ namespace Emby.Server.Implementations.Playlists
             {
             {
                 Genres = new[] { item.Name },
                 Genres = new[] { item.Name },
                 IncludeItemTypes = new[] { typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Audio).Name },
                 IncludeItemTypes = new[] { typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Audio).Name },
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
                 Limit = 4,
                 Limit = 4,
                 Recursive = true,
                 Recursive = true,
                 ImageTypes = new[] { ImageType.Primary },
                 ImageTypes = new[] { ImageType.Primary },
@@ -108,7 +107,7 @@ namespace Emby.Server.Implementations.Playlists
             {
             {
                 Genres = new[] { item.Name },
                 Genres = new[] { item.Name },
                 IncludeItemTypes = new[] { typeof(Series).Name, typeof(Movie).Name },
                 IncludeItemTypes = new[] { typeof(Series).Name, typeof(Movie).Name },
-                OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
+                OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
                 Limit = 4,
                 Limit = 4,
                 Recursive = true,
                 Recursive = true,
                 ImageTypes = new[] { ImageType.Primary },
                 ImageTypes = new[] { ImageType.Primary },

+ 24 - 26
Emby.Server.Implementations/Session/SessionManager.cs

@@ -1061,7 +1061,7 @@ namespace Emby.Server.Implementations.Session
 
 
             var session = GetSessionToRemoteControl(sessionId);
             var session = GetSessionToRemoteControl(sessionId);
 
 
-            var user = !session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(session.UserId) : null;
+            var user = session.UserId == Guid.Empty ? null : _userManager.GetUserById(session.UserId);
 
 
             List<BaseItem> items;
             List<BaseItem> items;
 
 
@@ -1086,7 +1086,7 @@ namespace Emby.Server.Implementations.Session
 
 
             if (command.PlayCommand == PlayCommand.PlayShuffle)
             if (command.PlayCommand == PlayCommand.PlayShuffle)
             {
             {
-                items = items.OrderBy(i => Guid.NewGuid()).ToList();
+                items.Shuffle();
                 command.PlayCommand = PlayCommand.PlayNow;
                 command.PlayCommand = PlayCommand.PlayNow;
             }
             }
 
 
@@ -1100,28 +1100,27 @@ namespace Emby.Server.Implementations.Session
                 }
                 }
             }
             }
 
 
-            if (user != null && command.ItemIds.Length == 1 && user.Configuration.EnableNextEpisodeAutoPlay)
+            if (user != null
+                && command.ItemIds.Length == 1
+                && user.Configuration.EnableNextEpisodeAutoPlay
+                && _libraryManager.GetItemById(command.ItemIds[0]) is Episode episode)
             {
             {
-                var episode = _libraryManager.GetItemById(command.ItemIds[0]) as Episode;
-                if (episode != null)
+                var series = episode.Series;
+                if (series != null)
                 {
                 {
-                    var series = episode.Series;
-                    if (series != null)
+                    var episodes = series.GetEpisodes(
+                            user,
+                            new DtoOptions(false)
+                            {
+                                EnableImages = false
+                            })
+                        .Where(i => !i.IsVirtualItem)
+                        .SkipWhile(i => i.Id != episode.Id)
+                        .ToList();
+
+                    if (episodes.Count > 0)
                     {
                     {
-                        var episodes = series.GetEpisodes(
-                                user,
-                                new DtoOptions(false)
-                                {
-                                    EnableImages = false
-                                })
-                            .Where(i => !i.IsVirtualItem)
-                            .SkipWhile(i => i.Id != episode.Id)
-                            .ToList();
-
-                        if (episodes.Count > 0)
-                        {
-                            command.ItemIds = episodes.Select(i => i.Id).ToArray();
-                        }
+                        command.ItemIds = episodes.Select(i => i.Id).ToArray();
                     }
                     }
                 }
                 }
             }
             }
@@ -1146,7 +1145,7 @@ namespace Emby.Server.Implementations.Session
             if (item == null)
             if (item == null)
             {
             {
                 _logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id);
                 _logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id);
-                return new List<BaseItem>();
+                return Array.Empty<BaseItem>();
             }
             }
 
 
             if (item is IItemByName byName)
             if (item is IItemByName byName)
@@ -1164,7 +1163,7 @@ namespace Emby.Server.Implementations.Session
                         }
                         }
                     },
                     },
                     IsVirtualItem = false,
                     IsVirtualItem = false,
-                    OrderBy = new ValueTuple<string, SortOrder>[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
+                    OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }
                 });
                 });
             }
             }
 
 
@@ -1185,12 +1184,11 @@ namespace Emby.Server.Implementations.Session
                         }
                         }
                     },
                     },
                     IsVirtualItem = false,
                     IsVirtualItem = false,
-                    OrderBy = new ValueTuple<string, SortOrder>[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
-
+                    OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }
                 });
                 });
             }
             }
 
 
-            return new List<BaseItem> { item };
+            return new[] { item };
         }
         }
 
 
         private IEnumerable<BaseItem> TranslateItemForInstantMix(Guid id, User user)
         private IEnumerable<BaseItem> TranslateItemForInstantMix(Guid id, User user)

+ 1 - 4
Emby.Server.Implementations/UserViews/DynamicImageProvider.cs

@@ -86,20 +86,17 @@ namespace Emby.Server.Implementations.UserViews
             {
             {
                 return items
                 return items
                     .Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb))
                     .Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb))
-                    .OrderBy(i => Guid.NewGuid())
                     .ToList();
                     .ToList();
             }
             }
 
 
             return items
             return items
                 .Where(i => i.HasImage(ImageType.Primary))
                 .Where(i => i.HasImage(ImageType.Primary))
-                .OrderBy(i => Guid.NewGuid())
                 .ToList();
                 .ToList();
         }
         }
 
 
         protected override bool Supports(BaseItem item)
         protected override bool Supports(BaseItem item)
         {
         {
-            var view = item as UserView;
-            if (view != null)
+            if (item is UserView view)
             {
             {
                 return IsUsingCollectionStrip(view);
                 return IsUsingCollectionStrip(view);
             }
             }

+ 0 - 2
MediaBrowser.Api/Movies/MoviesService.cs

@@ -191,12 +191,10 @@ namespace MediaBrowser.Api.Movies
             var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
             var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
             // Get recently played directors
             // Get recently played directors
             var recentDirectors = GetDirectors(mostRecentMovies)
             var recentDirectors = GetDirectors(mostRecentMovies)
-                .OrderBy(i => Guid.NewGuid())
                 .ToList();
                 .ToList();
 
 
             // Get recently played actors
             // Get recently played actors
             var recentActors = GetActors(mostRecentMovies)
             var recentActors = GetActors(mostRecentMovies)
-                .OrderBy(i => Guid.NewGuid())
                 .ToList();
                 .ToList();
 
 
             var similarToRecentlyPlayed = GetSimilarTo(user, recentlyPlayedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
             var similarToRecentlyPlayed = GetSimilarTo(user, recentlyPlayedMovies, itemLimit, dtoOptions, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();

+ 1 - 1
MediaBrowser.Api/TvShowsService.cs

@@ -482,7 +482,7 @@ namespace MediaBrowser.Api
 
 
             if (string.Equals(request.SortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
             if (string.Equals(request.SortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
             {
             {
-                episodes = episodes.OrderBy(i => Guid.NewGuid()).ToList();
+                episodes.Shuffle();
             }
             }
 
 
             var returnItems = episodes;
             var returnItems = episodes;

+ 1 - 1
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -476,7 +476,7 @@ namespace MediaBrowser.Api.UserLibrary
             }
             }
 
 
             // Apply default sorting if none requested
             // Apply default sorting if none requested
-            if (query.OrderBy.Length == 0)
+            if (query.OrderBy.Count == 0)
             {
             {
                 // Albums by artist
                 // Albums by artist
                 if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], "MusicAlbum", StringComparison.OrdinalIgnoreCase))
                 if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], "MusicAlbum", StringComparison.OrdinalIgnoreCase))

+ 21 - 16
MediaBrowser.Common/Extensions/CollectionExtensions.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
 
 
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace MediaBrowser.Common.Extensions
 namespace MediaBrowser.Common.Extensions
@@ -7,6 +8,26 @@ namespace MediaBrowser.Common.Extensions
     // The MS CollectionExtensions are only available in netcoreapp
     // The MS CollectionExtensions are only available in netcoreapp
     public static class CollectionExtensions
     public static class CollectionExtensions
     {
     {
+        private static readonly Random _rng = new Random();
+
+        /// <summary>
+        /// Shuffles the items in a list.
+        /// </summary>
+        /// <param name="list">The list that should get shuffled.</param>
+        /// <typeparam name="T">The type.</typeparam>
+        public static void Shuffle<T>(this IList<T> list)
+        {
+            int n = list.Count;
+            while (n > 1)
+            {
+                n--;
+                int k = _rng.Next(n + 1);
+                T value = list[k];
+                list[k] = list[n];
+                list[n] = value;
+            }
+        }
+
         public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
         public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
         {
         {
             dictionary.TryGetValue(key, out var ret);
             dictionary.TryGetValue(key, out var ret);
@@ -28,21 +49,5 @@ namespace MediaBrowser.Common.Extensions
                 destination[index + i] = source[i];
                 destination[index + i] = source[i];
             }
             }
         }
         }
-
-        /// <summary>
-        /// Copies all the elements of the current collection to the specified list
-        /// starting at the specified destination array index. The index is specified as a 32-bit integer.
-        /// </summary>
-        /// <param name="source">The current collection that is the source of the elements.</param>
-        /// <param name="destination">The list that is the destination of the elements copied from the current collection.</param>
-        /// <param name="index">A 32-bit integer that represents the index in <c>destination</c> at which copying begins.</param>
-        /// <typeparam name="T"></typeparam>
-        public static void CopyTo<T>(this IReadOnlyCollection<T> source, IList<T> destination, int index = 0)
-        {
-            foreach (T item in source)
-            {
-                destination[index++] = item;
-            }
-        }
     }
     }
 }
 }

+ 4 - 1
MediaBrowser.Controller/Entities/Folder.cs

@@ -1163,7 +1163,10 @@ namespace MediaBrowser.Controller.Entities
             }
             }
 
 
             //the true root should return our users root folder children
             //the true root should return our users root folder children
-            if (IsPhysicalRoot) return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren);
+            if (IsPhysicalRoot)
+            {
+                return LibraryManager.GetUserRootFolder().GetChildren(user, includeLinkedChildren);
+            }
 
 
             var result = new Dictionary<Guid, BaseItem>();
             var result = new Dictionary<Guid, BaseItem>();
 
 

+ 1 - 1
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -155,7 +155,7 @@ namespace MediaBrowser.Controller.Entities
         public bool EnableGroupByMetadataKey { get; set; }
         public bool EnableGroupByMetadataKey { get; set; }
         public bool? HasChapterImages { get; set; }
         public bool? HasChapterImages { get; set; }
 
 
-        public ValueTuple<string, SortOrder>[] OrderBy { get; set; }
+        public IReadOnlyList<(string, SortOrder)> OrderBy { get; set; }
 
 
         public DateTime? MinDateCreated { get; set; }
         public DateTime? MinDateCreated { get; set; }
         public DateTime? MinDateLastSaved { get; set; }
         public DateTime? MinDateLastSaved { get; set; }

+ 3 - 1
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -226,14 +226,16 @@ namespace MediaBrowser.Controller.Entities.TV
 
 
                 query.AncestorWithPresentationUniqueKey = null;
                 query.AncestorWithPresentationUniqueKey = null;
                 query.SeriesPresentationUniqueKey = seriesKey;
                 query.SeriesPresentationUniqueKey = seriesKey;
-                if (query.OrderBy.Length == 0)
+                if (query.OrderBy.Count == 0)
                 {
                 {
                     query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
                     query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
                 }
                 }
+
                 if (query.IncludeItemTypes.Length == 0)
                 if (query.IncludeItemTypes.Length == 0)
                 {
                 {
                     query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
                     query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
                 }
                 }
+
                 query.IsVirtualItem = false;
                 query.IsVirtualItem = false;
                 return LibraryManager.GetItemsResult(query);
                 return LibraryManager.GetItemsResult(query);
             }
             }

+ 5 - 3
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -450,14 +450,16 @@ namespace MediaBrowser.Controller.Entities
             return SortAndPage(items, totalRecordLimit, query, libraryManager, true);
             return SortAndPage(items, totalRecordLimit, query, libraryManager, true);
         }
         }
 
 
-        public static QueryResult<BaseItem> SortAndPage(IEnumerable<BaseItem> items,
+        public static QueryResult<BaseItem> SortAndPage(
+            IEnumerable<BaseItem> items,
             int? totalRecordLimit,
             int? totalRecordLimit,
             InternalItemsQuery query,
             InternalItemsQuery query,
-            ILibraryManager libraryManager, bool enableSorting)
+            ILibraryManager libraryManager,
+            bool enableSorting)
         {
         {
             if (enableSorting)
             if (enableSorting)
             {
             {
-                if (query.OrderBy.Length > 0)
+                if (query.OrderBy.Count > 0)
                 {
                 {
                     items = libraryManager.Sort(items, query.User, query.OrderBy);
                     items = libraryManager.Sort(items, query.User, query.OrderBy);
                 }
                 }

+ 1 - 1
MediaBrowser.Controller/Playlists/Playlist.cs

@@ -181,7 +181,7 @@ namespace MediaBrowser.Controller.Playlists
                 {
                 {
                     Recursive = true,
                     Recursive = true,
                     IsFolder = false,
                     IsFolder = false,
-                    OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
+                    OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
                     MediaTypes = new[] { mediaType },
                     MediaTypes = new[] { mediaType },
                     EnableTotalRecordCount = false,
                     EnableTotalRecordCount = false,
                     DtoOptions = options
                     DtoOptions = options