diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-08-25 20:12:52 +0200 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-08-25 20:43:44 +0200 |
| commit | 1d24c1df170d743d5b0d2c1c8c503e44486c6875 (patch) | |
| tree | 9acea13fd86a4885164c255b3b4b05b4411b632c | |
| parent | 4147a83b9356a9b6d101dde8217aec21fefb51f4 (diff) | |
Keep an OMDb credit whole when its annotation holds a comma
| -rw-r--r-- | MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 32 | ||||
| -rw-r--r-- | tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs | 14 |
2 files changed, 44 insertions, 2 deletions
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 7262cddd33..d51d913caa 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -443,7 +443,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var names = new List<string>(); - foreach (var credit in credits.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) + foreach (var credit in SplitCredits(credits)) { // OMDb annotates the credited role in parentheses, e.g. "Mari Okada (screenplay)". The same // person can be credited more than once this way, so strip it and let AddPerson deduplicate. @@ -451,9 +451,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb var annotation = name.IndexOf('(', StringComparison.Ordinal); if (annotation >= 0) { - name = name[..annotation].TrimEnd(); + name = name[..annotation]; } + name = name.Trim(); if (name.Length == 0) { continue; @@ -480,6 +481,33 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } + // Only the commas between credits, never one inside an annotation: "Jerry Siegel (created by: + // Superman, Superboy)" is one credit, and splitting it blindly invents a person called "Superboy)". + private static IEnumerable<string> SplitCredits(string credits) + { + var depth = 0; + var start = 0; + + for (var i = 0; i < credits.Length; i++) + { + switch (credits[i]) + { + case '(': + depth++; + break; + case ')': + depth = Math.Max(0, depth - 1); + break; + case ',' when depth == 0: + yield return credits[start..i]; + start = i + 1; + break; + } + } + + yield return credits[start..]; + } + private static bool IsNameSuffix(string value) { var suffix = value.EndsWith('.') ? value[..^1] : value; diff --git a/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs index 5e053943af..bd50a903f1 100644 --- a/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs @@ -35,6 +35,20 @@ namespace Jellyfin.Providers.Tests.Omdb } [Theory] + [InlineData( + "Jerry Siegel (created by: Superman, Superboy), Bob Kane (created by: Batman)", + "Jerry Siegel|Bob Kane")] + [InlineData("Alan Moore (created by: John Constantine)", "Alan Moore")] + public void AddPeople_CommaInsideAnAnnotation_StaysOneCredit(string credits, string expected) + { + var result = new MetadataResult<Movie>(); + + OmdbProvider.AddPeople(result, credits, PersonKind.Writer); + + Assert.Equal(expected.Split('|'), result.People!.Select(p => p.Name)); + } + + [Theory] [InlineData("Jack Salvatore, Jr.", "Jack Salvatore, Jr.")] [InlineData("Efrem Zimbalist, Jr., Tom Hanks", "Efrem Zimbalist, Jr.|Tom Hanks")] [InlineData("Tom Hanks, Sammy Davis, Jr", "Tom Hanks|Sammy Davis, Jr")] |
