diff options
3 files changed, 39 insertions, 24 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 0c7c411d0c..6a39b2177d 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -412,6 +412,13 @@ namespace Emby.Server.Implementations.Library } _persistenceService.DeleteItem([.. pathMaps.Select(f => f.Item.Id)]); + + // Evict the deleted items from the cache and announce each removal. + foreach (var (item, _, _) in pathMaps) + { + _cache.TryRemove(item.Id, out _); + ReportItemRemoved(item, item.GetOwner() ?? item.GetParent()); + } } public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem) @@ -611,6 +618,12 @@ namespace Emby.Server.Implementations.Library folder.UserData = null; } + // Announce the descendants before the item itself. + foreach (var child in children) + { + ReportItemRemoved(child, item); + } + ReportItemRemoved(item, parent); } diff --git a/Emby.Server.Implementations/Library/Search/SearchManager.cs b/Emby.Server.Implementations/Library/Search/SearchManager.cs index 01f9062734..0e180753a6 100644 --- a/Emby.Server.Implementations/Library/Search/SearchManager.cs +++ b/Emby.Server.Implementations/Library/Search/SearchManager.cs @@ -92,37 +92,33 @@ public class SearchManager : ISearchManager await Task.WhenAll(externalTask, internalTask).ConfigureAwait(false); var externalResults = await externalTask.ConfigureAwait(false); - var fromExternal = externalResults.Count > 0; - IReadOnlyList<SearchResult> results; - if (fromExternal) - { - results = externalResults; - } - else - { - results = await internalTask.ConfigureAwait(false); - if (_internalProviders.Length > 0) - { - _logger.LogDebug("No results from external providers, using internal provider results"); - } - } // Internal providers apply user-access filtering inline in their queries. External // providers don't know about user permissions, so they may return IDs from hidden - // libraries or items the user is otherwise blocked from. Run the post-filter only - // when results came from externals to close that gap. The Items controller's second - // roundtrip via folder.GetItems applies most of these again, but it does not restrict - // by TopParentIds when ItemIds is set. - if (fromExternal && results.Count > 0 && query.UserId.HasValue && !query.UserId.Value.IsEmpty()) + // libraries or items the user is otherwise blocked from. Filter them here to close + // that gap. The Items controller's second roundtrip via folder.GetItems applies most + // of these again, but it does not restrict by TopParentIds when ItemIds is set. + if (externalResults.Count > 0 && query.UserId.HasValue && !query.UserId.Value.IsEmpty()) { var user = _userManager.GetUserById(query.UserId.Value); if (user is not null) { - results = await FilterByUserAccessAsync(results, user, query, cancellationToken).ConfigureAwait(false); + externalResults = await FilterByUserAccessAsync(externalResults, user, query, cancellationToken).ConfigureAwait(false); } } - return results; + if (externalResults.Count > 0) + { + return externalResults; + } + + var internalResults = await internalTask.ConfigureAwait(false); + if (_internalProviders.Length > 0) + { + _logger.LogDebug("No results from external providers, using internal provider results"); + } + + return internalResults; } private async Task<IReadOnlyList<SearchResult>> FilterByUserAccessAsync( diff --git a/MediaBrowser.Controller/Library/SearchProviderQuery.cs b/MediaBrowser.Controller/Library/SearchProviderQuery.cs index 845588c872..b1ff800fa0 100644 --- a/MediaBrowser.Controller/Library/SearchProviderQuery.cs +++ b/MediaBrowser.Controller/Library/SearchProviderQuery.cs @@ -19,7 +19,9 @@ public class SearchProviderQuery public Guid? UserId { get; init; } /// <summary> - /// Gets the item types to include in the search. + /// Gets the item types to include in the search. An empty array means every type is eligible. + /// When this is non-empty it is the authoritative type filter and <see cref="ExcludeItemTypes"/> + /// does not apply; excludes only take effect when no include types were requested. /// </summary> public BaseItemKind[] IncludeItemTypes { get; init; } = []; @@ -29,7 +31,9 @@ public class SearchProviderQuery public BaseItemKind[] ExcludeItemTypes { get; init; } = []; /// <summary> - /// Gets the media types to include in the search. + /// Gets the media types to include in the search. This is an additional constraint rather than + /// an alternative one: a provider must return only items that match both the requested media + /// types and the requested item types, not the union of the two. /// </summary> public MediaType[] MediaTypes { get; init; } = []; @@ -39,7 +43,9 @@ public class SearchProviderQuery public int? Limit { get; init; } /// <summary> - /// Gets the parent ID to scope the search. + /// Gets the parent ID to scope the search. This scopes to the whole subtree, not just direct + /// children - callers routinely pass a library folder id and expect items nested arbitrarily + /// deep beneath it (an episode under a season under a series) to match. /// </summary> public Guid? ParentId { get; init; } } |
