diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-02-21 22:38:07 +0100 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-02-21 22:38:07 +0100 |
| commit | ae5420d4ae09dec7d62d1d0861dfc823a180d93b (patch) | |
| tree | cff54cca2310defe253700b14f83488a1061617c /MediaBrowser.Controller | |
| parent | 0f1a6fe4c27fa4c91b7e8dcd577960c568fa3c03 (diff) | |
Handle linkedChildren in GetPlayedAndTotalCountBatch and optimize filter
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 19 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TV/Season.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserViewBuilder.cs | 61 |
3 files changed, 64 insertions, 20 deletions
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 525a4bc334..7c66dc6e36 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -880,14 +880,12 @@ namespace MediaBrowser.Controller.Entities var user = query.User; - Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - IEnumerable<BaseItem> items; int totalItemCount = 0; if (query.User is null) { - items = Children.Where(filter); + items = UserViewBuilder.Filter(Children, user, query, UserDataManager, LibraryManager); totalItemCount = items.Count(); } else @@ -902,7 +900,12 @@ namespace MediaBrowser.Controller.Entities NameLessThan = query.NameLessThan }; - items = GetChildren(user, true, out totalItemCount, childQuery).Where(filter); + items = UserViewBuilder.Filter( + GetChildren(user, true, out totalItemCount, childQuery), + user, + query, + UserDataManager, + LibraryManager); } return PostFilterAndSort(items, query); @@ -1337,8 +1340,7 @@ namespace MediaBrowser.Controller.Entities .Where(e => e.IsVisible(user)) .ToArray(); - var realChildren = visibleChildren - .Where(e => query is null || UserViewBuilder.FilterItem(e, query)) + var realChildren = UserViewBuilder.Filter(visibleChildren, query.User, query, UserDataManager, LibraryManager) .ToArray(); var childCount = realChildren.Length; @@ -1722,15 +1724,14 @@ namespace MediaBrowser.Controller.Entities int playedCount; int totalCount; - if (precomputedCounts.HasValue && LinkedChildren.Length == 0) + if (precomputedCounts.HasValue) { // Use batch-fetched counts (avoids N+1 queries) (playedCount, totalCount) = precomputedCounts.Value; } else { - // Fall back to per-item query for LinkedChildren items (BoxSets, Playlists) - // or when no batch data is available + // Fall back to per-item query when no batch data is available var query = new InternalItemsQuery(user); if (LinkedChildren.Length > 0) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index b972ebaa6b..e1927a5077 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -175,9 +175,7 @@ namespace MediaBrowser.Controller.Entities.TV var user = query.User; - Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - - var items = GetEpisodes(user, query.DtoOptions, true).Where(filter); + var items = UserViewBuilder.Filter(GetEpisodes(user, query.DtoOptions, true), user, query, UserDataManager, LibraryManager); return PostFilterAndSort(items, query); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 81b0fe1c8c..77bdf402e4 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -414,14 +414,54 @@ namespace MediaBrowser.Controller.Entities InternalItemsQuery query) where T : BaseItem { - items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); + var filtered = Filter(items, query.User, query, _userDataManager, _libraryManager); - return SortAndPage(items, null, query, _libraryManager); + return SortAndPage(filtered, null, query, _libraryManager); } - public static bool FilterItem(BaseItem item, InternalItemsQuery query) + /// <summary> + /// Batch-aware filter that applies per-item checks. + /// </summary> + /// <param name="items">The items to filter.</param> + /// <param name="user">The user for filtering context.</param> + /// <param name="query">The query parameters.</param> + /// <param name="userDataManager">The user data manager.</param> + /// <param name="libraryManager">The library manager.</param> + /// <returns>The filtered items.</returns> + public static IEnumerable<BaseItem> Filter( + IEnumerable<BaseItem> items, + User user, + InternalItemsQuery query, + IUserDataManager userDataManager, + ILibraryManager libraryManager) { - return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager); + var filtered = items.Where(i => Filter(i, user, query, userDataManager, libraryManager)); + + if (query.IsPlayed.HasValue && user is not null) + { + var itemList = filtered.ToList(); + var folderIds = itemList.OfType<Folder>().Select(f => f.Id).ToList(); + + if (folderIds.Count > 0) + { + var counts = libraryManager.GetPlayedAndTotalCountBatch(folderIds, user); + var isPlayedValue = query.IsPlayed.Value; + + return itemList.Where(i => + { + if (i.IsFolder && counts.TryGetValue(i.Id, out var c)) + { + return (c.Total > 0 && c.Played == c.Total) == isPlayedValue; + } + + return true; + }); + } + + return itemList; + } + + return filtered; } public static QueryResult<BaseItem> SortAndPage( @@ -453,7 +493,7 @@ namespace MediaBrowser.Controller.Entities itemsArray); } - public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) + private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (!string.IsNullOrEmpty(query.NameStartsWith) && !item.SortName.StartsWith(query.NameStartsWith, StringComparison.InvariantCultureIgnoreCase)) { @@ -541,10 +581,15 @@ namespace MediaBrowser.Controller.Entities if (query.IsPlayed.HasValue) { - userData ??= userDataManager.GetUserData(user, item); - if (item.IsPlayed(user, userData) != query.IsPlayed.Value) + // Folder.IsPlayed() hits the DB per-item (N+1 queries). + // Folders are batch-filtered by the collection Filter() overload. + if (!item.IsFolder) { - return false; + userData ??= userDataManager.GetUserData(user, item); + if (item.IsPlayed(user, userData) != query.IsPlayed.Value) + { + return false; + } } } |
