From 9b5c98795e6d0195e1c004e6fe9e46757304cbfc Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Wed, 15 Jul 2026 22:17:20 +0000 Subject: [PATCH] Move ItemsProxy sort helpers --- .../Api/MultilangController.cs | 81 ++----------------- .../Services/ItemsProxySorting.cs | 52 ++++++++++++ 2 files changed, 57 insertions(+), 76 deletions(-) diff --git a/src/Jellyfin.Plugin.Multilang/Api/MultilangController.cs b/src/Jellyfin.Plugin.Multilang/Api/MultilangController.cs index 5e6cfdc..e549b92 100644 --- a/src/Jellyfin.Plugin.Multilang/Api/MultilangController.cs +++ b/src/Jellyfin.Plugin.Multilang/Api/MultilangController.cs @@ -408,9 +408,9 @@ public sealed class MultilangController : ControllerBase if (ids.Length == 0) return body; - var sortLocale = ResolveSortLocale(rules.SortLocale, controls.ClientLocale); - var sortCulture = GetSortCulture(sortLocale); - var sortArticles = GetSortArticles(sortLocale); + var sortLocale = ItemsProxySorting.ResolveSortLocale(rules.SortLocale, controls.ClientLocale); + var sortCulture = ItemsProxySorting.GetSortCulture(sortLocale); + var sortArticles = ItemsProxySorting.GetSortArticles(_articleCatalog, Plugin.Instance?.Configuration?.ArticleEntries ?? [], sortLocale); var localGenreIds = rules.Enabled ? ItemsProxyRequestBuilder.ParseLocalGenreIds(controls.GenreIds) : []; if (rules.Enabled || localGenreIds.Length > 0) @@ -753,7 +753,7 @@ public sealed class MultilangController : ControllerBase return false; } - var culture = GetSortCulture(ResolveSortLocale(locale, locale)); + var culture = ItemsProxySorting.GetSortCulture(ItemsProxySorting.ResolveSortLocale(locale, locale)); var comparer = StringComparer.Create(culture, true); var items = names .Where(kv => !string.IsNullOrWhiteSpace(kv.Value)) @@ -1182,7 +1182,7 @@ public sealed class MultilangController : ControllerBase var categoryMatch = PickCategoryMatch(rules, classificationFacts); var category = categoryMatch.Effective; var clientLocale = Request.Query.TryGetValue("mlLocale", out var mlLocale) ? mlLocale.ToString() : string.Empty; - var effectiveSortLocale = ResolveSortLocale(rules.SortLocale, clientLocale); + var effectiveSortLocale = ItemsProxySorting.ResolveSortLocale(rules.SortLocale, clientLocale); var genreLocale = string.IsNullOrWhiteSpace(clientLocale) ? effectiveSortLocale : clientLocale; var actionLists = ActionFields.ToDictionary( @@ -1751,77 +1751,6 @@ public sealed class MultilangController : ControllerBase return [JellyfinAction]; } - private static string ResolveSortLocale(string? configuredLocale, string? clientLocale) - { - var configured = (configuredLocale ?? string.Empty).Trim(); - if (configured.Length > 0 && !configured.Equals("Auto", StringComparison.OrdinalIgnoreCase)) - return configured; - - return (clientLocale ?? string.Empty).Trim(); - } - - private CultureInfo GetSortCulture(string? sortLocale) - { - var locale = (sortLocale ?? string.Empty).Trim(); - if (locale.Length == 0) - return CultureInfo.InvariantCulture; - - try - { - return CultureInfo.GetCultureInfo(locale); - } - catch (CultureNotFoundException) - { - return CultureInfo.InvariantCulture; - } - } - - private string[] GetSortArticles(string? sortLocale) - { - var locale = (sortLocale ?? string.Empty).Trim(); - if (locale.Length == 0) - locale = "en"; - - var configured = Plugin.Instance?.Configuration?.ArticleEntries ?? []; - var custom = configured.FirstOrDefault(e => e.Language.Equals(locale, StringComparison.OrdinalIgnoreCase)) - ?? configured.FirstOrDefault(e => locale.StartsWith(e.Language + "-", StringComparison.OrdinalIgnoreCase)); - if (custom is not null) - return SplitArticles(custom.Articles); - - var builtIns = _articleCatalog.GetBuiltIns(); - if (builtIns.TryGetValue(locale, out var exact)) - return exact; - - var dash = locale.IndexOf('-', StringComparison.Ordinal); - if (dash > 0 && builtIns.TryGetValue(locale[..dash], out var languageOnly)) - return languageOnly; - - return []; - } - - private static string[] SplitArticles(string articles) - => articles.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); - - private static bool TryGetItemsArray(JsonNode root, out JsonArray items) - { - if (root is JsonObject obj && obj["Items"] is JsonArray array) - { - items = array; - return true; - } - - if (root is JsonArray direct) - { - items = direct; - return true; - } - - items = []; - return false; - } - private IActionResult ServeEmbedded(string resource, string contentType) { var content = ReadEmbedded(resource); diff --git a/src/Jellyfin.Plugin.Multilang/Services/ItemsProxySorting.cs b/src/Jellyfin.Plugin.Multilang/Services/ItemsProxySorting.cs index fb3ef8c..350903e 100644 --- a/src/Jellyfin.Plugin.Multilang/Services/ItemsProxySorting.cs +++ b/src/Jellyfin.Plugin.Multilang/Services/ItemsProxySorting.cs @@ -1,6 +1,7 @@ using System.Globalization; using System.Text; using System.Text.Json.Nodes; +using Jellyfin.Plugin.Multilang.Configuration; namespace Jellyfin.Plugin.Multilang.Services; @@ -52,6 +53,57 @@ public static class ItemsProxySorting } } + public static string ResolveSortLocale(string? configuredLocale, string? clientLocale) + { + var configured = (configuredLocale ?? string.Empty).Trim(); + return configured.Length > 0 && !configured.Equals("Auto", StringComparison.OrdinalIgnoreCase) + ? configured + : (clientLocale ?? string.Empty).Trim(); + } + + public static CultureInfo GetSortCulture(string? sortLocale) + { + var locale = (sortLocale ?? string.Empty).Trim(); + if (locale.Length == 0) + return CultureInfo.InvariantCulture; + + try + { + return CultureInfo.GetCultureInfo(locale); + } + catch (CultureNotFoundException) + { + return CultureInfo.InvariantCulture; + } + } + + public static string[] GetSortArticles(SortArticleCatalog articleCatalog, IEnumerable configuredArticles, string? sortLocale) + { + var locale = (sortLocale ?? string.Empty).Trim(); + if (locale.Length == 0) + locale = "en"; + + var configured = configuredArticles.ToArray(); + var custom = configured.FirstOrDefault(e => e.Language.Equals(locale, StringComparison.OrdinalIgnoreCase)) + ?? configured.FirstOrDefault(e => locale.StartsWith(e.Language + "-", StringComparison.OrdinalIgnoreCase)); + if (custom is not null) + return SplitArticles(custom.Articles); + + var builtIns = articleCatalog.GetBuiltIns(); + if (builtIns.TryGetValue(locale, out var exact)) + return exact; + + var dash = locale.IndexOf('-', StringComparison.Ordinal); + return dash > 0 && builtIns.TryGetValue(locale[..dash], out var languageOnly) + ? languageOnly + : []; + } + + private static string[] SplitArticles(string articles) + => articles.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray(); + private static bool TryGetItemsArray(JsonNode root, out JsonArray items) { if (root is JsonObject obj && obj["Items"] is JsonArray array)