From 2eef0f11cd9887d890a82745881397e8a641c0c4 Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 17 Jul 2026 09:52:59 -0600 Subject: [PATCH] Preserve search filter case mode on reload --- docs/CHANGELOG.md | 2 + src/slskd/Application.cs | 38 +++++++++++-------- .../Core/ApplicationLifecycleTests.cs | 12 ++++++ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8860e73d9..11f53510c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -22,6 +22,8 @@ For dev or build tags, use the same logical version string embedded in the tag. ## [Unreleased] +- Reloaded search-request filters now preserve the configured regex case mode + instead of always becoming case-sensitive after an options change. - The web footer and README now offer direct PayPal and Ko-fi links for supporting slskdN development. - GitLab CI configuration now keeps the Arch package-smoke sudoers command as diff --git a/src/slskd/Application.cs b/src/slskd/Application.cs index ac0e94f1b..c68ca2893 100644 --- a/src/slskd/Application.cs +++ b/src/slskd/Application.cs @@ -186,17 +186,9 @@ public Application( Flags = Program.Flags; - var regexOptions = RegexOptions.Compiled; - - if (!Flags.CaseSensitiveRegEx) - { - regexOptions |= RegexOptions.IgnoreCase; - } - - CompiledSearchRequestFilters = OptionsAtStartup.Filters.Search.Request - .Select(f => new Regex(f, regexOptions, SearchRequestFilterMatchTimeout)) - .ToList() - .AsReadOnly(); + CompiledSearchRequestFilters = CompileSearchRequestFilters( + OptionsAtStartup.Filters.Search.Request, + Flags.CaseSensitiveRegEx); State = state; RegisterChange(State.OnChange(state => State_OnChange(state))); @@ -782,6 +774,23 @@ internal static SoulseekClientOptionsPatch CreateStartupSoulseekClientOptionsPat placeInQueueResolver: placeInQueueResolver); } + internal static IReadOnlyList CompileSearchRequestFilters( + IEnumerable filters, + bool caseSensitive) + { + var regexOptions = RegexOptions.Compiled; + + if (!caseSensitive) + { + regexOptions |= RegexOptions.IgnoreCase; + } + + return filters + .Select(f => new Regex(f, regexOptions, SearchRequestFilterMatchTimeout)) + .ToList() + .AsReadOnly(); + } + private static UserEndPointCache CreateUserEndPointCache() { var cache = new UserEndPointCache(); @@ -2242,10 +2251,9 @@ static string FormatOptionLogValue(PropertyInfo? property, object? value) if (PreviousOptions.Filters.Search.Request.Except(newOptions.Filters.Search.Request).Any() || newOptions.Filters.Search.Request.Except(PreviousOptions.Filters.Search.Request).Any()) { - CompiledSearchRequestFilters = newOptions.Filters.Search.Request - .Select(f => new Regex(f, RegexOptions.Compiled, SearchRequestFilterMatchTimeout)) - .ToList() - .AsReadOnly(); + CompiledSearchRequestFilters = CompileSearchRequestFilters( + newOptions.Filters.Search.Request, + Flags.CaseSensitiveRegEx); Log.Information("Updated and re-compiled search response filters"); } diff --git a/tests/slskd.Tests.Unit/Core/ApplicationLifecycleTests.cs b/tests/slskd.Tests.Unit/Core/ApplicationLifecycleTests.cs index 8d3804085..9d25c98c0 100644 --- a/tests/slskd.Tests.Unit/Core/ApplicationLifecycleTests.cs +++ b/tests/slskd.Tests.Unit/Core/ApplicationLifecycleTests.cs @@ -73,6 +73,18 @@ public void CreateStartupSoulseekClientOptionsPatch_DoesNotReapplyListenerSettin Assert.Null(patch.ListenPort); } + [Theory] + [InlineData(false, true)] + [InlineData(true, false)] + public void CompileSearchRequestFilters_PreservesConfiguredCaseMode( + bool caseSensitive, + bool expectedMatch) + { + var filters = Application.CompileSearchRequestFilters(["^secret$"], caseSensitive); + + Assert.Equal(expectedMatch, filters[0].IsMatch("SECRET")); + } + [Fact] public void FormatCompletedTransferProgress_ClampsNegativeAverageSpeed() {