Merge pull request #6870 from cvium/fix_omdb_image_provider

pull/6890/head
Cody Robibero 3 years ago committed by GitHub
commit 03c7bcf9c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -402,8 +402,6 @@ namespace MediaBrowser.Model.Configuration
/// </summary> /// </summary>
public bool RequireHttps { get; set; } = false; public bool RequireHttps { get; set; } = false;
public bool EnableNewOmdbSupport { get; set; } = true;
/// <summary> /// <summary>
/// Gets or sets the filter for remote IP connectivity. Used in conjuntion with <seealso cref="IsRemoteIPFilterBlacklist"/>. /// Gets or sets the filter for remote IP connectivity. Used in conjuntion with <seealso cref="IsRemoteIPFilterBlacklist"/>.
/// </summary> /// </summary>

@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -17,24 +16,17 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{ {
public class OmdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder public class OmdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
{ {
private readonly IHttpClientFactory _httpClientFactory;
private readonly OmdbItemProvider _itemProvider; private readonly OmdbItemProvider _itemProvider;
private readonly IFileSystem _fileSystem; private readonly OmdbProvider _omdbProvider;
private readonly IServerConfigurationManager _configurationManager;
private readonly IApplicationHost _appHost;
public OmdbEpisodeProvider( public OmdbEpisodeProvider(
IApplicationHost appHost,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager, ILibraryManager libraryManager,
IFileSystem fileSystem, IFileSystem fileSystem,
IServerConfigurationManager configurationManager) IServerConfigurationManager configurationManager)
{ {
_httpClientFactory = httpClientFactory; _itemProvider = new OmdbItemProvider(httpClientFactory, libraryManager, fileSystem, configurationManager);
_fileSystem = fileSystem; _omdbProvider = new OmdbProvider(httpClientFactory, fileSystem, configurationManager);
_configurationManager = configurationManager;
_appHost = appHost;
_itemProvider = new OmdbItemProvider(_appHost, httpClientFactory, libraryManager, fileSystem, configurationManager);
} }
// After TheTvDb // After TheTvDb
@ -44,12 +36,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{ {
return _itemProvider.GetSearchResults(searchInfo, "episode", cancellationToken); return _itemProvider.GetSearchResults(searchInfo, cancellationToken);
} }
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken) public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{ {
var result = new MetadataResult<Episode>() var result = new MetadataResult<Episode>
{ {
Item = new Episode(), Item = new Episode(),
QueriedById = true QueriedById = true
@ -61,13 +53,20 @@ namespace MediaBrowser.Providers.Plugins.Omdb
return result; return result;
} }
if (info.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string? seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId)) if (info.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string? seriesImdbId)
&& !string.IsNullOrEmpty(seriesImdbId)
&& info.IndexNumber.HasValue
&& info.ParentIndexNumber.HasValue)
{ {
if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue) result.HasMetadata = await _omdbProvider.FetchEpisodeData(
{ result,
result.HasMetadata = await new OmdbProvider(_httpClientFactory, _fileSystem, _configurationManager) info.IndexNumber.Value,
.FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProvider.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); info.ParentIndexNumber.Value,
} info.GetProviderId(MetadataProvider.Imdb),
seriesImdbId,
info.MetadataLanguage,
info.MetadataCountryCode,
cancellationToken).ConfigureAwait(false);
} }
return result; return result;

@ -2,8 +2,9 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,14 +23,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb
public class OmdbImageProvider : IRemoteImageProvider, IHasOrder public class OmdbImageProvider : IRemoteImageProvider, IHasOrder
{ {
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;
private readonly IFileSystem _fileSystem; private readonly OmdbProvider _omdbProvider;
private readonly IServerConfigurationManager _configurationManager;
public OmdbImageProvider(IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager) public OmdbImageProvider(IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{ {
_httpClientFactory = httpClientFactory; _httpClientFactory = httpClientFactory;
_fileSystem = fileSystem; _omdbProvider = new OmdbProvider(_httpClientFactory, fileSystem, configurationManager);
_configurationManager = configurationManager;
} }
public string Name => "The Open Movie Database"; public string Name => "The Open Movie Database";
@ -49,38 +48,27 @@ namespace MediaBrowser.Providers.Plugins.Omdb
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken) public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{ {
var imdbId = item.GetProviderId(MetadataProvider.Imdb); var imdbId = item.GetProviderId(MetadataProvider.Imdb);
if (string.IsNullOrWhiteSpace(imdbId))
{
return Enumerable.Empty<RemoteImageInfo>();
}
var list = new List<RemoteImageInfo>(); var rootObject = await _omdbProvider.GetRootObject(imdbId, cancellationToken).ConfigureAwait(false);
var provider = new OmdbProvider(_httpClientFactory, _fileSystem, _configurationManager);
if (!string.IsNullOrWhiteSpace(imdbId)) if (string.IsNullOrEmpty(rootObject.Poster))
{ {
var rootObject = await provider.GetRootObject(imdbId, cancellationToken).ConfigureAwait(false); return Enumerable.Empty<RemoteImageInfo>();
}
if (!string.IsNullOrEmpty(rootObject.Poster)) // the poster url is sometimes higher quality than the poster api
return new[]
{
new RemoteImageInfo
{ {
if (item is Episode) ProviderName = Name,
{ Url = rootObject.Poster
// img.omdbapi.com is returning 404's
list.Add(new RemoteImageInfo
{
ProviderName = Name,
Url = rootObject.Poster
});
}
else
{
list.Add(new RemoteImageInfo
{
ProviderName = Name,
Url = string.Format(CultureInfo.InvariantCulture, "https://img.omdbapi.com/?i={0}&apikey=2c9d9507", imdbId)
});
}
} }
} };
return list;
} }
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)

@ -8,11 +8,11 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json;
using MediaBrowser.Common;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -31,13 +31,10 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{ {
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _configurationManager;
private readonly IApplicationHost _appHost;
private readonly JsonSerializerOptions _jsonOptions; private readonly JsonSerializerOptions _jsonOptions;
private readonly OmdbProvider _omdbProvider;
public OmdbItemProvider( public OmdbItemProvider(
IApplicationHost appHost,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager, ILibraryManager libraryManager,
IFileSystem fileSystem, IFileSystem fileSystem,
@ -45,9 +42,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{ {
_httpClientFactory = httpClientFactory; _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_fileSystem = fileSystem; _omdbProvider = new OmdbProvider(_httpClientFactory, fileSystem, configurationManager);
_configurationManager = configurationManager;
_appHost = appHost;
_jsonOptions = new JsonSerializerOptions(JsonDefaults.Options); _jsonOptions = new JsonSerializerOptions(JsonDefaults.Options);
_jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); _jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter());
@ -59,185 +54,166 @@ namespace MediaBrowser.Providers.Plugins.Omdb
// After primary option // After primary option
public int Order => 2; public int Order => 2;
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken)
{
return GetSearchResultsInternal(searchInfo, true, cancellationToken);
}
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
{ {
return GetSearchResults(searchInfo, "series", cancellationToken); return GetSearchResultsInternal(searchInfo, true, cancellationToken);
} }
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken) public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken)
{ {
return GetSearchResults(searchInfo, "movie", cancellationToken); return GetSearchResultsInternal(searchInfo, true, cancellationToken);
} }
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken) public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{ {
return GetSearchResultsInternal(searchInfo, type, true, cancellationToken); return GetSearchResultsInternal(searchInfo, true, cancellationToken);
} }
private async Task<IEnumerable<RemoteSearchResult>> GetSearchResultsInternal(ItemLookupInfo searchInfo, string type, bool isSearch, CancellationToken cancellationToken) private async Task<IEnumerable<RemoteSearchResult>> GetSearchResultsInternal(ItemLookupInfo searchInfo, bool isSearch, CancellationToken cancellationToken)
{ {
var type = searchInfo switch
{
EpisodeInfo => "episode",
SeriesInfo => "series",
_ => "movie"
};
// This is a bit hacky?
var episodeSearchInfo = searchInfo as EpisodeInfo; var episodeSearchInfo = searchInfo as EpisodeInfo;
var indexNumberEnd = episodeSearchInfo?.IndexNumberEnd;
var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb); var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb);
var urlQuery = "plot=full&r=json"; var urlQuery = new StringBuilder("plot=full&r=json");
if (type == "episode" && episodeSearchInfo != null) if (episodeSearchInfo != null)
{ {
episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId); episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId);
} if (searchInfo.IndexNumber.HasValue)
{
var name = searchInfo.Name; urlQuery.Append("&Episode=").Append(searchInfo.IndexNumber.Value);
var year = searchInfo.Year; }
if (!string.IsNullOrWhiteSpace(name)) if (searchInfo.ParentIndexNumber.HasValue)
{ {
var parsedName = _libraryManager.ParseName(name); urlQuery.Append("&Season=").Append(searchInfo.ParentIndexNumber.Value);
var yearInName = parsedName.Year; }
name = parsedName.Name;
year ??= yearInName;
} }
if (string.IsNullOrWhiteSpace(imdbId)) if (string.IsNullOrWhiteSpace(imdbId))
{ {
if (year.HasValue) var name = searchInfo.Name;
var year = searchInfo.Year;
if (!string.IsNullOrWhiteSpace(name))
{ {
urlQuery += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture); var parsedName = _libraryManager.ParseName(name);
var yearInName = parsedName.Year;
name = parsedName.Name;
year ??= yearInName;
} }
// &s means search and returns a list of results as opposed to t if (year.HasValue)
if (isSearch)
{
urlQuery += "&s=" + WebUtility.UrlEncode(name);
}
else
{ {
urlQuery += "&t=" + WebUtility.UrlEncode(name); urlQuery.Append("&y=").Append(year);
} }
urlQuery += "&type=" + type; // &s means search and returns a list of results as opposed to t
urlQuery.Append(isSearch ? "&s=" : "&t=");
urlQuery.Append(WebUtility.UrlEncode(name));
urlQuery.Append("&type=")
.Append(type);
} }
else else
{ {
urlQuery += "&i=" + imdbId; urlQuery.Append("&i=")
.Append(imdbId);
isSearch = false; isSearch = false;
} }
if (type == "episode") var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());
{
if (searchInfo.IndexNumber.HasValue)
{
urlQuery += string.Format(CultureInfo.InvariantCulture, "&Episode={0}", searchInfo.IndexNumber);
}
if (searchInfo.ParentIndexNumber.HasValue)
{
urlQuery += string.Format(CultureInfo.InvariantCulture, "&Season={0}", searchInfo.ParentIndexNumber);
}
}
var url = OmdbProvider.GetOmdbUrl(urlQuery);
using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
var resultList = new List<SearchResult>();
if (isSearch) if (isSearch)
{ {
var searchResultList = await JsonSerializer.DeserializeAsync<SearchResultList>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); var searchResultList = await JsonSerializer.DeserializeAsync<SearchResultList>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
if (searchResultList != null && searchResultList.Search != null) if (searchResultList?.Search != null)
{ {
resultList.AddRange(searchResultList.Search); var resultCount = searchResultList.Search.Count;
var result = new RemoteSearchResult[resultCount];
for (var i = 0; i < resultCount; i++)
{
result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
}
return result;
} }
} }
else else
{ {
var result = await JsonSerializer.DeserializeAsync<SearchResult>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); var result = await JsonSerializer.DeserializeAsync<SearchResult>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase)) if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
{ {
resultList.Add(result); return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
} }
} }
return resultList.Select(result => return Enumerable.Empty<RemoteSearchResult>();
{
var item = new RemoteSearchResult
{
IndexNumber = searchInfo.IndexNumber,
Name = result.Title,
ParentIndexNumber = searchInfo.ParentIndexNumber,
SearchProviderName = Name
};
if (episodeSearchInfo != null && episodeSearchInfo.IndexNumberEnd.HasValue)
{
item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value;
}
item.SetProviderId(MetadataProvider.Imdb, result.imdbID);
if (result.Year.Length > 0
&& int.TryParse(result.Year.AsSpan().Slice(0, Math.Min(result.Year.Length, 4)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear))
{
item.ProductionYear = parsedYear;
}
if (!string.IsNullOrEmpty(result.Released)
&& DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released))
{
item.PremiereDate = released;
}
if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase))
{
item.ImageUrl = result.Poster;
}
return item;
});
} }
public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken) public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken)
{ {
return GetMovieResult<Trailer>(info, cancellationToken); return GetResult<Trailer>(info, cancellationToken);
} }
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken) public Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
{ {
return GetSearchResults(searchInfo, "movie", cancellationToken); return GetResult<Series>(info, cancellationToken);
} }
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
{ {
var result = new MetadataResult<Series> return GetResult<Movie>(info, cancellationToken);
}
private RemoteSearchResult ResultToMetadataResult(SearchResult result, ItemLookupInfo searchInfo, int? indexNumberEnd)
{
var item = new RemoteSearchResult
{ {
Item = new Series(), IndexNumber = searchInfo.IndexNumber,
QueriedById = true Name = result.Title,
ParentIndexNumber = searchInfo.ParentIndexNumber,
SearchProviderName = Name,
IndexNumberEnd = indexNumberEnd
}; };
var imdbId = info.GetProviderId(MetadataProvider.Imdb); item.SetProviderId(MetadataProvider.Imdb, result.imdbID);
if (string.IsNullOrWhiteSpace(imdbId))
if (OmdbProvider.TryParseYear(result.Year, out var parsedYear))
{ {
imdbId = await GetSeriesImdbId(info, cancellationToken).ConfigureAwait(false); item.ProductionYear = parsedYear;
result.QueriedById = false;
} }
if (!string.IsNullOrEmpty(imdbId)) if (!string.IsNullOrEmpty(result.Released)
&& DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released))
{ {
result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); item.PremiereDate = released;
result.HasMetadata = true;
await new OmdbProvider(_httpClientFactory, _fileSystem, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
} }
return result; if (!string.IsNullOrWhiteSpace(result.Poster))
} {
item.ImageUrl = result.Poster;
}
public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken) return item;
{
return GetMovieResult<Movie>(info, cancellationToken);
} }
private async Task<MetadataResult<T>> GetMovieResult<T>(ItemLookupInfo info, CancellationToken cancellationToken) private async Task<MetadataResult<T>> GetResult<T>(ItemLookupInfo info, CancellationToken cancellationToken)
where T : BaseItem, new() where T : BaseItem, new()
{ {
var result = new MetadataResult<T> var result = new MetadataResult<T>
@ -249,7 +225,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
var imdbId = info.GetProviderId(MetadataProvider.Imdb); var imdbId = info.GetProviderId(MetadataProvider.Imdb);
if (string.IsNullOrWhiteSpace(imdbId)) if (string.IsNullOrWhiteSpace(imdbId))
{ {
imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false); imdbId = await GetImdbId(info, cancellationToken).ConfigureAwait(false);
result.QueriedById = false; result.QueriedById = false;
} }
@ -258,22 +234,15 @@ namespace MediaBrowser.Providers.Plugins.Omdb
result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.Item.SetProviderId(MetadataProvider.Imdb, imdbId);
result.HasMetadata = true; result.HasMetadata = true;
await new OmdbProvider(_httpClientFactory, _fileSystem, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); await _omdbProvider.Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
} }
return result; return result;
} }
private async Task<string> GetMovieImdbId(ItemLookupInfo info, CancellationToken cancellationToken) private async Task<string> GetImdbId(ItemLookupInfo info, CancellationToken cancellationToken)
{
var results = await GetSearchResultsInternal(info, "movie", false, cancellationToken).ConfigureAwait(false);
var first = results.FirstOrDefault();
return first?.GetProviderId(MetadataProvider.Imdb);
}
private async Task<string> GetSeriesImdbId(SeriesInfo info, CancellationToken cancellationToken)
{ {
var results = await GetSearchResultsInternal(info, "series", false, cancellationToken).ConfigureAwait(false); var results = await GetSearchResultsInternal(info, false, cancellationToken).ConfigureAwait(false);
var first = results.FirstOrDefault(); var first = results.FirstOrDefault();
return first?.GetProviderId(MetadataProvider.Imdb); return first?.GetProviderId(MetadataProvider.Imdb);
} }

@ -4,10 +4,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -40,8 +42,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb
_configurationManager = configurationManager; _configurationManager = configurationManager;
_jsonOptions = new JsonSerializerOptions(JsonDefaults.Options); _jsonOptions = new JsonSerializerOptions(JsonDefaults.Options);
_jsonOptions.Converters.Add(new JsonOmdbNotAvailableStringConverter()); // These converters need to take priority
_jsonOptions.Converters.Add(new JsonOmdbNotAvailableInt32Converter()); _jsonOptions.Converters.Insert(0, new JsonOmdbNotAvailableStringConverter());
_jsonOptions.Converters.Insert(0, new JsonOmdbNotAvailableInt32Converter());
} }
/// <summary>Fetches data from OMDB service.</summary> /// <summary>Fetches data from OMDB service.</summary>
@ -64,8 +67,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb
var result = await GetRootObject(imdbId, cancellationToken).ConfigureAwait(false); var result = await GetRootObject(imdbId, cancellationToken).ConfigureAwait(false);
var isEnglishRequested = IsConfiguredForEnglish(item, language);
// Only take the name and rating if the user's language is set to English, since Omdb has no localization // Only take the name and rating if the user's language is set to English, since Omdb has no localization
if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase) || _configurationManager.Configuration.EnableNewOmdbSupport) if (isEnglishRequested)
{ {
item.Name = result.Title; item.Name = result.Title;
@ -75,9 +79,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
} }
} }
if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 if (TryParseYear(result.Year, out var year))
&& int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year)
&& year >= 0)
{ {
item.ProductionYear = year; item.ProductionYear = year;
} }
@ -113,7 +115,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
item.SetProviderId(MetadataProvider.Imdb, result.imdbID); item.SetProviderId(MetadataProvider.Imdb, result.imdbID);
} }
ParseAdditionalMetadata(itemResult, result); ParseAdditionalMetadata(itemResult, result, isEnglishRequested);
} }
/// <summary>Gets data about an episode.</summary> /// <summary>Gets data about an episode.</summary>
@ -176,8 +178,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb
return false; return false;
} }
var isEnglishRequested = IsConfiguredForEnglish(item, language);
// Only take the name and rating if the user's language is set to English, since Omdb has no localization // Only take the name and rating if the user's language is set to English, since Omdb has no localization
if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase) || _configurationManager.Configuration.EnableNewOmdbSupport) if (isEnglishRequested)
{ {
item.Name = result.Title; item.Name = result.Title;
@ -187,9 +190,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
} }
} }
if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 if (TryParseYear(result.Year, out var year))
&& int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year)
&& year >= 0)
{ {
item.ProductionYear = year; item.ProductionYear = year;
} }
@ -225,7 +226,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
item.SetProviderId(MetadataProvider.Imdb, result.imdbID); item.SetProviderId(MetadataProvider.Imdb, result.imdbID);
} }
ParseAdditionalMetadata(itemResult, result); ParseAdditionalMetadata(itemResult, result, isEnglishRequested);
return true; return true;
} }
@ -259,6 +260,30 @@ namespace MediaBrowser.Providers.Plugins.Omdb
return Url + "&" + query; return Url + "&" + query;
} }
/// <summary>
/// Extract the year from a string.
/// </summary>
/// <param name="input">The input string.</param>
/// <param name="year">The year.</param>
/// <returns>A value indicating whether the input could successfully be parsed as a year.</returns>
public static bool TryParseYear(string input, [NotNullWhen(true)] out int? year)
{
if (string.IsNullOrEmpty(input))
{
year = 0;
return false;
}
if (int.TryParse(input.AsSpan(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var result))
{
year = result;
return true;
}
year = 0;
return false;
}
private async Task<string> EnsureItemInfo(string imdbId, CancellationToken cancellationToken) private async Task<string> EnsureItemInfo(string imdbId, CancellationToken cancellationToken)
{ {
if (string.IsNullOrWhiteSpace(imdbId)) if (string.IsNullOrWhiteSpace(imdbId))
@ -291,7 +316,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
"i={0}&plot=short&tomatoes=true&r=json", "i={0}&plot=short&tomatoes=true&r=json",
imdbParam)); imdbParam));
var rootObject = await GetDeserializedOmdbResponse<RootObject>(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); var rootObject = await _httpClientFactory.CreateClient(NamedClient.Default).GetFromJsonAsync<RootObject>(url, _jsonOptions, cancellationToken).ConfigureAwait(false);
await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false);
@ -331,37 +356,13 @@ namespace MediaBrowser.Providers.Plugins.Omdb
imdbParam, imdbParam,
seasonId)); seasonId));
var rootObject = await GetDeserializedOmdbResponse<SeasonRootObject>(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); var rootObject = await _httpClientFactory.CreateClient(NamedClient.Default).GetFromJsonAsync<SeasonRootObject>(url, _jsonOptions, cancellationToken).ConfigureAwait(false);
await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false);
return path; return path;
} }
/// <summary>Gets response from OMDB service as type T.</summary>
/// <param name="httpClient">HttpClient instance to use for service call.</param>
/// <param name="url">Http URL to use for service call.</param>
/// <param name="cancellationToken">CancellationToken to use for service call.</param>
/// <typeparam name="T">The first generic type parameter.</typeparam>
/// <returns>OMDB service response as type T.</returns>
public async Task<T> GetDeserializedOmdbResponse<T>(HttpClient httpClient, string url, CancellationToken cancellationToken)
{
using var response = await GetOmdbResponse(httpClient, url, cancellationToken).ConfigureAwait(false);
await using Stream content = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
return await JsonSerializer.DeserializeAsync<T>(content, _jsonOptions, cancellationToken).ConfigureAwait(false);
}
/// <summary>Gets response from OMDB service.</summary>
/// <param name="httpClient">HttpClient instance to use for service call.</param>
/// <param name="url">Http URL to use for service call.</param>
/// <param name="cancellationToken">CancellationToken to use for service call.</param>
/// <returns>OMDB service response as HttpResponseMessage.</returns>
public static Task<HttpResponseMessage> GetOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken)
{
return httpClient.GetAsync(url, cancellationToken);
}
internal string GetDataFilePath(string imdbId) internal string GetDataFilePath(string imdbId)
{ {
if (string.IsNullOrEmpty(imdbId)) if (string.IsNullOrEmpty(imdbId))
@ -390,31 +391,25 @@ namespace MediaBrowser.Providers.Plugins.Omdb
return Path.Combine(dataPath, filename); return Path.Combine(dataPath, filename);
} }
private void ParseAdditionalMetadata<T>(MetadataResult<T> itemResult, RootObject result) private static void ParseAdditionalMetadata<T>(MetadataResult<T> itemResult, RootObject result, bool isEnglishRequested)
where T : BaseItem where T : BaseItem
{ {
var item = itemResult.Item; var item = itemResult.Item;
var isConfiguredForEnglish = IsConfiguredForEnglish(item) || _configurationManager.Configuration.EnableNewOmdbSupport;
// Grab series genres because IMDb data is better than TVDB. Leave movies alone // Grab series genres because IMDb data is better than TVDB. Leave movies alone
// But only do it if English is the preferred language because this data will not be localized // But only do it if English is the preferred language because this data will not be localized
if (isConfiguredForEnglish && !string.IsNullOrWhiteSpace(result.Genre)) if (isEnglishRequested && !string.IsNullOrWhiteSpace(result.Genre))
{ {
item.Genres = Array.Empty<string>(); item.Genres = Array.Empty<string>();
foreach (var genre in result.Genre foreach (var genre in result.Genre.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i)))
{ {
item.AddGenre(genre); item.AddGenre(genre);
} }
} }
if (isConfiguredForEnglish) if (isEnglishRequested)
{ {
// Omdb is currently English only, so for other languages skip this and let secondary providers fill it in
item.Overview = result.Plot; item.Overview = result.Plot;
} }
@ -427,7 +422,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{ {
var person = new PersonInfo var person = new PersonInfo
{ {
Name = result.Director.Trim(), Name = result.Director,
Type = PersonType.Director Type = PersonType.Director
}; };
@ -438,7 +433,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{ {
var person = new PersonInfo var person = new PersonInfo
{ {
Name = result.Writer.Trim(), Name = result.Writer,
Type = PersonType.Writer Type = PersonType.Writer
}; };
@ -447,29 +442,34 @@ namespace MediaBrowser.Providers.Plugins.Omdb
if (!string.IsNullOrWhiteSpace(result.Actors)) if (!string.IsNullOrWhiteSpace(result.Actors))
{ {
var actorList = result.Actors.Split(','); var actorList = result.Actors.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var actor in actorList) foreach (var actor in actorList)
{ {
if (!string.IsNullOrWhiteSpace(actor)) if (string.IsNullOrWhiteSpace(actor))
{ {
var person = new PersonInfo continue;
{
Name = actor.Trim(),
Type = PersonType.Actor
};
itemResult.AddPerson(person);
} }
var person = new PersonInfo
{
Name = actor,
Type = PersonType.Actor
};
itemResult.AddPerson(person);
} }
} }
} }
private bool IsConfiguredForEnglish(BaseItem item) private static bool IsConfiguredForEnglish(BaseItem item, string language)
{ {
var lang = item.GetPreferredMetadataLanguage(); if (string.IsNullOrEmpty(language))
{
language = item.GetPreferredMetadataLanguage();
}
// The data isn't localized and so can only be used for English users // The data isn't localized and so can only be used for English users
return string.Equals(lang, "en", StringComparison.OrdinalIgnoreCase); return string.Equals(language, "en", StringComparison.OrdinalIgnoreCase);
} }
internal class SeasonRootObject internal class SeasonRootObject
@ -546,7 +546,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
if (Ratings != null) if (Ratings != null)
{ {
var rating = Ratings.FirstOrDefault(i => string.Equals(i.Source, "Rotten Tomatoes", StringComparison.OrdinalIgnoreCase)); var rating = Ratings.FirstOrDefault(i => string.Equals(i.Source, "Rotten Tomatoes", StringComparison.OrdinalIgnoreCase));
if (rating != null && rating.Value != null) if (rating?.Value != null)
{ {
var value = rating.Value.TrimEnd('%'); var value = rating.Value.TrimEnd('%');
if (float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var score)) if (float.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var score))

Loading…
Cancel
Save