diff options
Diffstat (limited to 'MediaBrowser.Controller/Entities/Folder.cs')
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 286 |
1 files changed, 146 insertions, 140 deletions
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index cac5026f7..dd08c31ed 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,8 +1,9 @@ -#pragma warning disable CS1591 +#nullable disable + +#pragma warning disable CA1002, CA1721, CA1819, CS1591 using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Text.Json.Serialization; @@ -36,6 +37,11 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class Folder : BaseItem { + public Folder() + { + LinkedChildren = Array.Empty<LinkedChild>(); + } + public static IUserViewManager UserViewManager { get; set; } /// <summary> @@ -49,11 +55,6 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public DateTime? DateLastMediaAdded { get; set; } - public Folder() - { - LinkedChildren = Array.Empty<LinkedChild>(); - } - [JsonIgnore] public override bool SupportsThemeMedia => true; @@ -85,6 +86,87 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public virtual bool SupportsDateLastMediaAdded => false; + [JsonIgnore] + public override string FileNameWithoutExtension + { + get + { + if (IsFileProtocol) + { + return System.IO.Path.GetFileName(Path); + } + + return null; + } + } + + /// <summary> + /// Gets the actual children. + /// </summary> + /// <value>The actual children.</value> + [JsonIgnore] + public virtual IEnumerable<BaseItem> Children => LoadChildren(); + + /// <summary> + /// Gets thread-safe access to all recursive children of this folder - without regard to user. + /// </summary> + /// <value>The recursive children.</value> + [JsonIgnore] + public IEnumerable<BaseItem> RecursiveChildren => GetRecursiveChildren(); + + [JsonIgnore] + protected virtual bool SupportsShortcutChildren => false; + + protected virtual bool FilterLinkedChildrenPerUser => false; + + [JsonIgnore] + protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren; + + [JsonIgnore] + public virtual bool SupportsUserDataFromChildren + { + get + { + // These are just far too slow. + if (this is ICollectionFolder) + { + return false; + } + + if (this is UserView) + { + return false; + } + + if (this is UserRootFolder) + { + return false; + } + + if (this is Channel) + { + return false; + } + + if (SourceType != SourceType.Library) + { + return false; + } + + if (this is IItemByName) + { + if (this is not IHasDualAccess hasDualAccess || hasDualAccess.IsAccessedByName) + { + return false; + } + } + + return true; + } + } + + public static ICollectionManager CollectionManager { get; set; } + public override bool CanDelete() { if (IsRoot) @@ -107,20 +189,6 @@ namespace MediaBrowser.Controller.Entities return baseResult; } - [JsonIgnore] - public override string FileNameWithoutExtension - { - get - { - if (IsFileProtocol) - { - return System.IO.Path.GetFileName(Path); - } - - return null; - } - } - protected override bool IsAllowTagFilterEnforced() { if (this is ICollectionFolder) @@ -136,17 +204,12 @@ namespace MediaBrowser.Controller.Entities return true; } - [JsonIgnore] - protected virtual bool SupportsShortcutChildren => false; - /// <summary> /// Adds the child. /// </summary> /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - /// <exception cref="InvalidOperationException">Unable to add + item.Name</exception> - public void AddChild(BaseItem item, CancellationToken cancellationToken) + /// <exception cref="InvalidOperationException">Unable to add + item.Name.</exception> + public void AddChild(BaseItem item) { item.SetParent(this); @@ -168,23 +231,9 @@ namespace MediaBrowser.Controller.Entities LibraryManager.CreateItem(item, this); } - /// <summary> - /// Gets the actual children. - /// </summary> - /// <value>The actual children.</value> - [JsonIgnore] - public virtual IEnumerable<BaseItem> Children => LoadChildren(); - - /// <summary> - /// thread-safe access to all recursive children of this folder - without regard to user. - /// </summary> - /// <value>The recursive children.</value> - [JsonIgnore] - public IEnumerable<BaseItem> RecursiveChildren => GetRecursiveChildren(); - public override bool IsVisible(User user) { - if (this is ICollectionFolder && !(this is BasePluginFolder)) + if (this is ICollectionFolder && this is not BasePluginFolder) { var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders); if (blockedMediaFolders.Length > 0) @@ -211,6 +260,7 @@ namespace MediaBrowser.Controller.Entities /// Loads our children. Validation will occur externally. /// We want this synchronous. /// </summary> + /// <returns>Returns children.</returns> protected virtual List<BaseItem> LoadChildren() { // logger.LogDebug("Loading children from {0} {1} {2}", GetType().Name, Id, Path); @@ -225,20 +275,20 @@ namespace MediaBrowser.Controller.Entities public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken) { - return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem))); + return ValidateChildren(progress, new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken: cancellationToken); } /// <summary> /// Validates that the children of the folder still exist. /// </summary> /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> /// <param name="metadataRefreshOptions">The metadata refresh options.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true) + public Task ValidateChildren(IProgress<double> progress, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true, CancellationToken cancellationToken = default) { - return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); + return ValidateChildrenInternal(progress, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService, cancellationToken); } private Dictionary<Guid, BaseItem> GetActualChildrenDictionary() @@ -278,13 +328,13 @@ namespace MediaBrowser.Controller.Entities /// Validates the children internal. /// </summary> /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="directoryService">The directory service.</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { if (recursive) { @@ -293,7 +343,7 @@ namespace MediaBrowser.Controller.Entities try { - await ValidateChildrenInternal2(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false); + await ValidateChildrenInternal2(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken).ConfigureAwait(false); } finally { @@ -304,7 +354,7 @@ namespace MediaBrowser.Controller.Entities } } - private async Task ValidateChildrenInternal2(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + private async Task ValidateChildrenInternal2(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -526,7 +576,7 @@ namespace MediaBrowser.Controller.Entities private Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken) { return RunTasks( - (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService), + (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, null, directoryService, cancellationToken), children, progress, cancellationToken); @@ -595,6 +645,8 @@ namespace MediaBrowser.Controller.Entities /// Get the children of this folder from the actual file system. /// </summary> /// <returns>IEnumerable{BaseItem}.</returns> + /// <param name="directoryService">The directory service to use for operation.</param> + /// <returns>Returns set of base items.</returns> protected virtual IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService) { var collectionType = LibraryManager.GetContentType(this); @@ -621,7 +673,7 @@ namespace MediaBrowser.Controller.Entities { if (LinkedChildren.Length > 0) { - if (!(this is ICollectionFolder)) + if (this is not ICollectionFolder) { return GetChildren(user, true).Count; } @@ -678,7 +730,7 @@ namespace MediaBrowser.Controller.Entities return PostFilterAndSort(items, query, true); } - if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty) + if (this is not UserRootFolder && this is not AggregateFolder && query.ParentId == Guid.Empty) { query.Parent = this; } @@ -753,7 +805,7 @@ namespace MediaBrowser.Controller.Entities { if (LinkedChildren.Length > 0) { - if (!(this is ICollectionFolder)) + if (this is not ICollectionFolder) { Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name); return true; @@ -939,14 +991,18 @@ namespace MediaBrowser.Controller.Entities } else { - items = GetChildren(user, true).Where(filter); + // need to pass this param to the children. + var childQuery = new InternalItemsQuery + { + DisplayAlbumFolders = query.DisplayAlbumFolders + }; + + items = GetChildren(user, true, childQuery).Where(filter); } return PostFilterAndSort(items, query, true); } - public static ICollectionManager CollectionManager { get; set; } - protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query, bool enableSorting) { var user = query.User; @@ -964,7 +1020,7 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrEmpty(query.NameStartsWith)) { - items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.OrdinalIgnoreCase)); + items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase)); } if (!string.IsNullOrEmpty(query.NameLessThan)) @@ -1275,10 +1331,23 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Adds the children to list. /// </summary> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool recursive, InternalItemsQuery query) { - foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) + // If Query.AlbumFolders is set, then enforce the format as per the db in that it permits sub-folders in music albums. + IEnumerable<BaseItem> children = null; + if ((query?.DisplayAlbumFolders ?? false) && (this is MusicAlbum)) + { + children = Children; + query = null; + } + + // If there are not sub-folders, proceed as normal. + if (children == null) + { + children = GetEligibleChildrenForRecursiveChildren(user); + } + + foreach (var child in children) { bool? isVisibleToUser = null; @@ -1318,18 +1387,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Gets allowed recursive children of an item. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> - /// <returns>IEnumerable{BaseItem}.</returns> - /// <exception cref="ArgumentNullException"></exception> - public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) - { - return GetRecursiveChildren(user, null); - } - public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query) { if (user == null) @@ -1427,16 +1484,19 @@ namespace MediaBrowser.Controller.Entities return list; } - protected virtual bool FilterLinkedChildrenPerUser => false; - public bool ContainsLinkedChildByItemId(Guid itemId) { var linkedChildren = LinkedChildren; foreach (var i in linkedChildren) { - if (i.ItemId.HasValue && i.ItemId.Value == itemId) + if (i.ItemId.HasValue) { - return true; + if (i.ItemId.Value == itemId) + { + return true; + } + + continue; } var child = GetLinkedChild(i); @@ -1485,7 +1545,7 @@ namespace MediaBrowser.Controller.Entities var childOwner = child.GetOwner() ?? child; - if (childOwner != null && !(child is IItemByName)) + if (child is not IItemByName) { var childProtocol = childOwner.PathProtocol; if (!childProtocol.HasValue || childProtocol.Value != Model.MediaInfo.MediaProtocol.File) @@ -1524,9 +1584,6 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Item2 != null); } - [JsonIgnore] - protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren; - protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1547,7 +1604,8 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Refreshes the linked children. /// </summary> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + /// <param name="fileSystemChildren">The enumerable of file system metadata.</param> + /// <returns><c>true</c> if the linked children were updated, <c>false</c> otherwise.</returns> protected virtual bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren) { if (SupportsShortcutChildren) @@ -1611,7 +1669,6 @@ namespace MediaBrowser.Controller.Entities /// <param name="user">The user.</param> /// <param name="datePlayed">The date played.</param> /// <param name="resetPosition">if set to <c>true</c> [reset position].</param> - /// <returns>Task.</returns> public override void MarkPlayed( User user, DateTime? datePlayed, @@ -1653,7 +1710,6 @@ namespace MediaBrowser.Controller.Entities /// Marks the unplayed. /// </summary> /// <param name="user">The user.</param> - /// <returns>Task.</returns> public override void MarkUnplayed(User user) { var itemsResult = GetItemList(new InternalItemsQuery @@ -1690,51 +1746,6 @@ namespace MediaBrowser.Controller.Entities return !IsPlayed(user); } - [JsonIgnore] - public virtual bool SupportsUserDataFromChildren - { - get - { - // These are just far too slow. - if (this is ICollectionFolder) - { - return false; - } - - if (this is UserView) - { - return false; - } - - if (this is UserRootFolder) - { - return false; - } - - if (this is Channel) - { - return false; - } - - if (SourceType != SourceType.Library) - { - return false; - } - - var iItemByName = this as IItemByName; - if (iItemByName != null) - { - var hasDualAccess = this as IHasDualAccess; - if (hasDualAccess == null || hasDualAccess.IsAccessedByName) - { - return false; - } - } - - return true; - } - } - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) { if (!SupportsUserDataFromChildren) @@ -1764,20 +1775,15 @@ namespace MediaBrowser.Controller.Entities { EnableImages = false } - }); + }).TotalRecordCount; - double unplayedCount = unplayedQueryResult.TotalRecordCount; + dto.UnplayedItemCount = unplayedQueryResult; - dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; - - if (itemDto != null && itemDto.RecursiveItemCount.HasValue) + if (itemDto?.RecursiveItemCount > 0) { - if (itemDto.RecursiveItemCount.Value > 0) - { - var unplayedPercentage = (unplayedCount / itemDto.RecursiveItemCount.Value) * 100; - dto.PlayedPercentage = 100 - unplayedPercentage; - dto.Played = dto.PlayedPercentage.Value >= 100; - } + var unplayedPercentage = ((double)unplayedQueryResult / itemDto.RecursiveItemCount.Value) * 100; + dto.PlayedPercentage = 100 - unplayedPercentage; + dto.Played = dto.PlayedPercentage.Value >= 100; } else { |
