From 4b01aaa0f7c52557d1500daaae2bc457a56dbffe Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 1 Mar 2023 00:44:57 +0100 Subject: Allocate less Lists --- Emby.Server.Implementations/Library/UserViewManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Library/UserViewManager.cs') diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 1137625f4..0e2d34d39 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -286,7 +286,7 @@ namespace Emby.Server.Implementations.Library if (parents.Count == 0) { - return new List(); + return Array.Empty(); } if (includeItemTypes.Length == 0) -- cgit v1.2.3 From d8ec3a5470fe602fab356c37720d38190aa713ef Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 1 Mar 2023 18:57:23 +0100 Subject: Reduce usage of GetAwaiter().GetResult() --- .../Channels/ChannelManager.cs | 24 +++++++++------- .../EntryPoints/LibraryChangedNotifier.cs | 18 ++++++++---- .../EntryPoints/UserDataChangeNotifier.cs | 13 +++++---- .../Library/UserViewManager.cs | 4 +-- .../LiveTv/LiveTvManager.cs | 32 +++++++++++----------- Jellyfin.Api/Controllers/ChannelsController.cs | 6 ++-- Jellyfin.Api/Controllers/LiveTvController.cs | 10 +++---- .../ActivityLogWebSocketListener.cs | 4 +-- .../Channels/IChannelManager.cs | 4 +-- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 4 +-- MediaBrowser.Model/Dlna/StreamBuilder.cs | 23 +++++----------- .../Plugins/StudioImages/StudiosImageProvider.cs | 2 +- 12 files changed, 74 insertions(+), 70 deletions(-) (limited to 'Emby.Server.Implementations/Library/UserViewManager.cs') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 1e3c4dea1..961e225e9 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -157,16 +157,16 @@ namespace Emby.Server.Implementations.Channels } /// - public QueryResult GetChannelsInternal(ChannelQuery query) + public async Task> GetChannelsInternalAsync(ChannelQuery query) { var user = query.UserId.Equals(default) ? null : _userManager.GetUserById(query.UserId); - var channels = GetAllChannels() - .Select(GetChannelEntity) + var channels = await GetAllChannelEntitiesAsync() .OrderBy(i => i.SortName) - .ToList(); + .ToListAsync() + .ConfigureAwait(false); if (query.IsRecordingsFolder.HasValue) { @@ -226,6 +226,7 @@ namespace Emby.Server.Implementations.Channels if (user is not null) { + var userId = user.Id.ToString("N", CultureInfo.InvariantCulture); channels = channels.Where(i => { if (!i.IsVisible(user)) @@ -235,7 +236,7 @@ namespace Emby.Server.Implementations.Channels try { - return GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N", CultureInfo.InvariantCulture)); + return GetChannelProvider(i).IsEnabledFor(userId); } catch { @@ -258,7 +259,7 @@ namespace Emby.Server.Implementations.Channels { foreach (var item in all) { - RefreshLatestChannelItems(GetChannelProvider(item), CancellationToken.None).GetAwaiter().GetResult(); + await RefreshLatestChannelItems(GetChannelProvider(item), CancellationToken.None).ConfigureAwait(false); } } @@ -269,13 +270,13 @@ namespace Emby.Server.Implementations.Channels } /// - public QueryResult GetChannels(ChannelQuery query) + public async Task> GetChannelsAsync(ChannelQuery query) { var user = query.UserId.Equals(default) ? null : _userManager.GetUserById(query.UserId); - var internalResult = GetChannelsInternal(query); + var internalResult = await GetChannelsInternalAsync(query).ConfigureAwait(false); var dtoOptions = new DtoOptions(); @@ -327,9 +328,12 @@ namespace Emby.Server.Implementations.Channels progress.Report(100); } - private Channel GetChannelEntity(IChannel channel) + private async IAsyncEnumerable GetAllChannelEntitiesAsync() { - return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).GetAwaiter().GetResult(); + foreach (IChannel channel in GetAllChannels()) + { + yield return GetChannel(GetInternalChannelId(channel.Name)) ?? await GetChannel(channel, CancellationToken.None).ConfigureAwait(false); + } } private MediaSourceInfo[] GetSavedMediaSources(BaseItem item) diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 05d0a9b79..2e3988f9e 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -276,25 +276,31 @@ namespace Emby.Server.Implementations.EntryPoints /// Libraries the update timer callback. /// /// The state. - private void LibraryUpdateTimerCallback(object state) + private async void LibraryUpdateTimerCallback(object state) { + List foldersAddedTo; + List foldersRemovedFrom; + List itemsUpdated; + List itemsAdded; + List itemsRemoved; lock (_libraryChangedSyncLock) { // Remove dupes in case some were saved multiple times - var foldersAddedTo = _foldersAddedTo + foldersAddedTo = _foldersAddedTo .DistinctBy(x => x.Id) .ToList(); - var foldersRemovedFrom = _foldersRemovedFrom + foldersRemovedFrom = _foldersRemovedFrom .DistinctBy(x => x.Id) .ToList(); - var itemsUpdated = _itemsUpdated + itemsUpdated = _itemsUpdated .Where(i => !_itemsAdded.Contains(i)) .DistinctBy(x => x.Id) .ToList(); - SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None).GetAwaiter().GetResult(); + itemsAdded = _itemsAdded.ToList(); + itemsRemoved = _itemsRemoved.ToList(); if (LibraryUpdateTimer is not null) { @@ -308,6 +314,8 @@ namespace Emby.Server.Implementations.EntryPoints _foldersAddedTo.Clear(); _foldersRemovedFrom.Clear(); } + + await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false); } /// diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index e724618b3..d32759017 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -87,29 +87,30 @@ namespace Emby.Server.Implementations.EntryPoints } } - private void UpdateTimerCallback(object? state) + private async void UpdateTimerCallback(object? state) { + List>> changes; lock (_syncLock) { // Remove dupes in case some were saved multiple times - var changes = _changedItems.ToList(); + changes = _changedItems.ToList(); _changedItems.Clear(); - SendNotifications(changes, CancellationToken.None).GetAwaiter().GetResult(); - if (_updateTimer is not null) { _updateTimer.Dispose(); _updateTimer = null; } } + + await SendNotifications(changes, CancellationToken.None).ConfigureAwait(false); } private async Task SendNotifications(List>> changes, CancellationToken cancellationToken) { - foreach (var pair in changes) + foreach ((var key, var value) in changes) { - await SendNotifications(pair.Key, pair.Value, cancellationToken).ConfigureAwait(false); + await SendNotifications(key, value, cancellationToken).ConfigureAwait(false); } } diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 0e2d34d39..17f1d1905 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -111,10 +111,10 @@ namespace Emby.Server.Implementations.Library if (query.IncludeExternalContent) { - var channelResult = _channelManager.GetChannelsInternal(new ChannelQuery + var channelResult = _channelManager.GetChannelsInternalAsync(new ChannelQuery { UserId = query.UserId - }); + }).GetAwaiter().GetResult(); var channels = channelResult.Items; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 4003468d0..ee039ff0f 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1312,20 +1312,19 @@ namespace Emby.Server.Implementations.LiveTv return 7; } - private QueryResult GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, User user) + private async Task> GetEmbyRecordingsAsync(RecordingQuery query, DtoOptions dtoOptions, User user) { if (user is null) { return new QueryResult(); } - var folderIds = GetRecordingFolders(user, true) - .Select(i => i.Id) - .ToList(); + var folders = await GetRecordingFoldersAsync(user, true).ConfigureAwait(false); + var folderIds = Array.ConvertAll(folders, x => x.Id); var excludeItemTypes = new List(); - if (folderIds.Count == 0) + if (folderIds.Length == 0) { return new QueryResult(); } @@ -1392,7 +1391,7 @@ namespace Emby.Server.Implementations.LiveTv { MediaTypes = new[] { MediaType.Video }, Recursive = true, - AncestorIds = folderIds.ToArray(), + AncestorIds = folderIds, IsFolder = false, IsVirtualItem = false, Limit = limit, @@ -1528,7 +1527,7 @@ namespace Emby.Server.Implementations.LiveTv } } - public QueryResult GetRecordings(RecordingQuery query, DtoOptions options) + public async Task> GetRecordingsAsync(RecordingQuery query, DtoOptions options) { var user = query.UserId.Equals(default) ? null @@ -1536,7 +1535,7 @@ namespace Emby.Server.Implementations.LiveTv RemoveFields(options); - var internalResult = GetEmbyRecordings(query, options, user); + var internalResult = await GetEmbyRecordingsAsync(query, options, user).ConfigureAwait(false); var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); @@ -2379,12 +2378,11 @@ namespace Emby.Server.Implementations.LiveTv return _tvDtoService.GetInternalProgramId(externalId); } - public List GetRecordingFolders(User user) - { - return GetRecordingFolders(user, false); - } + /// + public Task GetRecordingFoldersAsync(User user) + => GetRecordingFoldersAsync(user, false); - private List GetRecordingFolders(User user, bool refreshChannels) + private async Task GetRecordingFoldersAsync(User user, bool refreshChannels) { var folders = EmbyTV.EmbyTV.Current.GetRecordingFolders() .SelectMany(i => i.Locations) @@ -2396,14 +2394,16 @@ namespace Emby.Server.Implementations.LiveTv .OrderBy(i => i.SortName) .ToList(); - folders.AddRange(_channelManager.GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery + var channels = await _channelManager.GetChannelsInternalAsync(new MediaBrowser.Model.Channels.ChannelQuery { UserId = user.Id, IsRecordingsFolder = true, RefreshLatestChannelItems = refreshChannels - }).Items); + }).ConfigureAwait(false); + + folders.AddRange(channels.Items); - return folders.Cast().ToList(); + return folders.Cast().ToArray(); } } } diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index b5c4d8346..11c4ac376 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -52,7 +52,7 @@ public class ChannelsController : BaseJellyfinApiController /// An containing the channels. [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetChannels( + public async Task>> GetChannels( [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, @@ -61,7 +61,7 @@ public class ChannelsController : BaseJellyfinApiController [FromQuery] bool? isFavorite) { userId = RequestHelpers.GetUserId(User, userId); - return _channelManager.GetChannels(new ChannelQuery + return await _channelManager.GetChannelsAsync(new ChannelQuery { Limit = limit, StartIndex = startIndex, @@ -69,7 +69,7 @@ public class ChannelsController : BaseJellyfinApiController SupportsLatestItems = supportsLatestItems, SupportsMediaDeletion = supportsMediaDeletion, IsFavorite = isFavorite - }); + }).ConfigureAwait(false); } /// diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 96fc91f93..267ba4afb 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -252,7 +252,7 @@ public class LiveTvController : BaseJellyfinApiController [HttpGet("Recordings")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.LiveTvAccess)] - public ActionResult> GetRecordings( + public async Task>> GetRecordings( [FromQuery] string? channelId, [FromQuery] Guid? userId, [FromQuery] int? startIndex, @@ -278,7 +278,7 @@ public class LiveTvController : BaseJellyfinApiController .AddClientFields(User) .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); - return _liveTvManager.GetRecordings( + return await _liveTvManager.GetRecordingsAsync( new RecordingQuery { ChannelId = channelId, @@ -299,7 +299,7 @@ public class LiveTvController : BaseJellyfinApiController ImageTypeLimit = imageTypeLimit, EnableImages = enableImages }, - dtoOptions); + dtoOptions).ConfigureAwait(false); } /// @@ -383,13 +383,13 @@ public class LiveTvController : BaseJellyfinApiController [HttpGet("Recordings/Folders")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.LiveTvAccess)] - public ActionResult> GetRecordingFolders([FromQuery] Guid? userId) + public async Task>> GetRecordingFolders([FromQuery] Guid? userId) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.Value.Equals(default) ? null : _userManager.GetUserById(userId.Value); - var folders = _liveTvManager.GetRecordingFolders(user); + var folders = await _liveTvManager.GetRecordingFoldersAsync(user).ConfigureAwait(false); var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user); diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 3eac81419..4a5e0ecd4 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -56,8 +56,8 @@ public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener e) + private async void OnEntryCreated(object? sender, GenericEventArgs e) { - SendData(true).GetAwaiter().GetResult(); + await SendData(true).ConfigureAwait(false); } } diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index e392a3493..8eb27888a 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -46,14 +46,14 @@ namespace MediaBrowser.Controller.Channels /// /// The query. /// The channels. - QueryResult GetChannelsInternal(ChannelQuery query); + Task> GetChannelsInternalAsync(ChannelQuery query); /// /// Gets the channels. /// /// The query. /// The channels. - QueryResult GetChannels(ChannelQuery query); + Task> GetChannelsAsync(ChannelQuery query); /// /// Gets the latest channel items. diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 46bdca302..3b6a16dee 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.LiveTv /// The query. /// The options. /// A recording. - QueryResult GetRecordings(RecordingQuery query, DtoOptions options); + Task> GetRecordingsAsync(RecordingQuery query, DtoOptions options); /// /// Gets the timers. @@ -308,6 +308,6 @@ namespace MediaBrowser.Controller.LiveTv void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null); - List GetRecordingFolders(User user); + Task GetRecordingFoldersAsync(User user); } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 6f99bbc13..84c8c012c 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -44,32 +44,24 @@ namespace MediaBrowser.Model.Dlna { ValidateMediaOptions(options, false); - var mediaSources = new List(); + var streams = new List(); foreach (var mediaSource in options.MediaSources) { - if (string.IsNullOrEmpty(options.MediaSourceId) - || string.Equals(mediaSource.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase)) + if (!(string.IsNullOrEmpty(options.MediaSourceId) + || string.Equals(mediaSource.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))) { - mediaSources.Add(mediaSource); + continue; } - } - var streams = new List(); - foreach (var mediaSourceInfo in mediaSources) - { - StreamInfo? streamInfo = GetOptimalAudioStream(mediaSourceInfo, options); + StreamInfo? streamInfo = GetOptimalAudioStream(mediaSource, options); if (streamInfo is not null) { + streamInfo.DeviceId = options.DeviceId; + streamInfo.DeviceProfileId = options.Profile.Id; streams.Add(streamInfo); } } - foreach (var stream in streams) - { - stream.DeviceId = options.DeviceId; - stream.DeviceProfileId = options.Profile.Id; - } - return GetOptimalStream(streams, options.GetMaxBitrate(true) ?? 0); } @@ -399,7 +391,6 @@ namespace MediaBrowser.Model.Dlna return (null, null, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles)); } - var playMethods = new List(); TranscodeReason transcodeReasons = 0; // The profile describes what the device supports diff --git a/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs b/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs index 0fb9d30a6..ae244da19 100644 --- a/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/StudioImages/StudiosImageProvider.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.Plugins.StudioImages /// public IEnumerable GetSupportedImages(BaseItem item) { - return new List + return new ImageType[] { ImageType.Thumb }; -- cgit v1.2.3 From eb52af4e6ab0a81b026063b2dd43dd81a1a08b8e Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 15 May 2023 14:45:33 +0200 Subject: Fix playlists library and migration (#9770) --- .../Library/UserViewManager.cs | 20 ++++++++++++----- .../Playlists/PlaylistManager.cs | 25 +++------------------- .../Playlists/PlaylistsFolder.cs | 6 ------ Jellyfin.Api/Controllers/ItemsController.cs | 7 ++++-- Jellyfin.Api/Controllers/PlaylistsController.cs | 10 --------- .../Migrations/Routines/FixPlaylistOwner.cs | 6 ++++-- .../Playlists/IPlaylistManager.cs | 7 +++--- 7 files changed, 30 insertions(+), 51 deletions(-) (limited to 'Emby.Server.Implementations/Library/UserViewManager.cs') diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 17f1d1905..2c3dc1857 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -46,10 +46,9 @@ namespace Emby.Server.Implementations.Library public Folder[] GetUserViews(UserViewQuery query) { var user = _userManager.GetUserById(query.UserId); - if (user is null) { - throw new ArgumentException("User Id specified in the query does not exist.", nameof(query)); + throw new ArgumentException("User id specified in the query does not exist.", nameof(query)); } var folders = _libraryManager.GetUserRootFolder() @@ -58,7 +57,6 @@ namespace Emby.Server.Implementations.Library .ToList(); var groupedFolders = new List(); - var list = new List(); foreach (var folder in folders) @@ -66,6 +64,20 @@ namespace Emby.Server.Implementations.Library var collectionFolder = folder as ICollectionFolder; var folderViewType = collectionFolder?.CollectionType; + // Playlist library requires special handling because the folder only refrences user playlists + if (string.Equals(folderViewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) + { + var items = folder.GetItemList(new InternalItemsQuery(user) + { + ParentId = folder.ParentId + }); + + if (!items.Any(item => item.IsVisible(user))) + { + continue; + } + } + if (UserView.IsUserSpecific(folder)) { list.Add(_libraryManager.GetNamedView(user, folder.Name, folder.Id, folderViewType, null)); @@ -132,14 +144,12 @@ namespace Emby.Server.Implementations.Library } var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList(); - var orders = user.GetPreferenceValues(PreferenceKind.OrderedViews); return list .OrderBy(i => { var index = Array.IndexOf(orders, i.Id); - if (index == -1 && i is UserView view && !view.DisplayParentId.Equals(default)) diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index adb8ac732..702f8d45b 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -67,9 +67,8 @@ namespace Emby.Server.Implementations.Playlists public async Task CreatePlaylist(PlaylistCreationRequest options) { var name = options.Name; - var folderName = _fileSystem.GetValidFilename(name); - var parentFolder = GetPlaylistsFolder(Guid.Empty); + var parentFolder = GetPlaylistsFolder(options.UserId); if (parentFolder is null) { throw new ArgumentException(nameof(parentFolder)); @@ -80,7 +79,6 @@ namespace Emby.Server.Implementations.Playlists foreach (var itemId in options.ItemIdList) { var item = _libraryManager.GetItemById(itemId); - if (item is null) { throw new ArgumentException("No item exists with the supplied Id"); @@ -121,7 +119,6 @@ namespace Emby.Server.Implementations.Playlists } var user = _userManager.GetUserById(options.UserId); - var path = Path.Combine(parentFolder.Path, folderName); path = GetTargetPath(path); @@ -130,7 +127,6 @@ namespace Emby.Server.Implementations.Playlists try { Directory.CreateDirectory(path); - var playlist = new Playlist { Name = name, @@ -140,7 +136,6 @@ namespace Emby.Server.Implementations.Playlists }; playlist.SetMediaType(options.MediaType); - parentFolder.AddChild(playlist); await playlist.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ForceSave = true }, CancellationToken.None) @@ -326,7 +321,8 @@ namespace Emby.Server.Implementations.Playlists } } - private void SavePlaylistFile(Playlist item) + /// + public void SavePlaylistFile(Playlist item) { // this is probably best done as a metadata provider // saving a file over itself will require some work to prevent this from happening when not needed @@ -564,20 +560,5 @@ namespace Emby.Server.Implementations.Playlists } } } - - /// - public async Task UpdatePlaylistAsync(Playlist playlist) - { - var currentPlaylist = (Playlist)_libraryManager.GetItemById(playlist.Id); - currentPlaylist.OwnerUserId = playlist.OwnerUserId; - currentPlaylist.Shares = playlist.Shares; - - await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - - if (currentPlaylist.IsFile) - { - SavePlaylistFile(currentPlaylist); - } - } } } diff --git a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs index e2f2e436f..549209715 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs @@ -27,11 +27,6 @@ namespace Emby.Server.Implementations.Playlists [JsonIgnore] public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; - public override bool IsVisible(User user) - { - return base.IsVisible(user) && GetChildren(user, true).Any(); - } - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) { return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); @@ -47,7 +42,6 @@ namespace Emby.Server.Implementations.Playlists query.Recursive = true; query.IncludeItemTypes = new[] { BaseItemKind.Playlist }; - query.Parent = null; return LibraryManager.GetItemsResult(query); } diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 377526729..d4116116b 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -503,6 +503,7 @@ public class ItemsController : BaseJellyfinApiController } } + query.Parent = null; result = folder.GetItems(query); } else @@ -511,10 +512,12 @@ public class ItemsController : BaseJellyfinApiController result = new QueryResult(itemsArray); } + // result might include items not accessible by the user, DtoService will remove them + var accessibleItems = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user); return new QueryResult( startIndex, - result.TotalRecordCount, - _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user)); + accessibleItems.Count, + accessibleItems); } /// diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 20995bf1b..8d2a738d4 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -65,14 +65,12 @@ public class PlaylistsController : BaseJellyfinApiController /// The media type. /// The create playlist payload. /// Playlist created. - /// User does not have permission to create playlists. /// /// A that represents the asynchronous operation to create a playlist. /// The task result contains an indicating success. /// [HttpPost] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> CreatePlaylist( [FromQuery, ParameterObsolete] string? name, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder)), ParameterObsolete] IReadOnlyList ids, @@ -105,11 +103,9 @@ public class PlaylistsController : BaseJellyfinApiController /// Item id, comma delimited. /// The userId. /// Items added to playlist. - /// User does not have permission to add items to playlist. /// An on success. [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task AddToPlaylist( [FromRoute, Required] Guid playlistId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, @@ -127,11 +123,9 @@ public class PlaylistsController : BaseJellyfinApiController /// The item id. /// The new index. /// Item moved to new index. - /// User does not have permission to move item. /// An on success. [HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")] [ProducesResponseType(StatusCodes.Status204NoContent)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task MoveItem( [FromRoute, Required] string playlistId, [FromRoute, Required] string itemId, @@ -147,11 +141,9 @@ public class PlaylistsController : BaseJellyfinApiController /// The playlist id. /// The item ids, comma delimited. /// Items removed. - /// User does not have permission to get playlist. /// An on success. [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task RemoveFromPlaylist( [FromRoute, Required] string playlistId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] entryIds) @@ -173,12 +165,10 @@ public class PlaylistsController : BaseJellyfinApiController /// Optional. The max number of images to return, per image type. /// Optional. The image types to include in the output. /// Original playlist returned. - /// User does not have permission to get playlist items. /// Playlist not found. /// The original playlist items. [HttpGet("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetPlaylistItems( [FromRoute, Required] Guid playlistId, diff --git a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs index 1dd938b1b..cf3182003 100644 --- a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs +++ b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; @@ -60,13 +61,14 @@ internal class FixPlaylistOwner : IMigrationRoutine { playlist.OwnerUserId = guid; playlist.Shares = shares.Where(x => x != firstEditShare).ToArray(); - _playlistManager.UpdatePlaylistAsync(playlist).GetAwaiter().GetResult(); + playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult(); + _playlistManager.SavePlaylistFile(playlist); } } else { playlist.OpenAccess = true; - _playlistManager.UpdatePlaylistAsync(playlist).GetAwaiter().GetResult(); + playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult(); } } } diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index d88943662..d1a51c2cf 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -66,10 +66,9 @@ namespace MediaBrowser.Controller.Playlists Task RemovePlaylistsAsync(Guid userId); /// - /// Updates a playlist. + /// Saves a playlist. /// - /// The updated playlist. - /// Task. - Task UpdatePlaylistAsync(Playlist playlist); + /// The playlist. + void SavePlaylistFile(Playlist item); } } -- cgit v1.2.3