From 4147a83b9356a9b6d101dde8217aec21fefb51f4 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 24 Aug 2026 22:20:33 +0200 Subject: Handle generational suffixes --- .../Plugins/Omdb/OmdbProvider.cs | 32 +++++++++++++++++++++- .../Omdb/OmdbProviderTests.cs | 16 +++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 7a8e2b3ce7..7262cddd33 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -27,6 +27,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb /// Provider for OMDB service. public class OmdbProvider { + /// Generational suffixes that OMDb separates from the name with a comma. + private static readonly string[] NameSuffixes = ["Jr", "Jnr", "Sr", "Snr", "II", "III", "IV", "V"]; + private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClientFactory _httpClientFactory; @@ -425,6 +428,11 @@ namespace MediaBrowser.Providers.Plugins.Omdb AddPeople(itemResult, result.Actors, PersonKind.Actor); } + /// Adds the people from a comma separated OMDb credit list. + /// The item type. + /// The metadata result to add the people to. + /// The comma separated OMDb credit list. + /// The kind of person each credit describes. internal static void AddPeople(MetadataResult itemResult, string credits, PersonKind type) where T : BaseItem { @@ -433,6 +441,8 @@ namespace MediaBrowser.Providers.Plugins.Omdb return; } + var names = new List(); + foreach (var credit in credits.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) { // OMDb annotates the credited role in parentheses, e.g. "Mari Okada (screenplay)". The same @@ -444,11 +454,24 @@ namespace MediaBrowser.Providers.Plugins.Omdb name = name[..annotation].TrimEnd(); } - if (string.IsNullOrEmpty(name)) + if (name.Length == 0) { continue; } + // A generational suffix is separated from the name it belongs to by the same comma the list + // uses, e.g. "Jack Salvatore, Jr.", so it has to be joined back instead of becoming a credit. + if (names.Count > 0 && IsNameSuffix(name)) + { + names[^1] = names[^1] + ", " + name; + continue; + } + + names.Add(name); + } + + foreach (var name in names) + { itemResult.AddPerson(new PersonInfo { Name = name, @@ -457,6 +480,13 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } + private static bool IsNameSuffix(string value) + { + var suffix = value.EndsWith('.') ? value[..^1] : value; + + return NameSuffixes.Contains(suffix, StringComparer.OrdinalIgnoreCase); + } + private static bool IsConfiguredForEnglish(BaseItem item, string language) { if (string.IsNullOrEmpty(language)) diff --git a/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs index d18c8c21a2..5e053943af 100644 --- a/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs @@ -34,6 +34,22 @@ namespace Jellyfin.Providers.Tests.Omdb 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")] + [InlineData("Harold Ramis, Ken Griffey, III (voice)", "Harold Ramis|Ken Griffey, III")] + [InlineData("Robert Downey Jr., Gwyneth Paltrow", "Robert Downey Jr.|Gwyneth Paltrow")] + [InlineData("Jr., Tom Hanks", "Jr.|Tom Hanks")] + public void AddPeople_GenerationalSuffix_StaysWithItsName(string credits, string expected) + { + var result = new MetadataResult(); + + OmdbProvider.AddPeople(result, credits, PersonKind.Actor); + + Assert.Equal(expected.Split('|'), result.People!.Select(p => p.Name)); + } + [Theory] [InlineData(null)] [InlineData("")] -- cgit v1.2.3