From 3f087eb4a54c7088e381d9e466a2978b6fb30e30 Mon Sep 17 00:00:00 2001 From: excelsior-dev <44299346+excelsior-dev@users.noreply.github.com> Date: Mon, 5 Oct 2026 19:18:49 -0400 Subject: Backport pull request #18223 from jellyfin/release-12.z Enhance internal search provider for multiple scripts Original-merge: 9ea203c47aa9f9723a22853151bf8291be3ed330 Merged-by: crobibero Backported-by: Cody Robibero --- .../Library/Search/SqlSearchProvider.cs | 31 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations/Library') diff --git a/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs b/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs index 2cbfb6a4fa..a5ea02df51 100644 --- a/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs +++ b/Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs @@ -10,6 +10,7 @@ using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; @@ -36,6 +37,7 @@ public class SqlSearchProvider : IInternalSearchProvider private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; private readonly IItemQueryHelpers _queryHelpers; + private readonly IServerConfigurationManager _configurationManager; /// /// Initializes a new instance of the class. @@ -45,18 +47,21 @@ public class SqlSearchProvider : IInternalSearchProvider /// The library manager. /// The user manager. /// The shared item query helpers. + /// The configuration manager. public SqlSearchProvider( IDbContextFactory dbProvider, IItemTypeLookup itemTypeLookup, ILibraryManager libraryManager, IUserManager userManager, - IItemQueryHelpers queryHelpers) + IItemQueryHelpers queryHelpers, + IServerConfigurationManager configurationManager) { _dbProvider = dbProvider; _itemTypeLookup = itemTypeLookup; _libraryManager = libraryManager; _userManager = userManager; _queryHelpers = queryHelpers; + _configurationManager = configurationManager; } /// @@ -98,6 +103,12 @@ public class SqlSearchProvider : IInternalSearchProvider // so match it via a case-insensitive LIKE rather than a per-row case conversion // that may not translate to SQL on every provider. var likeOriginal = $"%{rawSearchTerm}%"; + + // Great benefit for users with metadata in non-latin script + // since SortName is among other things stored transliterated. + var sortNameShape = BaseItem.GetSortName(rawSearchTerm, true, _configurationManager.Configuration); + var likeSortName = string.IsNullOrWhiteSpace(sortNameShape) ? null : $"%{sortNameShape}%"; + var limit = query.Limit ?? DefaultSearchLimit; var dbContext = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); @@ -107,9 +118,21 @@ public class SqlSearchProvider : IInternalSearchProvider var dbQuery = dbContext.BaseItems .AsNoTracking() .Where(e => e.Id != _placeholderId) - .Where(e => !e.IsVirtualItem) - .Where(e => e.CleanName!.Contains(cleanSearchTerm) - || (e.OriginalTitle != null && EF.Functions.Like(e.OriginalTitle, likeOriginal))); + .Where(e => !e.IsVirtualItem); + + if (likeSortName is null) + { + dbQuery = dbQuery + .Where(e => e.CleanName!.Contains(cleanSearchTerm) + || (e.OriginalTitle != null && EF.Functions.Like(e.OriginalTitle, likeOriginal))); + } + else + { + dbQuery = dbQuery + .Where(e => e.CleanName!.Contains(cleanSearchTerm) + || (e.OriginalTitle != null && EF.Functions.Like(e.OriginalTitle, likeOriginal)) + || (e.SortName != null && EF.Functions.Like(e.SortName, likeSortName))); + } dbQuery = ApplyTypeFilter(dbQuery, query.IncludeItemTypes, query.ExcludeItemTypes); dbQuery = ApplyMediaTypeFilter(dbQuery, query.MediaTypes); -- cgit v1.2.3