Browse Source

Handle es-419 in TMDb (#14946)

Erik W 6 days ago
parent
commit
2c7d2d4719

+ 1 - 1
MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs

@@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
             var language = item.GetPreferredMetadataLanguage();
 
             // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
-            var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, null, null, cancellationToken).ConfigureAwait(false);
+            var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, null, null, null, cancellationToken).ConfigureAwait(false);
 
             if (collection?.Images is null)
             {

+ 5 - 4
MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs

@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
 
             if (tmdbId > 0)
             {
-                var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken).ConfigureAwait(false);
+                var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, language, TmdbUtils.GetImageLanguagesParam(language, searchInfo.MetadataCountryCode), searchInfo.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
                 if (collection is null)
                 {
@@ -70,7 +70,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
                 return new[] { result };
             }
 
-            var collectionSearchResults = await _tmdbClientManager.SearchCollectionAsync(searchInfo.Name, language, cancellationToken).ConfigureAwait(false);
+            var collectionSearchResults = await _tmdbClientManager.SearchCollectionAsync(searchInfo.Name, language, searchInfo.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
             var collections = new RemoteSearchResult[collectionSearchResults.Count];
             for (var i = 0; i < collectionSearchResults.Count; i++)
@@ -95,6 +95,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
         {
             var tmdbId = Convert.ToInt32(info.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture);
             var language = info.MetadataLanguage;
+
             // We don't already have an Id, need to fetch it
             if (tmdbId <= 0)
             {
@@ -102,7 +103,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
                 // Caller provides the filename with extension stripped and NOT the parsed filename
                 var parsedName = _libraryManager.ParseName(info.Name);
                 var cleanedName = TmdbUtils.CleanName(parsedName.Name);
-                var searchResults = await _tmdbClientManager.SearchCollectionAsync(cleanedName, language, cancellationToken).ConfigureAwait(false);
+                var searchResults = await _tmdbClientManager.SearchCollectionAsync(cleanedName, language, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
                 if (searchResults is not null && searchResults.Count > 0)
                 {
@@ -114,7 +115,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
 
             if (tmdbId > 0)
             {
-                var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, language, TmdbUtils.GetImageLanguagesParam(language), cancellationToken).ConfigureAwait(false);
+                var collection = await _tmdbClientManager.GetCollectionAsync(tmdbId, language, TmdbUtils.GetImageLanguagesParam(language, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
                 if (collection is not null)
                 {

+ 3 - 2
MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieImageProvider.cs

@@ -59,6 +59,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
         public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
         {
             var language = item.GetPreferredMetadataLanguage();
+            var countryCode = item.GetPreferredMetadataCountryCode();
 
             var movieTmdbId = Convert.ToInt32(item.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture);
             if (movieTmdbId <= 0)
@@ -69,7 +70,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
                     return Enumerable.Empty<RemoteImageInfo>();
                 }
 
-                var movieResult = await _tmdbClientManager.FindByExternalIdAsync(movieImdbId, FindExternalSource.Imdb, language, cancellationToken).ConfigureAwait(false);
+                var movieResult = await _tmdbClientManager.FindByExternalIdAsync(movieImdbId, FindExternalSource.Imdb, language, countryCode, cancellationToken).ConfigureAwait(false);
                 if (movieResult?.MovieResults is not null && movieResult.MovieResults.Count > 0)
                 {
                     movieTmdbId = movieResult.MovieResults[0].Id;
@@ -83,7 +84,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
 
             // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
             var movie = await _tmdbClientManager
-                .GetMovieAsync(movieTmdbId, null, null, cancellationToken)
+                .GetMovieAsync(movieTmdbId, null, null, null, cancellationToken)
                 .ConfigureAwait(false);
 
             if (movie?.Images is null)

+ 11 - 7
MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs

@@ -59,7 +59,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
                     .GetMovieAsync(
                         int.Parse(id, CultureInfo.InvariantCulture),
                         searchInfo.MetadataLanguage,
-                        TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+                        TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode),
+                        searchInfo.MetadataCountryCode,
                         cancellationToken)
                     .ConfigureAwait(false);
 
@@ -93,7 +94,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
                 var result = await _tmdbClientManager.FindByExternalIdAsync(
                     id,
                     FindExternalSource.Imdb,
-                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode),
+                    searchInfo.MetadataCountryCode,
                     cancellationToken).ConfigureAwait(false);
                 movieResults = result?.MovieResults;
             }
@@ -103,7 +105,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
                 var result = await _tmdbClientManager.FindByExternalIdAsync(
                     id,
                     FindExternalSource.TvDb,
-                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+                    TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode),
+                    searchInfo.MetadataCountryCode,
                     cancellationToken).ConfigureAwait(false);
                 movieResults = result?.MovieResults;
             }
@@ -111,7 +114,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
             if (movieResults is null)
             {
                 movieResults = await _tmdbClientManager
-                    .SearchMovieAsync(searchInfo.Name, searchInfo.Year ?? 0, searchInfo.MetadataLanguage, cancellationToken)
+                    .SearchMovieAsync(searchInfo.Name, searchInfo.Year ?? 0, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken)
                     .ConfigureAwait(false);
             }
 
@@ -152,7 +155,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
                 // Caller provides the filename with extension stripped and NOT the parsed filename
                 var parsedName = _libraryManager.ParseName(info.Name);
                 var cleanedName = TmdbUtils.CleanName(parsedName.Name);
-                var searchResults = await _tmdbClientManager.SearchMovieAsync(cleanedName, info.Year ?? parsedName.Year ?? 0, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+
+                var searchResults = await _tmdbClientManager.SearchMovieAsync(cleanedName, info.Year ?? parsedName.Year ?? 0, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
                 if (searchResults.Count > 0)
                 {
@@ -162,7 +166,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
 
             if (string.IsNullOrEmpty(tmdbId) && !string.IsNullOrEmpty(imdbId))
             {
-                var movieResultFromImdbId = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                var movieResultFromImdbId = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
                 if (movieResultFromImdbId?.MovieResults.Count > 0)
                 {
                     tmdbId = movieResultFromImdbId.MovieResults[0].Id.ToString(CultureInfo.InvariantCulture);
@@ -175,7 +179,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
             }
 
             var movieResult = await _tmdbClientManager
-                .GetMovieAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+                .GetMovieAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken)
                 .ConfigureAwait(false);
 
             if (movieResult is null)

+ 2 - 1
MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs

@@ -60,7 +60,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
             }
 
             var language = item.GetPreferredMetadataLanguage();
-            var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), language, cancellationToken).ConfigureAwait(false);
+            var countryCode = item.GetPreferredMetadataCountryCode();
+            var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), language, countryCode, cancellationToken).ConfigureAwait(false);
             if (personResult?.Images?.Profiles is null)
             {
                 return Enumerable.Empty<RemoteImageInfo>();

+ 2 - 2
MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs

@@ -39,7 +39,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), searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
                 if (personResult is not null)
                 {
@@ -101,7 +101,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
 
             if (personTmdbId > 0)
             {
-                var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
                 if (person is null)
                 {
                     return result;

+ 1 - 1
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs

@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
 
             // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
             var episodeResult = await _tmdbClientManager
-                .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
+                .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, series.DisplayOrder, null, null, null, cancellationToken)
                 .ConfigureAwait(false);
 
             var stills = episodeResult?.Images?.Stills;

+ 2 - 2
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs

@@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
                 List<TvEpisode>? result = null;
                 for (int? episode = startindex; episode <= endindex; episode++)
                 {
-                    var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
+                    var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
                     if (episodeInfo is not null)
                     {
                         (result ??= new List<TvEpisode>()).Add(episodeInfo);
@@ -157,7 +157,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             else
             {
                 episodeResult = await _tmdbClientManager
-                    .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+                    .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken)
                     .ConfigureAwait(false);
             }
 

+ 1 - 1
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs

@@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
 
             // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
             var seasonResult = await _tmdbClientManager
-                .GetSeasonAsync(seriesTmdbId, season.IndexNumber.Value, null, null, cancellationToken)
+                .GetSeasonAsync(seriesTmdbId, season.IndexNumber.Value, null, null, null, cancellationToken)
                 .ConfigureAwait(false);
 
             var posters = seasonResult?.Images?.Posters;

+ 1 - 1
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs

@@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             }
 
             var seasonResult = await _tmdbClientManager
-                .GetSeasonAsync(Convert.ToInt32(seriesTmdbId, CultureInfo.InvariantCulture), seasonNumber.Value, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+                .GetSeasonAsync(Convert.ToInt32(seriesTmdbId, CultureInfo.InvariantCulture), seasonNumber.Value, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken)
                 .ConfigureAwait(false);
 
             if (seasonResult is null)

+ 1 - 1
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs

@@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
 
             // TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
             var series = await _tmdbClientManager
-                .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), null, null, cancellationToken)
+                .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), null, null, null, cancellationToken)
                 .ConfigureAwait(false);
 
             if (series?.Images is null)

+ 8 - 8
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs

@@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbId))
             {
                 var series = await _tmdbClientManager
-                    .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), searchInfo.MetadataLanguage, searchInfo.MetadataLanguage, cancellationToken)
+                    .GetSeriesAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), searchInfo.MetadataLanguage, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken)
                     .ConfigureAwait(false);
 
                 if (series is not null)
@@ -71,7 +71,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             if (searchInfo.TryGetProviderId(MetadataProvider.Imdb, out var imdbId))
             {
                 var findResult = await _tmdbClientManager
-                    .FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, searchInfo.MetadataLanguage, cancellationToken)
+                    .FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken)
                     .ConfigureAwait(false);
 
                 var tvResults = findResult?.TvResults;
@@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             if (searchInfo.TryGetProviderId(MetadataProvider.Tvdb, out var tvdbId))
             {
                 var findResult = await _tmdbClientManager
-                    .FindByExternalIdAsync(tvdbId, FindExternalSource.TvDb, searchInfo.MetadataLanguage, cancellationToken)
+                    .FindByExternalIdAsync(tvdbId, FindExternalSource.TvDb, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken)
                     .ConfigureAwait(false);
 
                 var tvResults = findResult?.TvResults;
@@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
                 }
             }
 
-            var tvSearchResults = await _tmdbClientManager.SearchSeriesAsync(searchInfo.Name, searchInfo.MetadataLanguage, cancellationToken: cancellationToken)
+            var tvSearchResults = await _tmdbClientManager.SearchSeriesAsync(searchInfo.Name, searchInfo.MetadataLanguage, searchInfo.MetadataCountryCode, cancellationToken: cancellationToken)
                 .ConfigureAwait(false);
 
             var remoteResults = new RemoteSearchResult[tvSearchResults.Count];
@@ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
 
             if (string.IsNullOrEmpty(tmdbId) && info.TryGetProviderId(MetadataProvider.Imdb, out var imdbId))
             {
-                var searchResult = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                var searchResult = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
                 if (searchResult?.TvResults.Count > 0)
                 {
                     tmdbId = searchResult.TvResults[0].Id.ToString(CultureInfo.InvariantCulture);
@@ -182,7 +182,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
 
             if (string.IsNullOrEmpty(tmdbId) && info.TryGetProviderId(MetadataProvider.Tvdb, out var tvdbId))
             {
-                var searchResult = await _tmdbClientManager.FindByExternalIdAsync(tvdbId, FindExternalSource.TvDb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                var searchResult = await _tmdbClientManager.FindByExternalIdAsync(tvdbId, FindExternalSource.TvDb, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
                 if (searchResult?.TvResults.Count > 0)
                 {
                     tmdbId = searchResult.TvResults[0].Id.ToString(CultureInfo.InvariantCulture);
@@ -196,7 +196,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
                 // Caller provides the filename with extension stripped and NOT the parsed filename
                 var parsedName = _libraryManager.ParseName(info.Name);
                 var cleanedName = TmdbUtils.CleanName(parsedName.Name);
-                var searchResults = await _tmdbClientManager.SearchSeriesAsync(cleanedName, info.MetadataLanguage, info.Year ?? parsedName.Year ?? 0, cancellationToken).ConfigureAwait(false);
+                var searchResults = await _tmdbClientManager.SearchSeriesAsync(cleanedName, info.MetadataLanguage, info.MetadataCountryCode, info.Year ?? parsedName.Year ?? 0, cancellationToken).ConfigureAwait(false);
 
                 if (searchResults.Count > 0)
                 {
@@ -212,7 +212,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
             cancellationToken.ThrowIfCancellationRequested();
 
             var tvShow = await _tmdbClientManager
-                .GetSeriesAsync(tmdbIdInt, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+                .GetSeriesAsync(tmdbIdInt, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage, info.MetadataCountryCode), info.MetadataCountryCode, cancellationToken)
                 .ConfigureAwait(false);
 
             if (tvShow is null)

+ 37 - 25
MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs

@@ -51,9 +51,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="tmdbId">The movie's TMDb id.</param>
         /// <param name="language">The movie's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb movie or null if not found.</returns>
-        public async Task<Movie?> GetMovieAsync(int tmdbId, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        public async Task<Movie?> GetMovieAsync(int tmdbId, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"movie-{tmdbId.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out Movie? movie))
@@ -71,7 +72,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             movie = await _tmDbClient.GetMovieAsync(
                 tmdbId,
-                TmdbUtils.NormalizeLanguage(language),
+                TmdbUtils.NormalizeLanguage(language, countryCode),
                 imageLanguages,
                 extraMethods,
                 cancellationToken).ConfigureAwait(false);
@@ -90,9 +91,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="tmdbId">The collection's TMDb id.</param>
         /// <param name="language">The collection's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb collection or null if not found.</returns>
-        public async Task<Collection?> GetCollectionAsync(int tmdbId, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        public async Task<Collection?> GetCollectionAsync(int tmdbId, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"collection-{tmdbId.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out Collection? collection))
@@ -104,7 +106,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             collection = await _tmDbClient.GetCollectionAsync(
                 tmdbId,
-                TmdbUtils.NormalizeLanguage(language),
+                TmdbUtils.NormalizeLanguage(language, countryCode),
                 imageLanguages,
                 CollectionMethods.Images,
                 cancellationToken).ConfigureAwait(false);
@@ -123,9 +125,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="tmdbId">The tv show's TMDb id.</param>
         /// <param name="language">The tv show's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb tv show information or null if not found.</returns>
-        public async Task<TvShow?> GetSeriesAsync(int tmdbId, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        public async Task<TvShow?> GetSeriesAsync(int tmdbId, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"series-{tmdbId.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out TvShow? series))
@@ -143,7 +146,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             series = await _tmDbClient.GetTvShowAsync(
                 tmdbId,
-                language: TmdbUtils.NormalizeLanguage(language),
+                language: TmdbUtils.NormalizeLanguage(language, countryCode),
                 includeImageLanguage: imageLanguages,
                 extraMethods: extraMethods,
                 cancellationToken: cancellationToken).ConfigureAwait(false);
@@ -163,9 +166,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="displayOrder">The display order.</param>
         /// <param name="language">The tv show's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb tv show episode group information or null if not found.</returns>
-        private async Task<TvGroupCollection?> GetSeriesGroupAsync(int tvShowId, string displayOrder, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        private async Task<TvGroupCollection?> GetSeriesGroupAsync(int tvShowId, string displayOrder, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             TvGroupType? groupType =
                 string.Equals(displayOrder, "originalAirDate", StringComparison.Ordinal) ? TvGroupType.OriginalAirDate :
@@ -190,7 +194,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             await EnsureClientConfigAsync().ConfigureAwait(false);
 
-            var series = await GetSeriesAsync(tvShowId, language, imageLanguages, cancellationToken).ConfigureAwait(false);
+            var series = await GetSeriesAsync(tvShowId, language, imageLanguages, countryCode, cancellationToken).ConfigureAwait(false);
             var episodeGroupId = series?.EpisodeGroups.Results.Find(g => g.Type == groupType)?.Id;
 
             if (episodeGroupId is null)
@@ -200,7 +204,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             group = await _tmDbClient.GetTvEpisodeGroupsAsync(
                 episodeGroupId,
-                language: TmdbUtils.NormalizeLanguage(language),
+                language: TmdbUtils.NormalizeLanguage(language, countryCode),
                 cancellationToken: cancellationToken).ConfigureAwait(false);
 
             if (group is not null)
@@ -218,9 +222,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="seasonNumber">The season number.</param>
         /// <param name="language">The tv season's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb tv season information or null if not found.</returns>
-        public async Task<TvSeason?> GetSeasonAsync(int tvShowId, int seasonNumber, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        public async Task<TvSeason?> GetSeasonAsync(int tvShowId, int seasonNumber, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"season-{tvShowId.ToString(CultureInfo.InvariantCulture)}-s{seasonNumber.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out TvSeason? season))
@@ -233,7 +238,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
             season = await _tmDbClient.GetTvSeasonAsync(
                 tvShowId,
                 seasonNumber,
-                language: TmdbUtils.NormalizeLanguage(language),
+                language: TmdbUtils.NormalizeLanguage(language, countryCode),
                 includeImageLanguage: imageLanguages,
                 extraMethods: TvSeasonMethods.Credits | TvSeasonMethods.Images | TvSeasonMethods.ExternalIds | TvSeasonMethods.Videos,
                 cancellationToken: cancellationToken).ConfigureAwait(false);
@@ -255,9 +260,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="displayOrder">The display order.</param>
         /// <param name="language">The episode's language.</param>
         /// <param name="imageLanguages">A comma-separated list of image languages.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb tv episode information or null if not found.</returns>
-        public async Task<TvEpisode?> GetEpisodeAsync(int tvShowId, int seasonNumber, int episodeNumber, string displayOrder, string? language, string? imageLanguages, CancellationToken cancellationToken)
+        public async Task<TvEpisode?> GetEpisodeAsync(int tvShowId, int seasonNumber, int episodeNumber, string displayOrder, string? language, string? imageLanguages, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"episode-{tvShowId.ToString(CultureInfo.InvariantCulture)}-s{seasonNumber.ToString(CultureInfo.InvariantCulture)}e{episodeNumber.ToString(CultureInfo.InvariantCulture)}-{displayOrder}-{language}";
             if (_memoryCache.TryGetValue(key, out TvEpisode? episode))
@@ -267,7 +273,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             await EnsureClientConfigAsync().ConfigureAwait(false);
 
-            var group = await GetSeriesGroupAsync(tvShowId, displayOrder, language, imageLanguages, cancellationToken).ConfigureAwait(false);
+            var group = await GetSeriesGroupAsync(tvShowId, displayOrder, language, imageLanguages, countryCode, cancellationToken).ConfigureAwait(false);
             if (group is not null)
             {
                 var season = group.Groups.Find(s => s.Order == seasonNumber);
@@ -284,7 +290,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
                 tvShowId,
                 seasonNumber,
                 episodeNumber,
-                language: TmdbUtils.NormalizeLanguage(language),
+                language: TmdbUtils.NormalizeLanguage(language, countryCode),
                 includeImageLanguage: imageLanguages,
                 extraMethods: TvEpisodeMethods.Credits | TvEpisodeMethods.Images | TvEpisodeMethods.ExternalIds | TvEpisodeMethods.Videos,
                 cancellationToken: cancellationToken).ConfigureAwait(false);
@@ -301,10 +307,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// Gets a person eg. cast or crew member from the TMDb API based on its TMDb id.
         /// </summary>
         /// <param name="personTmdbId">The person's TMDb id.</param>
-        /// <param name="language">The episode's language.</param>
+        /// <param name="language">The person's language.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb person information or null if not found.</returns>
-        public async Task<Person?> GetPersonAsync(int personTmdbId, string language, CancellationToken cancellationToken)
+        public async Task<Person?> GetPersonAsync(int personTmdbId, string language, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out Person? person))
@@ -316,7 +323,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
 
             person = await _tmDbClient.GetPersonAsync(
                 personTmdbId,
-                TmdbUtils.NormalizeLanguage(language),
+                TmdbUtils.NormalizeLanguage(language, countryCode),
                 PersonMethods.TvCredits | PersonMethods.MovieCredits | PersonMethods.Images | PersonMethods.ExternalIds,
                 cancellationToken).ConfigureAwait(false);
 
@@ -334,12 +341,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="externalId">The item's external id.</param>
         /// <param name="source">The source of the id eg. IMDb.</param>
         /// <param name="language">The item's language.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb item or null if not found.</returns>
         public async Task<FindContainer?> FindByExternalIdAsync(
             string externalId,
             FindExternalSource source,
             string language,
+            string? countryCode,
             CancellationToken cancellationToken)
         {
             var key = $"find-{source.ToString()}-{externalId.ToString(CultureInfo.InvariantCulture)}-{language}";
@@ -353,7 +362,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
             result = await _tmDbClient.FindAsync(
                 source,
                 externalId,
-                TmdbUtils.NormalizeLanguage(language),
+                TmdbUtils.NormalizeLanguage(language, countryCode),
                 cancellationToken).ConfigureAwait(false);
 
             if (result is not null)
@@ -369,10 +378,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// </summary>
         /// <param name="name">The name of the tv show.</param>
         /// <param name="language">The tv show's language.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="year">The year the tv show first aired.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb tv show information.</returns>
-        public async Task<IReadOnlyList<SearchTv>> SearchSeriesAsync(string name, string language, int year = 0, CancellationToken cancellationToken = default)
+        public async Task<IReadOnlyList<SearchTv>> SearchSeriesAsync(string name, string language, string? countryCode, int year = 0, CancellationToken cancellationToken = default)
         {
             var key = $"searchseries-{name}-{year.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out SearchContainer<SearchTv>? series) && series is not null)
@@ -383,7 +393,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
             await EnsureClientConfigAsync().ConfigureAwait(false);
 
             var searchResults = await _tmDbClient
-                .SearchTvShowAsync(name, TmdbUtils.NormalizeLanguage(language), includeAdult: Plugin.Instance.Configuration.IncludeAdult, firstAirDateYear: year, cancellationToken: cancellationToken)
+                .SearchTvShowAsync(name, TmdbUtils.NormalizeLanguage(language, countryCode), includeAdult: Plugin.Instance.Configuration.IncludeAdult, firstAirDateYear: year, cancellationToken: cancellationToken)
                 .ConfigureAwait(false);
 
             if (searchResults.Results.Count > 0)
@@ -431,7 +441,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <returns>The TMDb movie information.</returns>
         public Task<IReadOnlyList<SearchMovie>> SearchMovieAsync(string name, string language, CancellationToken cancellationToken)
         {
-            return SearchMovieAsync(name, 0, language, cancellationToken);
+            return SearchMovieAsync(name, 0, language, null, cancellationToken);
         }
 
         /// <summary>
@@ -440,9 +450,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// <param name="name">The name of the movie.</param>
         /// <param name="year">The release year of the movie.</param>
         /// <param name="language">The movie's language.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb movie information.</returns>
-        public async Task<IReadOnlyList<SearchMovie>> SearchMovieAsync(string name, int year, string language, CancellationToken cancellationToken)
+        public async Task<IReadOnlyList<SearchMovie>> SearchMovieAsync(string name, int year, string language, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"moviesearch-{name}-{year.ToString(CultureInfo.InvariantCulture)}-{language}";
             if (_memoryCache.TryGetValue(key, out SearchContainer<SearchMovie>? movies) && movies is not null)
@@ -453,7 +464,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
             await EnsureClientConfigAsync().ConfigureAwait(false);
 
             var searchResults = await _tmDbClient
-                .SearchMovieAsync(name, TmdbUtils.NormalizeLanguage(language), includeAdult: Plugin.Instance.Configuration.IncludeAdult, year: year, cancellationToken: cancellationToken)
+                .SearchMovieAsync(name, TmdbUtils.NormalizeLanguage(language, countryCode), includeAdult: Plugin.Instance.Configuration.IncludeAdult, year: year, cancellationToken: cancellationToken)
                 .ConfigureAwait(false);
 
             if (searchResults.Results.Count > 0)
@@ -469,9 +480,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// </summary>
         /// <param name="name">The name of the collection.</param>
         /// <param name="language">The collection's language.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>The TMDb collection information.</returns>
-        public async Task<IReadOnlyList<SearchCollection>> SearchCollectionAsync(string name, string language, CancellationToken cancellationToken)
+        public async Task<IReadOnlyList<SearchCollection>> SearchCollectionAsync(string name, string language, string? countryCode, CancellationToken cancellationToken)
         {
             var key = $"collectionsearch-{name}-{language}";
             if (_memoryCache.TryGetValue(key, out SearchContainer<SearchCollection>? collections) && collections is not null)
@@ -482,7 +494,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
             await EnsureClientConfigAsync().ConfigureAwait(false);
 
             var searchResults = await _tmDbClient
-                .SearchCollectionAsync(name, TmdbUtils.NormalizeLanguage(language), cancellationToken: cancellationToken)
+                .SearchCollectionAsync(name, TmdbUtils.NormalizeLanguage(language, countryCode), cancellationToken: cancellationToken)
                 .ConfigureAwait(false);
 
             if (searchResults.Results.Count > 0)

+ 13 - 3
MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs

@@ -105,14 +105,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// Normalizes a language string for use with TMDb's include image language parameter.
         /// </summary>
         /// <param name="preferredLanguage">The preferred language as either a 2 letter code with or without country code.</param>
+        /// <param name="countryCode">The country code, ISO 3166-1.</param>
         /// <returns>The comma separated language string.</returns>
-        public static string GetImageLanguagesParam(string preferredLanguage)
+        public static string GetImageLanguagesParam(string preferredLanguage, string? countryCode = null)
         {
             var languages = new List<string>();
 
             if (!string.IsNullOrEmpty(preferredLanguage))
             {
-                preferredLanguage = NormalizeLanguage(preferredLanguage);
+                preferredLanguage = NormalizeLanguage(preferredLanguage, countryCode);
 
                 languages.Add(preferredLanguage);
 
@@ -140,15 +141,24 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
         /// Normalizes a language string for use with TMDb's language parameter.
         /// </summary>
         /// <param name="language">The language code.</param>
+        /// <param name="countryCode">The country code.</param>
         /// <returns>The normalized language code.</returns>
         [return: NotNullIfNotNull(nameof(language))]
-        public static string? NormalizeLanguage(string? language)
+        public static string? NormalizeLanguage(string? language, string? countryCode = null)
         {
             if (string.IsNullOrEmpty(language))
             {
                 return language;
             }
 
+            // Handle es-419 (Latin American Spanish) by converting to regional variant
+            if (string.Equals(language, "es-419", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(countryCode))
+            {
+                language = string.Equals(countryCode, "AR", StringComparison.OrdinalIgnoreCase)
+                    ? "es-AR"
+                    : "es-MX";
+            }
+
             // TMDb requires this to be uppercase
             // Everything after the hyphen must be written in uppercase due to a way TMDb wrote their API.
             // See here: https://www.themoviedb.org/talk/5119221d760ee36c642af4ad?page=3#56e372a0c3a3685a9e0019ab