aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library/Search
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Library/Search')
-rw-r--r--Emby.Server.Implementations/Library/Search/SearchManager.cs24
-rw-r--r--Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs7
2 files changed, 22 insertions, 9 deletions
diff --git a/Emby.Server.Implementations/Library/Search/SearchManager.cs b/Emby.Server.Implementations/Library/Search/SearchManager.cs
index 0e180753a6..a8ee416b31 100644
--- a/Emby.Server.Implementations/Library/Search/SearchManager.cs
+++ b/Emby.Server.Implementations/Library/Search/SearchManager.cs
@@ -112,13 +112,12 @@ public class SearchManager : ISearchManager
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;
+ return await internalTask.ConfigureAwait(false);
}
private async Task<IReadOnlyList<SearchResult>> FilterByUserAccessAsync(
@@ -144,17 +143,24 @@ public class SearchManager : ISearchManager
baseQuery = _queryHelpers.ApplyAccessFiltering(dbContext, baseQuery, accessFilter);
- var allowedCount = await baseQuery.CountAsync(cancellationToken).ConfigureAwait(false);
- if (allowedCount == candidates.Count)
+ var allowed = await baseQuery
+ .Select(e => new { e.Id, e.PrimaryVersionId })
+ .ToListAsync(cancellationToken)
+ .ConfigureAwait(false);
+
+ var allowedIds = allowed.Select(e => e.Id).ToHashSet();
+
+ // A provider can return both an alternate version and the primary it belongs to, and the
+ // two are one item to the user.
+ allowedIds.ExceptWith(allowed
+ .Where(e => e.PrimaryVersionId.HasValue && allowedIds.Contains(e.PrimaryVersionId.Value))
+ .Select(e => e.Id));
+
+ if (allowedIds.Count == candidates.Count)
{
return candidates;
}
- var allowedIds = await baseQuery
- .Select(e => e.Id)
- .ToHashSetAsync(cancellationToken)
- .ConfigureAwait(false);
-
var filtered = candidates.Where(c => allowedIds.Contains(c.ItemId)).ToList();
if (filtered.Count < candidates.Count)
{
diff --git a/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs b/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs
index c4d3b249d5..2cbfb6a4fa 100644
--- a/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs
+++ b/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs
@@ -115,6 +115,7 @@ public class SqlSearchProvider : IInternalSearchProvider
dbQuery = ApplyMediaTypeFilter(dbQuery, query.MediaTypes);
dbQuery = ApplyParentFilter(dbQuery, query.ParentId);
dbQuery = ApplyUserAccessFilter(dbContext, dbQuery, query);
+ dbQuery = ExcludeVersionsOfMatchedPrimaries(dbQuery);
// Compute the score in SQL: the ternary translates to a CASE WHEN. CleanName is
// the pre-normalized (lowercase, diacritic-stripped) form, so we score against it
@@ -193,6 +194,12 @@ public class SqlSearchProvider : IInternalSearchProvider
return query.Where(e => e.ParentId == pid || e.Parents!.Any(p => p.ParentItemId == pid));
}
+ private static IQueryable<BaseItemEntity> ExcludeVersionsOfMatchedPrimaries(IQueryable<BaseItemEntity> query)
+ {
+ var matched = query;
+ return query.Where(e => e.PrimaryVersionId == null || !matched.Any(p => p.Id == e.PrimaryVersionId));
+ }
+
private IQueryable<BaseItemEntity> ApplyUserAccessFilter(
JellyfinDbContext dbContext,
IQueryable<BaseItemEntity> query,