From c584d36fd4a643cfd252eddabbda8a91c2d8e0da Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Wed, 12 May 2021 14:48:45 +0200 Subject: [PATCH 1/4] Fix Tmdb person language --- .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 5 ++--- .../Plugins/Tmdb/People/TmdbPersonProvider.cs | 5 ++--- MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs | 4 +++- MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs | 6 ++++++ 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index bf42ceadef..d523d0315d 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -1,6 +1,5 @@ #pragma warning disable CS1591 -using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -48,6 +47,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { + var language = item.GetPreferredMetadataLanguage(); var person = (Person)item; if (!person.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) @@ -55,14 +55,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People return Enumerable.Empty(); } - var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); + var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), language, cancellationToken).ConfigureAwait(false); if (personResult?.Images?.Profiles == null) { return Enumerable.Empty(); } var remoteImages = new RemoteImageInfo[personResult.Images.Profiles.Count]; - var language = item.GetPreferredMetadataLanguage(); for (var i = 0; i < personResult.Images.Profiles.Count; i++) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs index 1757c82678..6db550b1d0 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -32,7 +31,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People { if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) { - var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); + var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false); if (personResult != null) { @@ -96,7 +95,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People if (personTmdbId > 0) { - var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false); + var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, id.MetadataLanguage, cancellationToken).ConfigureAwait(false); result.HasMetadata = true; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs index 05e5d3ced7..125b1b604a 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs @@ -276,9 +276,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb /// Gets a person eg. cast or crew member from the TMDb API based on its TMDb id. /// /// The person's TMDb id. + /// The episode's language. /// The cancellation token. /// The TMDb person information or null if not found. - public async Task GetPersonAsync(int personTmdbId, CancellationToken cancellationToken) + public async Task GetPersonAsync(int personTmdbId, string language, CancellationToken cancellationToken) { var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}"; if (_memoryCache.TryGetValue(key, out Person person)) @@ -290,6 +291,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb person = await _tmDbClient.GetPersonAsync( personTmdbId, + TmdbUtils.NormalizeLanguage(language), PersonMethods.TvCredits | PersonMethods.MovieCredits | PersonMethods.Images | PersonMethods.ExternalIds, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs index b4e165f82b..7c64035fe4 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs @@ -148,6 +148,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb if (parts.Length == 2) { + // TMDB doesn't support Switzerland (de-CH, it-CH or fr-CH) so use the language (de, it or fr) without country code + if (string.Equals(parts[1], "ch", StringComparison.Ordinal)) + { + return parts[0]; + } + language = parts[0] + "-" + parts[1].ToUpperInvariant(); } From 96e05e5b669e0d275b98bebfd9dd422dcc8f7103 Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Mon, 17 May 2021 12:55:27 +0200 Subject: [PATCH 2/4] Add tests for NoralizeLanguage --- Jellyfin.sln | 7 +++++ .../Tmdb/People/TmdbPersonImageProvider.cs | 2 +- .../Plugins/Tmdb/TmdbUtils.cs | 2 +- .../Jellyfin.Providers.Tests.csproj | 30 +++++++++++++++++++ .../Tmdb/TmdbUtilsTests.cs | 27 +++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj create mode 100644 tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs diff --git a/Jellyfin.sln b/Jellyfin.sln index 8626a4b1ba..bfb43a23d0 100644 --- a/Jellyfin.sln +++ b/Jellyfin.sln @@ -81,6 +81,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Tests", "te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Integration.Tests", "tests\Jellyfin.Server.Integration.Tests\Jellyfin.Server.Integration.Tests.csproj", "{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Providers.Tests", "tests\Jellyfin.Providers.Tests\Jellyfin.Providers.Tests.csproj", "{CE21845F-74AD-42F6-B7BA-90506E6CD09E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -223,6 +225,10 @@ Global {68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Debug|Any CPU.Build.0 = Debug|Any CPU {68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Release|Any CPU.ActiveCfg = Release|Any CPU {68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Release|Any CPU.Build.0 = Release|Any CPU + {CE21845F-74AD-42F6-B7BA-90506E6CD09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE21845F-74AD-42F6-B7BA-90506E6CD09E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE21845F-74AD-42F6-B7BA-90506E6CD09E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE21845F-74AD-42F6-B7BA-90506E6CD09E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -240,6 +246,7 @@ Global {42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {3ADBCD8C-C0F2-4956-8FDC-35D686B74CF9} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} {68B0B823-A5AC-4E8B-82EA-965AAC7BF76E} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} + {CE21845F-74AD-42F6-B7BA-90506E6CD09E} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE} diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index d523d0315d..99a43966f3 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -47,8 +47,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - var language = item.GetPreferredMetadataLanguage(); var person = (Person)item; + var language = item.GetPreferredMetadataLanguage(); if (!person.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs index 7c64035fe4..b713736a0f 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb if (parts.Length == 2) { // TMDB doesn't support Switzerland (de-CH, it-CH or fr-CH) so use the language (de, it or fr) without country code - if (string.Equals(parts[1], "ch", StringComparison.Ordinal)) + if (string.Equals(parts[1], "CH", StringComparison.OrdinalIgnoreCase)) { return parts[0]; } diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj new file mode 100644 index 0000000000..2d8174b880 --- /dev/null +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -0,0 +1,30 @@ + + + + net5.0 + false + true + enable + AllEnabledByDefault + ../jellyfin-tests.ruleset + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs new file mode 100644 index 0000000000..f6a7c676f4 --- /dev/null +++ b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Providers.Plugins.Tmdb; +using Xunit; + +namespace Jellyfin.Providers.Tests.Tmdb +{ + public static class TmdbUtilsTests + { + [Theory] + [InlineData("de", "de")] + [InlineData("En", "En")] + [InlineData("de-de", "de-DE")] + [InlineData("en-US", "en-US")] + [InlineData("de-CH", "de")] + public static void NormalizeLanguage_Valid_Success(string input, string expected) + { + Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input)); + } + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + public static void NormalizeLanguage_Invalid_Equal(string? input, string? expected) + { + Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input!)); + } + } +} From 6353966abdc31a7806c6d4d62154cf3da7c86adf Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Tue, 18 May 2021 13:17:34 +0200 Subject: [PATCH 3/4] Fix cache key --- MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs index 125b1b604a..79ec6139d1 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs @@ -281,7 +281,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb /// The TMDb person information or null if not found. public async Task GetPersonAsync(int personTmdbId, string language, CancellationToken cancellationToken) { - var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}"; + var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}-{language}"; if (_memoryCache.TryGetValue(key, out Person person)) { return person; From ee7a95e088520f835a4d179c7c5faec5eaa8f9ff Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Tue, 18 May 2021 13:44:38 +0200 Subject: [PATCH 4/4] Move GetMetadataLanguage --- .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index 99a43966f3..e4c908a62c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -48,13 +48,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { var person = (Person)item; - var language = item.GetPreferredMetadataLanguage(); if (!person.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId)) { return Enumerable.Empty(); } + var language = item.GetPreferredMetadataLanguage(); var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), language, cancellationToken).ConfigureAwait(false); if (personResult?.Images?.Profiles == null) {