diff options
| author | excelsior-dev <44299346+excelsior-dev@users.noreply.github.com> | 2026-10-05 19:18:49 -0400 |
|---|---|---|
| committer | Cody Robibero <cody@robibe.ro> | 2026-10-05 19:18:49 -0400 |
| commit | 3f087eb4a54c7088e381d9e466a2978b6fb30e30 (patch) | |
| tree | 0f7620921df26119f428e81449655102d7642da5 | |
| parent | 6983363761b34d7efaef8d9074e874cae481cb1e (diff) | |
Backport pull request #18223 from jellyfin/release-12.z
Enhance internal search provider for multiple scripts
Original-merge: 9ea203c47aa9f9723a22853151bf8291be3ed330
Merged-by: crobibero <cody@robibe.ro>
Backported-by: Cody Robibero <cody@robibe.ro>
| -rw-r--r-- | CONTRIBUTORS.md | 1 | ||||
| -rw-r--r-- | Emby.Server.Implementations/Library/Search/SqlSearchProvider.cs | 31 | ||||
| -rw-r--r-- | tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs | 10 |
3 files changed, 37 insertions, 5 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index aca9d6b790..8240b458e6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -244,6 +244,7 @@ - [Oggeb1](https://github.com/Oggeb1) - [scr4bble](https://github.com/scr4bble) - [Mateus Bandeira](https://github.com/mateusbandeiraa) + - [excelsior](https://github.com/excelsior-dev) - [TheDreadPirate](https://github.com/thedreaddpirate) - [klizas](https://github.com/klizas) 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; /// <summary> /// Initializes a new instance of the <see cref="SqlSearchProvider"/> class. @@ -45,18 +47,21 @@ public class SqlSearchProvider : IInternalSearchProvider /// <param name="libraryManager">The library manager.</param> /// <param name="userManager">The user manager.</param> /// <param name="queryHelpers">The shared item query helpers.</param> + /// <param name="configurationManager">The configuration manager.</param> public SqlSearchProvider( IDbContextFactory<JellyfinDbContext> 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; } /// <inheritdoc/> @@ -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); diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs index 5aa770b9b3..89ca037256 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs @@ -9,8 +9,11 @@ using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; using Jellyfin.Server.Implementations.Item; using Jellyfin.Server.Implementations.Tests.Item; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Configuration; +using Microsoft.Extensions.Configuration; using Moq; using Xunit; using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind; @@ -52,12 +55,17 @@ public sealed class SqlSearchProviderTests : SqliteDbTestFixture var userManager = new Mock<IUserManager>(); userManager.Setup(u => u.GetUserById(_user.Id)).Returns(_user); + var serverConfigurationManager = new Mock<IServerConfigurationManager>(); + serverConfigurationManager.Setup(scm => scm.Configuration) + .Returns(new ServerConfiguration()); + _provider = new SqlSearchProvider( CreateDbContextFactory(), itemTypeLookup, _libraryManager.Object, userManager.Object, - CreateBaseItemRepository(itemTypeLookup)); + CreateBaseItemRepository(itemTypeLookup), + serverConfigurationManager.Object); } [Fact] |
