From 6fb6b5f1766a1f37a61b9faaa40209bab995bf30 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 14 Apr 2024 08:18:36 -0600 Subject: Validate item access (#11171) --- Jellyfin.Api/Controllers/LibraryStructureController.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index 23c430f85..c1d01a5c2 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -6,6 +6,8 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LibraryStructureDto; using MediaBrowser.Common.Api; @@ -311,15 +313,21 @@ public class LibraryStructureController : BaseJellyfinApiController /// /// The library name and options. /// Library updated. + /// Item not found. /// A . [HttpPost("LibraryOptions")] [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateLibraryOptions( [FromBody] UpdateLibraryOptionsDto request) { - var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id); + var item = _libraryManager.GetItemById(request.Id, User.GetUserId()); + if (item is null) + { + return NotFound(); + } - collectionFolder.UpdateLibraryOptions(request.LibraryOptions); + item.UpdateLibraryOptions(request.LibraryOptions); return NoContent(); } } -- cgit v1.2.3 From bb018c4adc7916fafb7dac2db9a902be8d20e75d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 17 Apr 2024 18:44:50 +0200 Subject: Enable nullable for LibraryManager (#11191) --- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/LibraryManager.cs | 169 ++++++++++----------- .../Library/Validators/PeopleValidator.cs | 7 +- .../Controllers/LibraryStructureController.cs | 16 +- Jellyfin.Api/Helpers/MediaInfoHelper.cs | 4 +- Jellyfin.Api/Helpers/StreamingHelpers.cs | 4 +- .../Models/LibraryStructureDto/MediaPathDto.cs | 2 +- .../Routines/RemoveDownloadImagesInAdvance.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 37 +++-- .../Resolvers/IResolverIgnoreRule.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 2 +- 11 files changed, 121 insertions(+), 126 deletions(-) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 665d70a41..b01fd93a7 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Library } /// - public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent) + public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) { // Don't ignore application folders if (fileInfo.FullName.Contains(_serverApplicationPaths.RootFolderPath, StringComparison.InvariantCulture)) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 0a4432bec..03002300c 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -90,8 +88,8 @@ namespace Emby.Server.Implementations.Library /// /// The _root folder. /// - private volatile AggregateFolder _rootFolder; - private volatile UserRootFolder _userRootFolder; + private volatile AggregateFolder? _rootFolder; + private volatile UserRootFolder? _userRootFolder; private bool _wizardCompleted; @@ -156,17 +154,17 @@ namespace Emby.Server.Implementations.Library /// /// Occurs when [item added]. /// - public event EventHandler ItemAdded; + public event EventHandler? ItemAdded; /// /// Occurs when [item updated]. /// - public event EventHandler ItemUpdated; + public event EventHandler? ItemUpdated; /// /// Occurs when [item removed]. /// - public event EventHandler ItemRemoved; + public event EventHandler? ItemRemoved; /// /// Gets the root folder. @@ -265,7 +263,7 @@ namespace Emby.Server.Implementations.Library /// /// The sender. /// The instance containing the event data. - private void ConfigurationUpdated(object sender, EventArgs e) + private void ConfigurationUpdated(object? sender, EventArgs e) { var config = _configurationManager.Configuration; @@ -480,7 +478,7 @@ namespace Emby.Server.Implementations.Library /// The args. /// The resolvers. /// BaseItem. - private BaseItem ResolveItem(ItemResolveArgs args, IItemResolver[] resolvers) + private BaseItem? ResolveItem(ItemResolveArgs args, IItemResolver[]? resolvers) { var item = (resolvers ?? EntityResolvers).Select(r => Resolve(args, r)) .FirstOrDefault(i => i is not null); @@ -493,7 +491,7 @@ namespace Emby.Server.Implementations.Library return item; } - private BaseItem Resolve(ItemResolveArgs args, IItemResolver resolver) + private BaseItem? Resolve(ItemResolveArgs args, IItemResolver resolver) { try { @@ -535,16 +533,16 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, IDirectoryService directoryService = null) + public BaseItem? ResolvePath(FileSystemMetadata fileInfo, Folder? parent = null, IDirectoryService? directoryService = null) => ResolvePath(fileInfo, directoryService ?? new DirectoryService(_fileSystem), null, parent); - private BaseItem ResolvePath( + private BaseItem? ResolvePath( FileSystemMetadata fileInfo, IDirectoryService directoryService, - IItemResolver[] resolvers, - Folder parent = null, + IItemResolver[]? resolvers, + Folder? parent = null, CollectionType? collectionType = null, - LibraryOptions libraryOptions = null) + LibraryOptions? libraryOptions = null) { ArgumentNullException.ThrowIfNull(fileInfo); @@ -617,7 +615,7 @@ namespace Emby.Server.Implementations.Library return ResolveItem(args, resolvers); } - public bool IgnoreFile(FileSystemMetadata file, BaseItem parent) + public bool IgnoreFile(FileSystemMetadata file, BaseItem? parent) => EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)); public List NormalizeRootPathList(IEnumerable paths) @@ -692,16 +690,16 @@ namespace Emby.Server.Implementations.Library private IEnumerable ResolveFileList( IReadOnlyList fileList, IDirectoryService directoryService, - Folder parent, + Folder? parent, CollectionType? collectionType, - IItemResolver[] resolvers, + IItemResolver[]? resolvers, LibraryOptions libraryOptions) { // Given that fileList is a list we can save enumerator allocations by indexing for (var i = 0; i < fileList.Count; i++) { var file = fileList[i]; - BaseItem result = null; + BaseItem? result = null; try { result = ResolvePath(file, directoryService, resolvers, parent, collectionType, libraryOptions); @@ -730,7 +728,7 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? - ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) + (ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)) as Folder ?? throw new InvalidOperationException("Something went very wong")) .DeepCopy(); // In case program data folder was moved @@ -796,7 +794,7 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(userRootPath); var newItemId = GetNewItemId(userRootPath, typeof(UserRootFolder)); - UserRootFolder tmpItem = null; + UserRootFolder? tmpItem = null; try { tmpItem = GetItemById(newItemId) as UserRootFolder; @@ -809,7 +807,8 @@ namespace Emby.Server.Implementations.Library if (tmpItem is null) { _logger.LogDebug("Creating new userRootFolder with DeepCopy"); - tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy(); + tmpItem = (ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath)) as Folder ?? throw new InvalidOperationException("Failed to get user root path")) + .DeepCopy(); } // In case program data folder was moved @@ -828,7 +827,8 @@ namespace Emby.Server.Implementations.Library return _userRootFolder; } - public BaseItem FindByPath(string path, bool? isFolder) + /// + public BaseItem? FindByPath(string path, bool? isFolder) { // If this returns multiple items it could be tricky figuring out which one is correct. // In most cases, the newest one will be and the others obsolete but not yet cleaned up @@ -847,12 +847,8 @@ namespace Emby.Server.Implementations.Library .FirstOrDefault(); } - /// - /// Gets the person. - /// - /// The name. - /// Task{Person}. - public Person GetPerson(string name) + /// + public Person? GetPerson(string name) { var path = Person.GetPath(name); var id = GetItemByNameId(path); @@ -1159,7 +1155,7 @@ namespace Emby.Server.Implementations.Library .ToList(); } - private VirtualFolderInfo GetVirtualFolderInfo(string dir, List allCollectionFolders, HashSet refreshQueue) + private VirtualFolderInfo GetVirtualFolderInfo(string dir, List allCollectionFolders, HashSet? refreshQueue) { var info = new VirtualFolderInfo { @@ -1224,14 +1220,14 @@ namespace Emby.Server.Implementations.Library } /// - public BaseItem GetItemById(Guid id) + public BaseItem? GetItemById(Guid id) { if (id.IsEmpty()) { throw new ArgumentException("Guid can't be empty", nameof(id)); } - if (_cache.TryGetValue(id, out BaseItem item)) + if (_cache.TryGetValue(id, out BaseItem? item)) { return item; } @@ -1247,7 +1243,7 @@ namespace Emby.Server.Implementations.Library } /// - public T GetItemById(Guid id) + public T? GetItemById(Guid id) where T : BaseItem { var item = GetItemById(id); @@ -1260,7 +1256,7 @@ namespace Emby.Server.Implementations.Library } /// - public T GetItemById(Guid id, Guid userId) + public T? GetItemById(Guid id, Guid userId) where T : BaseItem { var user = userId.IsEmpty() ? null : _userManager.GetUserById(userId); @@ -1268,7 +1264,7 @@ namespace Emby.Server.Implementations.Library } /// - public T GetItemById(Guid id, User user) + public T? GetItemById(Guid id, User? user) where T : BaseItem { var item = GetItemById(id); @@ -1435,7 +1431,7 @@ namespace Emby.Server.Implementations.Library var parents = new BaseItem[len]; for (int i = 0; i < len; i++) { - parents[i] = GetItemById(ancestorIds[i]); + parents[i] = GetItemById(ancestorIds[i]) ?? throw new ArgumentException($"Failed to find parent with id: {ancestorIds[i]}"); if (parents[i] is not (ICollectionFolder or UserView)) { return; @@ -1449,7 +1445,7 @@ namespace Emby.Server.Implementations.Library // Prevent searching in all libraries due to empty filter if (query.TopParentIds.Length == 0) { - query.TopParentIds = new[] { Guid.NewGuid() }; + query.TopParentIds = [Guid.NewGuid()]; } } @@ -1546,7 +1542,7 @@ namespace Emby.Server.Implementations.Library } } - private IEnumerable GetTopParentIdsForQuery(BaseItem item, User user) + private IEnumerable GetTopParentIdsForQuery(BaseItem item, User? user) { if (item is UserView view) { @@ -1624,7 +1620,7 @@ namespace Emby.Server.Implementations.Library return items .SelectMany(i => i.ToArray()) .Select(ResolveIntro) - .Where(i => i is not null); + .Where(i => i is not null)!; // null values got filtered out } /// @@ -1653,9 +1649,9 @@ namespace Emby.Server.Implementations.Library /// /// The info. /// Video. - private Video ResolveIntro(IntroInfo info) + private Video? ResolveIntro(IntroInfo info) { - Video video = null; + Video? video = null; if (info.ItemId.HasValue) { @@ -1706,29 +1702,26 @@ namespace Emby.Server.Implementations.Library return video; } - /// - /// Sorts the specified sort by. - /// - /// The items. - /// The user. - /// The sort by. - /// The sort order. - /// IEnumerable{BaseItem}. - public IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder) + /// + public IEnumerable Sort(IEnumerable items, User? user, IEnumerable sortBy, SortOrder sortOrder) { var isFirst = true; - IOrderedEnumerable orderedItems = null; + IOrderedEnumerable? orderedItems = null; foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c is not null)) { if (isFirst) { - orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy); + orderedItems = sortOrder == SortOrder.Descending + ? items.OrderByDescending(i => i, orderBy) + : items.OrderBy(i => i, orderBy); } else { - orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy); + orderedItems = sortOrder == SortOrder.Descending + ? orderedItems!.ThenByDescending(i => i, orderBy) + : orderedItems!.ThenBy(i => i, orderBy); // orderedItems is set during the first iteration } isFirst = false; @@ -1737,11 +1730,12 @@ namespace Emby.Server.Implementations.Library return orderedItems ?? items; } - public IEnumerable Sort(IEnumerable items, User user, IEnumerable<(ItemSortBy OrderBy, SortOrder SortOrder)> orderBy) + /// + public IEnumerable Sort(IEnumerable items, User? user, IEnumerable<(ItemSortBy OrderBy, SortOrder SortOrder)> orderBy) { var isFirst = true; - IOrderedEnumerable orderedItems = null; + IOrderedEnumerable? orderedItems = null; foreach (var (name, sortOrder) in orderBy) { @@ -1753,11 +1747,15 @@ namespace Emby.Server.Implementations.Library if (isFirst) { - orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, comparer) : items.OrderBy(i => i, comparer); + orderedItems = sortOrder == SortOrder.Descending + ? items.OrderByDescending(i => i, comparer) + : items.OrderBy(i => i, comparer); } else { - orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, comparer) : orderedItems.ThenBy(i => i, comparer); + orderedItems = sortOrder == SortOrder.Descending + ? orderedItems!.ThenByDescending(i => i, comparer) + : orderedItems!.ThenBy(i => i, comparer); // orderedItems is set during the first iteration } isFirst = false; @@ -1772,14 +1770,14 @@ namespace Emby.Server.Implementations.Library /// The name. /// The user. /// IBaseItemComparer. - private IBaseItemComparer GetComparer(ItemSortBy name, User user) + private IBaseItemComparer? GetComparer(ItemSortBy name, User? user) { var comparer = Comparers.FirstOrDefault(c => name == c.Type); // If it requires a user, create a new one, and assign the user if (comparer is IUserBaseItemComparer) { - var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType()); + var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType())!; // only null for Nullable instances userComparer.User = user; userComparer.UserManager = _userManager; @@ -1791,23 +1789,14 @@ namespace Emby.Server.Implementations.Library return comparer; } - /// - /// Creates the item. - /// - /// The item. - /// The parent item. - public void CreateItem(BaseItem item, BaseItem parent) + /// + public void CreateItem(BaseItem item, BaseItem? parent) { CreateItems(new[] { item }, parent, CancellationToken.None); } - /// - /// Creates the items. - /// - /// The items. - /// The parent item. - /// The cancellation token. - public void CreateItems(IReadOnlyList items, BaseItem parent, CancellationToken cancellationToken) + /// + public void CreateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken) { _itemRepository.SaveItems(items, cancellationToken); @@ -2089,16 +2078,16 @@ namespace Emby.Server.Implementations.Library public LibraryOptions GetLibraryOptions(BaseItem item) { - if (item is not CollectionFolder collectionFolder) + if (item is CollectionFolder collectionFolder) { - // List.Find is more performant than FirstOrDefault due to enumerator allocation - collectionFolder = GetCollectionFolders(item) - .Find(folder => folder is CollectionFolder) as CollectionFolder; + return collectionFolder.GetLibraryOptions(); } - return collectionFolder is null - ? new LibraryOptions() - : collectionFolder.GetLibraryOptions(); + // List.Find is more performant than FirstOrDefault due to enumerator allocation + return GetCollectionFolders(item) + .Find(folder => folder is CollectionFolder) is CollectionFolder collectionFolder2 + ? collectionFolder2.GetLibraryOptions() + : new LibraryOptions(); } public CollectionType? GetContentType(BaseItem item) @@ -2452,7 +2441,7 @@ namespace Emby.Server.Implementations.Library { if (parentId.HasValue) { - return GetItemById(parentId.Value); + return GetItemById(parentId.Value) ?? throw new ArgumentException($"Invalid parent id: {parentId.Value}"); } if (!userId.IsNullOrEmpty()) @@ -2489,7 +2478,7 @@ namespace Emby.Server.Implementations.Library var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd; // TODO nullable - what are we trying to do there with empty episodeInfo? - EpisodeInfo episodeInfo = null; + EpisodeInfo? episodeInfo = null; if (episode.IsFileProtocol) { episodeInfo = resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming); @@ -2692,7 +2681,7 @@ namespace Emby.Server.Implementations.Library } } - BaseItem GetExtra(FileSystemMetadata file, ExtraType extraType) + BaseItem? GetExtra(FileSystemMetadata file, ExtraType extraType) { var extra = ResolvePath(_fileSystem.GetFileInfo(file.FullName), directoryService, _extraResolver.GetResolversForExtraType(extraType)); if (extra is not Video && extra is not Audio) @@ -2719,9 +2708,9 @@ namespace Emby.Server.Implementations.Library } } - public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem) + public string GetPathAfterNetworkSubstitution(string path, BaseItem? ownerItem) { - string newPath; + string? newPath; if (ownerItem is not null) { var libraryOptions = GetLibraryOptions(ownerItem); @@ -2795,8 +2784,8 @@ namespace Emby.Server.Implementations.Library } }) .Where(i => i is not null) - .Where(i => query.User is null || i.IsVisible(query.User)) - .ToList(); + .Where(i => query.User is null || i!.IsVisible(query.User)) + .ToList()!; // null values are filtered out } public List GetPeopleNames(InternalPeopleQuery query) @@ -2898,7 +2887,7 @@ namespace Emby.Server.Implementations.Library if (collectionType is not null) { - var path = Path.Combine(virtualFolderPath, collectionType.ToString().ToLowerInvariant() + ".collection"); + var path = Path.Combine(virtualFolderPath, collectionType.ToString()!.ToLowerInvariant() + ".collection"); // Can't be null with legal values? await File.WriteAllBytesAsync(path, Array.Empty()).ConfigureAwait(false); } @@ -2932,7 +2921,7 @@ namespace Emby.Server.Implementations.Library private async Task SavePeopleMetadataAsync(IEnumerable people, CancellationToken cancellationToken) { - List personsToSave = null; + List? personsToSave = null; foreach (var person in people) { @@ -3150,7 +3139,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(path)); } - List removeList = null; + List? removeList = null; foreach (var contentType in _configurationManager.Configuration.ContentTypes) { @@ -3204,7 +3193,7 @@ namespace Emby.Server.Implementations.Library CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions); } - private static bool ItemIsVisible(BaseItem item, User user) + private static bool ItemIsVisible(BaseItem? item, User? user) { if (item is null) { diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 601aab5b9..725b8f76c 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -64,6 +64,11 @@ namespace Emby.Server.Implementations.Library.Validators try { var item = _libraryManager.GetPerson(person); + if (item is null) + { + _logger.LogWarning("Failed to get person: {Name}", person); + continue; + } var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { @@ -92,7 +97,7 @@ namespace Emby.Server.Implementations.Library.Validators var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { BaseItemKind.Person }, + IncludeItemTypes = [BaseItemKind.Person], IsDeadPerson = true, IsLocked = false }); diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index c1d01a5c2..f685eeaa0 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -75,7 +75,7 @@ public class LibraryStructureController : BaseJellyfinApiController [HttpPost] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task AddVirtualFolder( - [FromQuery] string? name, + [FromQuery] string name, [FromQuery] CollectionTypeOptions? collectionType, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] paths, [FromBody] AddVirtualFolderDto? libraryOptionsDto, @@ -103,7 +103,7 @@ public class LibraryStructureController : BaseJellyfinApiController [HttpDelete] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RemoveVirtualFolder( - [FromQuery] string? name, + [FromQuery] string name, [FromQuery] bool refreshLibrary = false) { await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false); @@ -267,18 +267,16 @@ public class LibraryStructureController : BaseJellyfinApiController /// Whether to refresh the library. /// A . /// Media path removed. - /// The name of the library may not be empty. + /// The name of the library and path may not be empty. [HttpDelete("Paths")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RemoveMediaPath( - [FromQuery] string? name, - [FromQuery] string? path, + [FromQuery] string name, + [FromQuery] string path, [FromQuery] bool refreshLibrary = false) { - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentNullException(nameof(name)); - } + ArgumentException.ThrowIfNullOrWhiteSpace(name); + ArgumentException.ThrowIfNullOrWhiteSpace(path); _libraryMonitor.Stop(); diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 52e2e1df5..212d678a8 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -24,6 +24,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Helpers; @@ -398,7 +399,8 @@ public class MediaInfoHelper if (profile is not null) { - var item = _libraryManager.GetItemById(request.ItemId); + var item = _libraryManager.GetItemById(request.ItemId) + ?? throw new ResourceNotFoundException(); SetDeviceSpecificData( item, diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index ab4826369..d6d7a56eb 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -19,6 +19,7 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Net.Http.Headers; namespace Jellyfin.Api.Helpers; @@ -108,7 +109,8 @@ public static class StreamingHelpers ?? state.SupportedSubtitleCodecs.FirstOrDefault(); } - var item = libraryManager.GetItemById(streamingRequest.Id); + var item = libraryManager.GetItemById(streamingRequest.Id) + ?? throw new ResourceNotFoundException(); state.IsInputVideo = item.MediaType == MediaType.Video; diff --git a/Jellyfin.Api/Models/LibraryStructureDto/MediaPathDto.cs b/Jellyfin.Api/Models/LibraryStructureDto/MediaPathDto.cs index 94ffc5238..7a549aada 100644 --- a/Jellyfin.Api/Models/LibraryStructureDto/MediaPathDto.cs +++ b/Jellyfin.Api/Models/LibraryStructureDto/MediaPathDto.cs @@ -12,7 +12,7 @@ public class MediaPathDto /// Gets or sets the name of the library. /// [Required] - public string? Name { get; set; } + public required string Name { get; set; } /// /// Gets or sets the path to add. diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs index 9137ea234..52fb93d59 100644 --- a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs +++ b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs @@ -42,7 +42,7 @@ namespace Jellyfin.Server.Migrations.Routines } var libraryOptions = virtualFolder.LibraryOptions; - var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(folderId); + var collectionFolder = _libraryManager.GetItemById(folderId) ?? throw new InvalidOperationException("Failed to find CollectionFolder"); // The property no longer exists in LibraryOptions, so we just re-save the options to get old data removed. collectionFolder.UpdateLibraryOptions(libraryOptions); _logger.LogInformation("Removed from '{VirtualFolder}'", virtualFolder.Name); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index f0680f101..37703ceee 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CA1002, CS1591 using System; @@ -33,17 +31,17 @@ namespace MediaBrowser.Controller.Library /// /// Occurs when [item added]. /// - event EventHandler ItemAdded; + event EventHandler? ItemAdded; /// /// Occurs when [item updated]. /// - event EventHandler ItemUpdated; + event EventHandler? ItemUpdated; /// /// Occurs when [item removed]. /// - event EventHandler ItemRemoved; + event EventHandler? ItemRemoved; /// /// Gets the root folder. @@ -60,10 +58,10 @@ namespace MediaBrowser.Controller.Library /// The parent. /// An instance of . /// BaseItem. - BaseItem ResolvePath( + BaseItem? ResolvePath( FileSystemMetadata fileInfo, - Folder parent = null, - IDirectoryService directoryService = null); + Folder? parent = null, + IDirectoryService? directoryService = null); /// /// Resolves a set of files into a list of BaseItem. @@ -86,7 +84,7 @@ namespace MediaBrowser.Controller.Library /// /// The name of the person. /// Task{Person}. - Person GetPerson(string name); + Person? GetPerson(string name); /// /// Finds the by path. @@ -94,7 +92,7 @@ namespace MediaBrowser.Controller.Library /// The path. /// true is the path is a directory; otherwise false. /// BaseItem. - BaseItem FindByPath(string path, bool? isFolder); + BaseItem? FindByPath(string path, bool? isFolder); /// /// Gets the artist. @@ -166,7 +164,8 @@ namespace MediaBrowser.Controller.Library /// /// The id. /// BaseItem. - BaseItem GetItemById(Guid id); + /// is null. + BaseItem? GetItemById(Guid id); /// /// Gets the item by id, as T. @@ -174,7 +173,7 @@ namespace MediaBrowser.Controller.Library /// The item id. /// The type of item. /// The item. - T GetItemById(Guid id) + T? GetItemById(Guid id) where T : BaseItem; /// @@ -184,7 +183,7 @@ namespace MediaBrowser.Controller.Library /// The user id to validate against. /// The type of item. /// The item if found. - public T GetItemById(Guid id, Guid userId) + public T? GetItemById(Guid id, Guid userId) where T : BaseItem; /// @@ -194,7 +193,7 @@ namespace MediaBrowser.Controller.Library /// The user to validate against. /// The type of item. /// The item if found. - public T GetItemById(Guid id, User user) + public T? GetItemById(Guid id, User? user) where T : BaseItem; /// @@ -228,9 +227,9 @@ namespace MediaBrowser.Controller.Library /// The sort by. /// The sort order. /// IEnumerable{BaseItem}. - IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder); + IEnumerable Sort(IEnumerable items, User? user, IEnumerable sortBy, SortOrder sortOrder); - IEnumerable Sort(IEnumerable items, User user, IEnumerable<(ItemSortBy OrderBy, SortOrder SortOrder)> orderBy); + IEnumerable Sort(IEnumerable items, User? user, IEnumerable<(ItemSortBy OrderBy, SortOrder SortOrder)> orderBy); /// /// Gets the user root folder. @@ -243,7 +242,7 @@ namespace MediaBrowser.Controller.Library /// /// Item to create. /// Parent of new item. - void CreateItem(BaseItem item, BaseItem parent); + void CreateItem(BaseItem item, BaseItem? parent); /// /// Creates the items. @@ -251,7 +250,7 @@ namespace MediaBrowser.Controller.Library /// Items to create. /// Parent of new items. /// CancellationToken to use for operation. - void CreateItems(IReadOnlyList items, BaseItem parent, CancellationToken cancellationToken); + void CreateItems(IReadOnlyList items, BaseItem? parent, CancellationToken cancellationToken); /// /// Updates the item. @@ -529,7 +528,7 @@ namespace MediaBrowser.Controller.Library /// QueryResult<BaseItem>. QueryResult QueryItems(InternalItemsQuery query); - string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null); + string GetPathAfterNetworkSubstitution(string path, BaseItem? ownerItem = null); /// /// Converts the image to local. diff --git a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs index a07b3e898..733d40ba1 100644 --- a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs +++ b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs @@ -14,6 +14,6 @@ namespace MediaBrowser.Controller.Resolvers /// The file information. /// The parent BaseItem. /// True if the file should be ignored. - bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent); + bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent); } } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 1399ac307..b25cfc83f 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -947,7 +947,7 @@ namespace MediaBrowser.XbmcMetadata.Savers if (saveImagePath) { var personEntity = libraryManager.GetPerson(person.Name); - var image = personEntity.GetImageInfo(ImageType.Primary, 0); + var image = personEntity?.GetImageInfo(ImageType.Primary, 0); if (image is not null) { -- cgit v1.2.3 From 3feb3f81bfe848aa829e7c129bee3cd060c23c05 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 30 Apr 2024 21:32:59 +0200 Subject: More efficient array creation (#11468) --- .../AppBase/BaseConfigurationManager.cs | 8 ++------ .../Data/SqliteItemRepository.cs | 14 ++------------ Emby.Server.Implementations/Library/IgnorePatterns.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 9 ++------- Emby.Server.Implementations/Library/UserViewManager.cs | 4 ++-- .../Playlists/PlaylistManager.cs | 11 +++-------- .../ScheduledTasks/ScheduledTaskWorker.cs | 7 +++---- Emby.Server.Implementations/Session/SessionManager.cs | 11 ++++------- Jellyfin.Api/Controllers/ItemUpdateController.cs | 12 +++--------- Jellyfin.Api/Controllers/LibraryController.cs | 4 ++-- Jellyfin.Api/Controllers/LibraryStructureController.cs | 2 +- Jellyfin.Api/Controllers/UserViewsController.cs | 9 ++------- Jellyfin.Api/Extensions/DtoExtensions.cs | 12 ++---------- MediaBrowser.Controller/Entities/BaseItem.cs | 18 ++++-------------- MediaBrowser.Controller/Entities/Extensions.cs | 8 ++------ MediaBrowser.Controller/Entities/TagExtensions.cs | 4 ++-- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 4 ++-- .../Net/BasePeriodicWebSocketListener.cs | 2 +- MediaBrowser.Controller/Session/SessionInfo.cs | 4 +--- MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs | 4 +--- src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 2 +- src/Jellyfin.LiveTv/Listings/ListingsManager.cs | 14 ++++++-------- src/Jellyfin.LiveTv/LiveTvManager.cs | 2 +- src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs | 12 ++---------- src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs | 7 +++---- 25 files changed, 55 insertions(+), 131 deletions(-) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index a2f38c8c2..9e98d5ce0 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -127,15 +127,11 @@ namespace Emby.Server.Implementations.AppBase if (_configurationFactories is null) { - _configurationFactories = new[] { factory }; + _configurationFactories = [factory]; } else { - var oldLen = _configurationFactories.Length; - var arr = new IConfigurationFactory[oldLen + 1]; - _configurationFactories.CopyTo(arr, 0); - arr[oldLen] = factory; - _configurationFactories = arr; + _configurationFactories = [.._configurationFactories, factory]; } _configurationStores = _configurationFactories diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index e3015095c..9ef1bd66d 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2323,14 +2323,7 @@ namespace Emby.Server.Implementations.Data columns.Add(builder.ToString()); - var oldLen = query.ExcludeItemIds.Length; - var newLen = oldLen + item.ExtraIds.Length + 1; - var excludeIds = new Guid[newLen]; - query.ExcludeItemIds.CopyTo(excludeIds, 0); - excludeIds[oldLen] = item.Id; - item.ExtraIds.CopyTo(excludeIds, oldLen + 1); - - query.ExcludeItemIds = excludeIds; + query.ExcludeItemIds = [..query.ExcludeItemIds, item.Id, ..item.ExtraIds]; query.ExcludeProviderIds = item.ProviderIds; } @@ -2838,10 +2831,7 @@ namespace Emby.Server.Implementations.Data prepend.Add((ItemSortBy.Random, SortOrder.Ascending)); } - var arr = new (ItemSortBy, SortOrder)[prepend.Count + orderBy.Count]; - prepend.CopyTo(arr, 0); - orderBy.CopyTo(arr, prepend.Count); - orderBy = query.OrderBy = arr; + orderBy = query.OrderBy = [..prepend, ..orderBy]; } else if (orderBy.Count == 0) { diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs index cf6fc1845..a2301c8ae 100644 --- a/Emby.Server.Implementations/Library/IgnorePatterns.cs +++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs @@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.Library } }; - private static readonly Glob[] _globs = _patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray(); + private static readonly Glob[] _globs = Array.ConvertAll(_patterns, p => Glob.Parse(p, _globOptions)); /// /// Returns true if the supplied path should be ignored. diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 3e41a5048..3b5714f8e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -3038,9 +3038,7 @@ namespace Emby.Server.Implementations.Library { var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath); - var list = libraryOptions.PathInfos.ToList(); - list.Add(pathInfo); - libraryOptions.PathInfos = list.ToArray(); + libraryOptions.PathInfos = [..libraryOptions.PathInfos, pathInfo]; SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); @@ -3059,8 +3057,7 @@ namespace Emby.Server.Implementations.Library SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); - var list = libraryOptions.PathInfos.ToList(); - foreach (var originalPathInfo in list) + foreach (var originalPathInfo in libraryOptions.PathInfos) { if (string.Equals(mediaPath.Path, originalPathInfo.Path, StringComparison.Ordinal)) { @@ -3069,8 +3066,6 @@ namespace Emby.Server.Implementations.Library } } - libraryOptions.PathInfos = list.ToArray(); - CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions); } diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 83a66c8e4..d9a559014 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -303,8 +303,8 @@ namespace Emby.Server.Implementations.Library { // Handle situations with the grouping setting, e.g. movies showing up in tv, etc. // Thanks to mixed content libraries included in the UserView - var hasCollectionType = parents.OfType().ToArray(); - if (hasCollectionType.Length > 0) + var hasCollectionType = parents.OfType().ToList(); + if (hasCollectionType.Count > 0) { if (hasCollectionType.All(i => i.CollectionType == CollectionType.movies)) { diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 7a6cf9eff..6007591b2 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -226,13 +226,8 @@ namespace Emby.Server.Implementations.Playlists return; } - // Create a new array with the updated playlist items - var newLinkedChildren = new LinkedChild[playlist.LinkedChildren.Length + childrenToAdd.Count]; - playlist.LinkedChildren.CopyTo(newLinkedChildren, 0); - childrenToAdd.CopyTo(newLinkedChildren, playlist.LinkedChildren.Length); - // Update the playlist in the repository - playlist.LinkedChildren = newLinkedChildren; + playlist.LinkedChildren = [..playlist.LinkedChildren, ..childrenToAdd]; await UpdatePlaylistInternal(playlist).ConfigureAwait(false); @@ -526,8 +521,8 @@ namespace Emby.Server.Implementations.Playlists foreach (var playlist in playlists) { // Update owner if shared - var rankedShares = playlist.Shares.OrderByDescending(x => x.CanEdit).ToArray(); - if (rankedShares.Length > 0) + var rankedShares = playlist.Shares.OrderByDescending(x => x.CanEdit).ToList(); + if (rankedShares.Count > 0) { playlist.OwnerUserId = rankedShares[0].UserId; playlist.Shares = rankedShares.Skip(1).ToArray(); diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index efb6436ae..40e1bbf15 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -256,8 +256,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { get { - var triggers = InternalTriggers; - return triggers.Select(i => i.Item1).ToArray(); + return Array.ConvertAll(InternalTriggers, i => i.Item1); } set @@ -269,7 +268,7 @@ namespace Emby.Server.Implementations.ScheduledTasks SaveTriggers(triggerList); - InternalTriggers = triggerList.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); + InternalTriggers = Array.ConvertAll(triggerList, i => new Tuple(i, GetTrigger(i))); } } @@ -503,7 +502,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private Tuple[] LoadTriggers() { // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly - var settings = LoadTriggerSettings().Where(i => i is not null).ToArray(); + var settings = LoadTriggerSettings().Where(i => i is not null); return settings.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); } diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 06798628f..10d5b4f97 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -400,7 +400,7 @@ namespace Emby.Server.Implementations.Session { session.NowPlayingQueue = nowPlayingQueue; - var itemIds = nowPlayingQueue.Select(queue => queue.Id).ToArray(); + var itemIds = Array.ConvertAll(nowPlayingQueue, queue => queue.Id); session.NowPlayingQueueFullItems = _dtoService.GetBaseItemDtos( _libraryManager.GetItemList(new InternalItemsQuery { ItemIds = itemIds }), new DtoOptions(true)); @@ -1386,16 +1386,13 @@ namespace Emby.Server.Implementations.Session if (session.AdditionalUsers.All(i => !i.UserId.Equals(userId))) { var user = _userManager.GetUserById(userId); - - var list = session.AdditionalUsers.ToList(); - - list.Add(new SessionUserInfo + var newUser = new SessionUserInfo { UserId = userId, UserName = user.Username - }); + }; - session.AdditionalUsers = list.ToArray(); + session.AdditionalUsers = [..session.AdditionalUsers, newUser]; } } diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 56ef5f8f1..b4ce343be 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -264,7 +264,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (request.Studios is not null) { - item.Studios = request.Studios.Select(x => x.Name).ToArray(); + item.Studios = Array.ConvertAll(request.Studios, x => x.Name); } if (request.DateCreated.HasValue) @@ -379,10 +379,7 @@ public class ItemUpdateController : BaseJellyfinApiController { if (item is IHasAlbumArtist hasAlbumArtists) { - hasAlbumArtists.AlbumArtists = request - .AlbumArtists - .Select(i => i.Name) - .ToArray(); + hasAlbumArtists.AlbumArtists = Array.ConvertAll(request.AlbumArtists, i => i.Name); } } @@ -390,10 +387,7 @@ public class ItemUpdateController : BaseJellyfinApiController { if (item is IHasArtist hasArtists) { - hasArtists.Artists = request - .ArtistItems - .Select(i => i.Name) - .ToArray(); + hasArtists.Artists = Array.ConvertAll(request.ArtistItems, i => i.Name); } } diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 3b4e80ff3..64df4c4f0 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -158,13 +158,13 @@ public class LibraryController : BaseJellyfinApiController return NotFound(); } - IEnumerable themeItems; + IReadOnlyList themeItems; while (true) { themeItems = item.GetThemeSongs(); - if (themeItems.Any() || !inheritFromParent) + if (themeItems.Count > 0 || !inheritFromParent) { break; } diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index f685eeaa0..fb9f44d46 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -85,7 +85,7 @@ public class LibraryStructureController : BaseJellyfinApiController if (paths is not null && paths.Length > 0) { - libraryOptions.PathInfos = paths.Select(i => new MediaPathInfo(i)).ToArray(); + libraryOptions.PathInfos = Array.ConvertAll(paths, i => new MediaPathInfo(i)); } await _libraryManager.AddVirtualFolder(name, collectionType, libraryOptions, refreshLibrary).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index bf3ce1d39..01da50d02 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -85,16 +85,11 @@ public class UserViewsController : BaseJellyfinApiController var folders = _userViewManager.GetUserViews(query); var dtoOptions = new DtoOptions().AddClientFields(User); - var fields = dtoOptions.Fields.ToList(); - - fields.Add(ItemFields.PrimaryImageAspectRatio); - fields.Add(ItemFields.DisplayPreferencesId); - dtoOptions.Fields = fields.ToArray(); + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.PrimaryImageAspectRatio, ItemFields.DisplayPreferencesId]; var user = _userManager.GetUserById(userId.Value); - var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)) - .ToArray(); + var dtos = Array.ConvertAll(folders, i => _dtoService.GetBaseItemDto(i, dtoOptions, user)); return new QueryResult(dtos); } diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs index 7d9823c25..3d17dbda1 100644 --- a/Jellyfin.Api/Extensions/DtoExtensions.cs +++ b/Jellyfin.Api/Extensions/DtoExtensions.cs @@ -43,11 +43,7 @@ public static class DtoExtensions client.Contains("media center", StringComparison.OrdinalIgnoreCase) || client.Contains("classic", StringComparison.OrdinalIgnoreCase)) { - int oldLen = dtoOptions.Fields.Count; - var arr = new ItemFields[oldLen + 1]; - dtoOptions.Fields.CopyTo(arr, 0); - arr[oldLen] = ItemFields.RecursiveItemCount; - dtoOptions.Fields = arr; + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.RecursiveItemCount]; } } @@ -61,11 +57,7 @@ public static class DtoExtensions client.Contains("samsung", StringComparison.OrdinalIgnoreCase) || client.Contains("androidtv", StringComparison.OrdinalIgnoreCase)) { - int oldLen = dtoOptions.Fields.Count; - var arr = new ItemFields[oldLen + 1]; - dtoOptions.Fields.CopyTo(arr, 0); - arr[oldLen] = ItemFields.ChildCount; - dtoOptions.Fields = arr; + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.ChildCount]; } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 6c9097689..22793206e 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1779,14 +1779,11 @@ namespace MediaBrowser.Controller.Entities int curLen = current.Length; if (curLen == 0) { - Studios = new[] { name }; + Studios = [name]; } else { - var newArr = new string[curLen + 1]; - current.CopyTo(newArr, 0); - newArr[curLen] = name; - Studios = newArr; + Studios = [..current, name]; } } } @@ -1808,9 +1805,7 @@ namespace MediaBrowser.Controller.Entities var genres = Genres; if (!genres.Contains(name, StringComparison.OrdinalIgnoreCase)) { - var list = genres.ToList(); - list.Add(name); - Genres = list.ToArray(); + Genres = [..genres, name]; } } @@ -1980,12 +1975,7 @@ namespace MediaBrowser.Controller.Entities public void AddImage(ItemImageInfo image) { - var current = ImageInfos; - var currentCount = current.Length; - var newArr = new ItemImageInfo[currentCount + 1]; - current.CopyTo(newArr, 0); - newArr[currentCount] = image; - ImageInfos = newArr; + ImageInfos = [..ImageInfos, image]; } public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index 3005bee0a..c56603a3e 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -30,15 +30,11 @@ namespace MediaBrowser.Controller.Entities if (item.RemoteTrailers.Count == 0) { - item.RemoteTrailers = new[] { mediaUrl }; + item.RemoteTrailers = [mediaUrl]; } else { - var oldIds = item.RemoteTrailers; - var newIds = new MediaUrl[oldIds.Count + 1]; - oldIds.CopyTo(newIds); - newIds[oldIds.Count] = mediaUrl; - item.RemoteTrailers = newIds; + item.RemoteTrailers = [..item.RemoteTrailers, mediaUrl]; } } } diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs index ec3eb0f70..c1e4d1db2 100644 --- a/MediaBrowser.Controller/Entities/TagExtensions.cs +++ b/MediaBrowser.Controller/Entities/TagExtensions.cs @@ -21,11 +21,11 @@ namespace MediaBrowser.Controller.Entities { if (current.Length == 0) { - item.Tags = new[] { name }; + item.Tags = [name]; } else { - item.Tags = current.Concat(new[] { name }).ToArray(); + item.Tags = [..current, name]; } } } diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 6202f92f5..b558ef73d 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -116,8 +116,8 @@ namespace MediaBrowser.Controller.Library { get { - var paths = string.IsNullOrEmpty(Path) ? Array.Empty() : new[] { Path }; - return AdditionalLocations is null ? paths : paths.Concat(AdditionalLocations).ToArray(); + var paths = string.IsNullOrEmpty(Path) ? Array.Empty() : [Path]; + return AdditionalLocations is null ? paths : [..paths, ..AdditionalLocations]; } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 06386f2b8..a47d2fa45 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.Controller.Net lock (_activeConnectionsLock) { - foreach (var connection in _activeConnections.ToArray()) + foreach (var connection in _activeConnections.ToList()) { DisposeConnection(connection); } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 76d5d3a3f..9e3358818 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -270,9 +270,7 @@ namespace MediaBrowser.Controller.Session public void AddController(ISessionController controller) { - var controllers = SessionControllers.ToList(); - controllers.Add(controller); - SessionControllers = controllers.ToArray(); + SessionControllers = [..SessionControllers, controller]; } public bool ContainsUser(Guid userId) diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs index 16ea5e3ea..af867cd59 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs @@ -117,9 +117,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var artist = reader.ReadNormalizedString(); if (!string.IsNullOrEmpty(artist) && item is MusicVideo artistVideo) { - var list = artistVideo.Artists.ToList(); - list.Add(artist); - artistVideo.Artists = list.ToArray(); + artistVideo.Artists = [..artistVideo.Artists, artist]; } break; diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index cce2911dc..83f68ab50 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -1130,7 +1130,7 @@ namespace Jellyfin.LiveTv.Channels { if (!item.Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase)) { - item.Tags = item.Tags.Concat(new[] { "livestream" }).ToArray(); + item.Tags = [..item.Tags, "livestream"]; _logger.LogDebug("Forcing update due to Tags {0}", item.Name); forceUpdate = true; } diff --git a/src/Jellyfin.LiveTv/Listings/ListingsManager.cs b/src/Jellyfin.LiveTv/Listings/ListingsManager.cs index 87f47611e..dfd376092 100644 --- a/src/Jellyfin.LiveTv/Listings/ListingsManager.cs +++ b/src/Jellyfin.LiveTv/Listings/ListingsManager.cs @@ -60,14 +60,13 @@ public class ListingsManager : IListingsManager var config = _config.GetLiveTvConfiguration(); - var list = config.ListingProviders.ToList(); - int index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + var list = config.ListingProviders; + int index = Array.FindIndex(list, i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) { info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - list.Add(info); - config.ListingProviders = list.ToArray(); + config.ListingProviders = [..list, info]; } else { @@ -236,13 +235,12 @@ public class ListingsManager : IListingsManager if (!string.Equals(tunerChannelNumber, providerChannelNumber, StringComparison.OrdinalIgnoreCase)) { - var list = listingsProviderInfo.ChannelMappings.ToList(); - list.Add(new NameValuePair + var newItem = new NameValuePair { Name = tunerChannelNumber, Value = providerChannelNumber - }); - listingsProviderInfo.ChannelMappings = list.ToArray(); + }; + listingsProviderInfo.ChannelMappings = [..listingsProviderInfo.ChannelMappings, newItem]; } _config.SaveConfiguration("livetv", config); diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index c19d8195c..0c85dc434 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -939,7 +939,7 @@ namespace Jellyfin.LiveTv { var internalChannelId = _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId); var channel = _libraryManager.GetItemById(internalChannelId); - channelName = channel is null ? null : channel.Name; + channelName = channel?.Name; } return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName); diff --git a/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs b/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs index 18e4810a2..9e7323f5b 100644 --- a/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs +++ b/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs @@ -115,11 +115,7 @@ namespace Jellyfin.LiveTv.Timers throw new ArgumentException("item already exists", nameof(item)); } - int oldLen = _items.Length; - var newList = new T[oldLen + 1]; - _items.CopyTo(newList, 0); - newList[oldLen] = item; - _items = newList; + _items = [.._items, item]; SaveList(); } @@ -134,11 +130,7 @@ namespace Jellyfin.LiveTv.Timers int index = Array.FindIndex(_items, i => EqualityComparer(i, item)); if (index == -1) { - int oldLen = _items.Length; - var newList = new T[oldLen + 1]; - _items.CopyTo(newList, 0); - newList[oldLen] = item; - _items = newList; + _items = [.._items, item]; } else { diff --git a/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs b/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs index 60be19c68..473f00153 100644 --- a/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs +++ b/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs @@ -76,14 +76,13 @@ public class TunerHostManager : ITunerHostManager var config = _config.GetLiveTvConfiguration(); - var list = config.TunerHosts.ToList(); - var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + var list = config.TunerHosts; + var index = Array.FindIndex(list, i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) { info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - list.Add(info); - config.TunerHosts = list.ToArray(); + config.TunerHosts = [..list, info]; } else { -- cgit v1.2.3 From 4035f6aa218944ad40af04797d352ec00dc1714c Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sat, 1 Jun 2024 18:41:10 -0400 Subject: Backport pull request #11876 from jellyfin/release-10.9.z Don't check if admin has access to library when updating Original-merge: 563033786f82ae0a0b63d99f7a039cd0987c82bb Merged-by: crobibero Backported-by: Joshua M. Boniface --- Jellyfin.Api/Controllers/LibraryStructureController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index fb9f44d46..d268b93a8 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -319,7 +319,7 @@ public class LibraryStructureController : BaseJellyfinApiController public ActionResult UpdateLibraryOptions( [FromBody] UpdateLibraryOptionsDto request) { - var item = _libraryManager.GetItemById(request.Id, User.GetUserId()); + var item = _libraryManager.GetItemById(request.Id); if (item is null) { return NotFound(); -- cgit v1.2.3 From e2c4e52f398dc3fb45e2251ee291257594bcd7a5 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 30 May 2024 00:26:32 +0200 Subject: Add regressions tests for update library endpoint --- .../Controllers/LibraryStructureController.cs | 1 - MediaBrowser.Model/Entities/VirtualFolderInfo.cs | 2 - .../Controllers/LibraryStructureControllerTests.cs | 114 +++++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index d268b93a8..bff578feb 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index 89bb72c3c..ea3df3726 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -2,8 +2,6 @@ #pragma warning disable CS1591 using System; -using System.Text.Json.Serialization; -using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Model.Configuration; namespace MediaBrowser.Model.Entities diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs new file mode 100644 index 000000000..bf3bfdad4 --- /dev/null +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryStructureControllerTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http.Json; +using System.Text.Json; +using System.Threading.Tasks; +using Jellyfin.Api.Models.LibraryStructureDto; +using Jellyfin.Extensions.Json; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using Xunit; +using Xunit.Priority; + +namespace Jellyfin.Server.Integration.Tests.Controllers; + +[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)] +public sealed class LibraryStructureControllerTests : IClassFixture +{ + private readonly JellyfinApplicationFactory _factory; + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + private static string? _accessToken; + + public LibraryStructureControllerTests(JellyfinApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + [Priority(-1)] + public async Task Post_NewVirtualFolder_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + var body = new AddVirtualFolderDto() + { + LibraryOptions = new LibraryOptions() + { + Enabled = false + } + }; + + using var response = await client.PostAsJsonAsync("Library/VirtualFolders?name=test&refreshLibrary=true", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } + + [Fact] + [Priority(0)] + public async Task UpdateLibraryOptions_Invalid_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + var body = new UpdateLibraryOptionsDto() + { + Id = Guid.NewGuid(), + LibraryOptions = new LibraryOptions() + }; + + using var response = await client.PostAsJsonAsync("Library/VirtualFolders/LibraryOptions", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Priority(0)] + public async Task UpdateLibraryOptions_Valid_Success() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.GetAsync("Library/VirtualFolders"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var library = await response.Content.ReadFromJsonAsAsyncEnumerable(_jsonOptions) + .FirstOrDefaultAsync(x => string.Equals(x?.Name, "test", StringComparison.Ordinal)); + Assert.NotNull(library); + + var options = library.LibraryOptions; + Assert.NotNull(options); + Assert.False(options.Enabled); + options.Enabled = true; + + var body = new UpdateLibraryOptionsDto() + { + Id = Guid.Parse(library.ItemId), + LibraryOptions = options + }; + + using var response2 = await client.PostAsJsonAsync("Library/VirtualFolders/LibraryOptions", body, _jsonOptions); + Assert.Equal(HttpStatusCode.NoContent, response2.StatusCode); + } + + [Fact] + [Priority(1)] + public async Task DeleteLibrary_Invalid_NotFound() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.DeleteAsync("Library/VirtualFolders?name=doesntExist"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + [Priority(1)] + public async Task DeleteLibrary_Valid_Success() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); + + using var response = await client.DeleteAsync("Library/VirtualFolders?name=test&refreshLibrary=true"); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } +} -- cgit v1.2.3 From cd5fb8413603ea04249e016b83fe262aebdf351e Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 6 Jun 2024 14:30:34 -0400 Subject: Backport pull request #11963 from jellyfin/release-10.9.z Fix Library renaming Original-merge: b78efd6b1e90f925d85605132e337470065e7230 Merged-by: joshuaboniface Backported-by: Joshua M. Boniface --- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- Jellyfin.Api/Controllers/LibraryStructureController.cs | 16 +++++++++++++++- MediaBrowser.Controller/Library/ILibraryManager.cs | 8 ++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index e66f2496a..953fe19e0 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1029,7 +1029,7 @@ namespace Emby.Server.Implementations.Library } } - private async Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false) + public async Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false) { await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index bff578feb..b6de67e88 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -179,7 +179,21 @@ public class LibraryStructureController : BaseJellyfinApiController // No need to start if scanning the library because it will handle it if (refreshLibrary) { - await _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None).ConfigureAwait(false); + await _libraryManager.ValidateTopLibraryFolders(CancellationToken.None, true).ConfigureAwait(false); + var newLib = _libraryManager.GetUserRootFolder().Children.FirstOrDefault(f => f.Path.Equals(newPath, StringComparison.OrdinalIgnoreCase)); + if (newLib is CollectionFolder folder) + { + foreach (var child in folder.GetPhysicalFolders()) + { + await child.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + await child.ValidateChildren(new Progress(), CancellationToken.None).ConfigureAwait(false); + } + } + else + { + // We don't know if this one can be validated individually, trigger a new validation + await _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None).ConfigureAwait(false); + } } else { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 37703ceee..b802b7e6e 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -149,6 +149,14 @@ namespace MediaBrowser.Controller.Library /// Task. Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken); + /// + /// Reloads the root media folder. + /// + /// The cancellation token. + /// Is remove the library itself allowed. + /// Task. + Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false); + Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false); /// -- cgit v1.2.3 From f38ca3a392fa6658557c0fa099481aa45f8db54c Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 6 Jun 2024 21:07:22 +0200 Subject: Fix build --- Jellyfin.Api/Controllers/LibraryStructureController.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'Jellyfin.Api/Controllers/LibraryStructureController.cs') diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index b6de67e88..93c2393f3 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Extensions; -- cgit v1.2.3