diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index 17175f91cf..99402a9694 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -13,13 +13,15 @@ namespace MediaBrowser.Controller.Providers public MetadataResult() { Images = new List(); + ResultLanguage = "en"; } public List People { get; set; } public bool HasMetadata { get; set; } public T Item { get; set; } - + public string ResultLanguage { get; set; } + public bool QueriedById { get; set; } public void AddPerson(PersonInfo p) { if (People == null) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 18405aae91..48f8ebb049 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -651,6 +651,8 @@ namespace MediaBrowser.Providers.Manager { var refreshResult = new RefreshResult(); + var results = new List>(); + foreach (var provider in providers) { var providerName = provider.GetType().Name; @@ -667,7 +669,7 @@ namespace MediaBrowser.Providers.Manager if (result.HasMetadata) { - MergeData(result, temp, new List(), false, false); + results.Add(result); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; } @@ -688,6 +690,38 @@ namespace MediaBrowser.Providers.Manager } } + var orderedResults = new List>(); + + if (string.IsNullOrEmpty(id.MetadataLanguage)) + { + orderedResults.AddRange(results); + } + else + { + // prioritize results with matching ResultLanguage + foreach (var result in results) + { + if (!string.IsNullOrEmpty(result.ResultLanguage) && result.ResultLanguage == id.MetadataLanguage && result.QueriedById) + { + orderedResults.Add(result); + } + } + + // add all other results + foreach (var result in results) + { + if (!orderedResults.Contains(result)) + { + orderedResults.Add(result); + } + } + } + + foreach (var result in results) + { + MergeData(result, temp, new List(), false, false); + } + return refreshResult; } diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index 914b775af7..428bde2f28 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -212,13 +212,15 @@ namespace MediaBrowser.Providers.Omdb { var result = new MetadataResult { - Item = new Series() + Item = new Series(), + QueriedById = true }; var imdbId = info.GetProviderId(MetadataProviders.Imdb); if (string.IsNullOrWhiteSpace(imdbId)) { imdbId = await GetSeriesImdbId(info, cancellationToken).ConfigureAwait(false); + result.QueriedById = false; } if (!string.IsNullOrEmpty(imdbId)) @@ -251,13 +253,15 @@ namespace MediaBrowser.Providers.Omdb { var result = new MetadataResult { - Item = new T() + Item = new T(), + QueriedById = true }; var imdbId = info.GetProviderId(MetadataProviders.Imdb); if (string.IsNullOrWhiteSpace(imdbId)) { imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false); + result.QueriedById = false; } if (!string.IsNullOrEmpty(imdbId)) diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs index 621f665146..78bce241f4 100644 --- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs @@ -43,7 +43,8 @@ namespace MediaBrowser.Providers.TV { var result = new MetadataResult() { - Item = new Episode() + Item = new Episode(), + QueriedById = true }; // Allowing this will dramatically increase scan times diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs index bc9842b736..748124c033 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs @@ -91,6 +91,13 @@ namespace MediaBrowser.Providers.TV var response = await GetEpisodeInfo(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); result.HasMetadata = true; + result.QueriedById = true; + + if (!string.IsNullOrEmpty(response.overview)) + { + // if overview is non-empty, we can assume that localized data was returned + result.ResultLanguage = info.MetadataLanguage; + } var item = new Episode(); result.Item = item; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs index 3245a2c85a..fb06780293 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs @@ -119,6 +119,7 @@ namespace MediaBrowser.Providers.TV public async Task> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); + result.QueriedById = true; var tmdbId = info.GetProviderId(MetadataProviders.Tmdb); @@ -154,6 +155,7 @@ namespace MediaBrowser.Providers.TV if (string.IsNullOrEmpty(tmdbId)) { + result.QueriedById = false; var searchResults = await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetSearchResults(info, cancellationToken).ConfigureAwait(false); var searchResult = searchResults.FirstOrDefault(); @@ -168,7 +170,7 @@ namespace MediaBrowser.Providers.TV { cancellationToken.ThrowIfCancellationRequested(); - result.Item = await FetchSeriesData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + result = await FetchMovieData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); result.HasMetadata = result.Item != null; } @@ -176,7 +178,7 @@ namespace MediaBrowser.Providers.TV return result; } - private async Task FetchSeriesData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken) + private async Task> FetchMovieData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken) { string dataFilePath = null; RootObject seriesInfo = null; @@ -194,16 +196,18 @@ namespace MediaBrowser.Providers.TV tmdbId = seriesInfo.id.ToString(_usCulture); dataFilePath = GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath); await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false); - var item = new Series(); + var result = new MetadataResult(); + result.Item = new Series(); + result.ResultLanguage = seriesInfo.ResultLanguage; - ProcessMainInfo(item, seriesInfo, preferredCountryCode); + ProcessMainInfo(result.Item, seriesInfo, preferredCountryCode); - return item; + return result; } private void ProcessMainInfo(Series series, RootObject seriesInfo, string preferredCountryCode) @@ -324,7 +328,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } @@ -354,6 +358,11 @@ namespace MediaBrowser.Providers.TV }).ConfigureAwait(false)) { mainResult = _jsonSerializer.DeserializeFromStream(json); + + if (!string.IsNullOrEmpty(language)) + { + mainResult.ResultLanguage = language; + } } cancellationToken.ThrowIfCancellationRequested(); @@ -385,6 +394,7 @@ namespace MediaBrowser.Providers.TV var englishResult = _jsonSerializer.DeserializeFromStream(json); mainResult.overview = englishResult.overview; + mainResult.ResultLanguage = "en"; } } @@ -627,6 +637,7 @@ namespace MediaBrowser.Providers.TV public ExternalIds external_ids { get; set; } public Videos videos { get; set; } public ContentRatings content_ratings { get; set; } + public string ResultLanguage { get; set; } } public int Order diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index a41a95c126..41a2282d80 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -108,6 +108,7 @@ namespace MediaBrowser.Providers.TV public async Task> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken) { var result = new MetadataResult(); + result.QueriedById = true; if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue)) @@ -713,6 +714,17 @@ namespace MediaBrowser.Providers.TV } } + break; + } + case "Language": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + result.ResultLanguage = val; + } + break; } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 66a02eba21..4ac9e68361 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -93,9 +93,11 @@ namespace MediaBrowser.Providers.TV public async Task> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken) { var result = new MetadataResult(); + result.QueriedById = true; if (!IsValidSeries(itemId.ProviderIds)) { + result.QueriedById = false; await Identify(itemId).ConfigureAwait(false); } @@ -159,7 +161,7 @@ namespace MediaBrowser.Providers.TV var seriesXmlPath = GetSeriesXmlPath(seriesProviderIds, metadataLanguage); var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml"); - FetchSeriesInfo(series, seriesXmlPath, cancellationToken); + FetchSeriesInfo(result, seriesXmlPath, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); @@ -607,7 +609,7 @@ namespace MediaBrowser.Providers.TV return name.Trim(); } - private void FetchSeriesInfo(Series item, string seriesXmlPath, CancellationToken cancellationToken) + private void FetchSeriesInfo(MetadataResult result, string seriesXmlPath, CancellationToken cancellationToken) { var settings = new XmlReaderSettings { @@ -639,7 +641,7 @@ namespace MediaBrowser.Providers.TV { using (var subtree = reader.ReadSubtree()) { - FetchDataFromSeriesNode(item, subtree, cancellationToken); + FetchDataFromSeriesNode(result, subtree, cancellationToken); } break; } @@ -667,9 +669,9 @@ namespace MediaBrowser.Providers.TV } } - if (item.Status.HasValue && item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0) + if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0) { - item.EndDate = episiodeAirDates.Max(); + result.Item.EndDate = episiodeAirDates.Max(); } } @@ -861,8 +863,10 @@ namespace MediaBrowser.Providers.TV } } - private void FetchDataFromSeriesNode(Series item, XmlReader reader, CancellationToken cancellationToken) + private void FetchDataFromSeriesNode(MetadataResult result, XmlReader reader, CancellationToken cancellationToken) { + Series item = result.Item; + reader.MoveToContent(); // Loop through each element @@ -886,6 +890,12 @@ namespace MediaBrowser.Providers.TV break; } + case "Language": + { + result.ResultLanguage = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); + break; + } + case "Airs_DayOfWeek": { var val = reader.ReadElementContentAsString();