Merge pull request #2549 from dkanada/refactor

Refactor some provider classes
This commit is contained in:
dkanada
2020-03-18 17:43:15 +09:00
committed by GitHub
55 changed files with 146 additions and 205 deletions

View File

@@ -12,7 +12,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Providers.TV.TheTVDB;
using MediaBrowser.Providers.Plugins.TheTvdb;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.TV
@@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.TV
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
private readonly IFileSystem _fileSystem;
private readonly TvDbClientManager _tvDbClientManager;
private readonly TvdbClientManager _tvdbClientManager;
public MissingEpisodeProvider(
ILogger logger,
@@ -34,14 +34,14 @@ namespace MediaBrowser.Providers.TV
ILibraryManager libraryManager,
ILocalizationManager localization,
IFileSystem fileSystem,
TvDbClientManager tvDbClientManager)
TvdbClientManager tvdbClientManager)
{
_logger = logger;
_config = config;
_libraryManager = libraryManager;
_localization = localization;
_fileSystem = fileSystem;
_tvDbClientManager = tvDbClientManager;
_tvdbClientManager = tvdbClientManager;
}
public async Task<bool> Run(Series series, bool addNewItems, CancellationToken cancellationToken)
@@ -52,7 +52,7 @@ namespace MediaBrowser.Providers.TV
return false;
}
var episodes = await _tvDbClientManager.GetAllEpisodesAsync(Convert.ToInt32(tvdbId), series.GetPreferredMetadataLanguage(), cancellationToken);
var episodes = await _tvdbClientManager.GetAllEpisodesAsync(Convert.ToInt32(tvdbId), series.GetPreferredMetadataLanguage(), cancellationToken);
var episodeLookup = episodes
.Select(i =>

View File

@@ -1,80 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Omdb;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.TV.Omdb
{
public class OmdbEpisodeProvider :
IRemoteMetadataProvider<Episode, EpisodeInfo>,
IHasOrder
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
private readonly OmdbItemProvider _itemProvider;
private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _configurationManager;
private readonly IApplicationHost _appHost;
public OmdbEpisodeProvider(IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager)
{
_jsonSerializer = jsonSerializer;
_httpClient = httpClient;
_fileSystem = fileSystem;
_configurationManager = configurationManager;
_appHost = appHost;
_itemProvider = new OmdbItemProvider(jsonSerializer, _appHost, httpClient, logger, libraryManager, fileSystem, configurationManager);
}
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
return _itemProvider.GetSearchResults(searchInfo, "episode", cancellationToken);
}
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<Episode>()
{
Item = new Episode(),
QueriedById = true
};
// Allowing this will dramatically increase scan times
if (info.IsMissingEpisode)
{
return result;
}
if (info.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out string seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId))
{
if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue)
{
result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager)
.FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProviders.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
}
}
return result;
}
// After TheTvDb
public int Order => 1;
public string Name => "The Open Movie Database";
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _itemProvider.GetImageResponse(url, cancellationToken);
}
}
}

View File

@@ -9,7 +9,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.TV.TheTVDB;
using MediaBrowser.Providers.Plugins.TheTvdb;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.TV
@@ -17,7 +17,7 @@ namespace MediaBrowser.Providers.TV
public class SeriesMetadataService : MetadataService<Series, SeriesInfo>
{
private readonly ILocalizationManager _localization;
private readonly TvDbClientManager _tvDbClientManager;
private readonly TvdbClientManager _tvdbClientManager;
public SeriesMetadataService(
IServerConfigurationManager serverConfigurationManager,
@@ -26,11 +26,11 @@ namespace MediaBrowser.Providers.TV
IFileSystem fileSystem,
ILibraryManager libraryManager,
ILocalizationManager localization,
TvDbClientManager tvDbClientManager)
TvdbClientManager tvdbClientManager)
: base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager)
{
_localization = localization;
_tvDbClientManager = tvDbClientManager;
_tvdbClientManager = tvdbClientManager;
}
/// <inheritdoc />
@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.TV
LibraryManager,
_localization,
FileSystem,
_tvDbClientManager);
_tvdbClientManager);
try
{

View File

@@ -1,284 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Caching.Memory;
using TvDbSharper;
using TvDbSharper.Dto;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvDbClientManager
{
private const string DefaultLanguage = "en";
private readonly SemaphoreSlim _cacheWriteLock = new SemaphoreSlim(1, 1);
private readonly IMemoryCache _cache;
private readonly TvDbClient _tvDbClient;
private DateTime _tokenCreatedAt;
public TvDbClientManager(IMemoryCache memoryCache)
{
_cache = memoryCache;
_tvDbClient = new TvDbClient();
}
private TvDbClient TvDbClient
{
get
{
if (string.IsNullOrEmpty(_tvDbClient.Authentication.Token))
{
_tvDbClient.Authentication.AuthenticateAsync(TvdbUtils.TvdbApiKey).GetAwaiter().GetResult();
_tokenCreatedAt = DateTime.Now;
}
// Refresh if necessary
if (_tokenCreatedAt < DateTime.Now.Subtract(TimeSpan.FromHours(20)))
{
try
{
_tvDbClient.Authentication.RefreshTokenAsync().GetAwaiter().GetResult();
}
catch
{
_tvDbClient.Authentication.AuthenticateAsync(TvdbUtils.TvdbApiKey).GetAwaiter().GetResult();
}
_tokenCreatedAt = DateTime.Now;
}
return _tvDbClient;
}
}
public Task<TvDbResponse<SeriesSearchResult[]>> GetSeriesByNameAsync(string name, string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("series", name, language);
return TryGetValue(cacheKey, language,() => TvDbClient.Search.SearchSeriesByNameAsync(name, cancellationToken));
}
public Task<TvDbResponse<Series>> GetSeriesByIdAsync(int tvdbId, string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("series", tvdbId, language);
return TryGetValue(cacheKey, language,() => TvDbClient.Series.GetAsync(tvdbId, cancellationToken));
}
public Task<TvDbResponse<EpisodeRecord>> GetEpisodesAsync(int episodeTvdbId, string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("episode", episodeTvdbId, language);
return TryGetValue(cacheKey, language,() => TvDbClient.Episodes.GetAsync(episodeTvdbId, cancellationToken));
}
public async Task<List<EpisodeRecord>> GetAllEpisodesAsync(int tvdbId, string language,
CancellationToken cancellationToken)
{
// Traverse all episode pages and join them together
var episodes = new List<EpisodeRecord>();
var episodePage = await GetEpisodesPageAsync(tvdbId, new EpisodeQuery(), language, cancellationToken)
.ConfigureAwait(false);
episodes.AddRange(episodePage.Data);
if (!episodePage.Links.Next.HasValue || !episodePage.Links.Last.HasValue)
{
return episodes;
}
int next = episodePage.Links.Next.Value;
int last = episodePage.Links.Last.Value;
for (var page = next; page <= last; ++page)
{
episodePage = await GetEpisodesPageAsync(tvdbId, page, new EpisodeQuery(), language, cancellationToken)
.ConfigureAwait(false);
episodes.AddRange(episodePage.Data);
}
return episodes;
}
public Task<TvDbResponse<SeriesSearchResult[]>> GetSeriesByImdbIdAsync(
string imdbId,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("series", imdbId, language);
return TryGetValue(cacheKey, language,() => TvDbClient.Search.SearchSeriesByImdbIdAsync(imdbId, cancellationToken));
}
public Task<TvDbResponse<SeriesSearchResult[]>> GetSeriesByZap2ItIdAsync(
string zap2ItId,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("series", zap2ItId, language);
return TryGetValue(cacheKey, language, () => TvDbClient.Search.SearchSeriesByZap2ItIdAsync(zap2ItId, cancellationToken));
}
public Task<TvDbResponse<Actor[]>> GetActorsAsync(
int tvdbId,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("actors", tvdbId, language);
return TryGetValue(cacheKey, language, () => TvDbClient.Series.GetActorsAsync(tvdbId, cancellationToken));
}
public Task<TvDbResponse<Image[]>> GetImagesAsync(
int tvdbId,
ImagesQuery imageQuery,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("images", tvdbId, language, imageQuery);
return TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesAsync(tvdbId, imageQuery, cancellationToken));
}
public Task<TvDbResponse<Language[]>> GetLanguagesAsync(CancellationToken cancellationToken)
{
return TryGetValue("languages", null, () => TvDbClient.Languages.GetAllAsync(cancellationToken));
}
public Task<TvDbResponse<EpisodesSummary>> GetSeriesEpisodeSummaryAsync(
int tvdbId,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey("seriesepisodesummary", tvdbId, language);
return TryGetValue(cacheKey, language,
() => TvDbClient.Series.GetEpisodesSummaryAsync(tvdbId, cancellationToken));
}
public Task<TvDbResponse<EpisodeRecord[]>> GetEpisodesPageAsync(
int tvdbId,
int page,
EpisodeQuery episodeQuery,
string language,
CancellationToken cancellationToken)
{
var cacheKey = GenerateKey(language, tvdbId, episodeQuery);
return TryGetValue(cacheKey, language,
() => TvDbClient.Series.GetEpisodesAsync(tvdbId, page, episodeQuery, cancellationToken));
}
public Task<string> GetEpisodeTvdbId(
EpisodeInfo searchInfo,
string language,
CancellationToken cancellationToken)
{
searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(),
out var seriesTvdbId);
var episodeQuery = new EpisodeQuery();
// Prefer SxE over premiere date as it is more robust
if (searchInfo.IndexNumber.HasValue && searchInfo.ParentIndexNumber.HasValue)
{
switch (searchInfo.SeriesDisplayOrder)
{
case "dvd":
episodeQuery.DvdEpisode = searchInfo.IndexNumber.Value;
episodeQuery.DvdSeason = searchInfo.ParentIndexNumber.Value;
break;
case "absolute":
episodeQuery.AbsoluteNumber = searchInfo.IndexNumber.Value;
break;
default:
//aired order
episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
break;
}
}
else if (searchInfo.PremiereDate.HasValue)
{
// tvdb expects yyyy-mm-dd format
episodeQuery.FirstAired = searchInfo.PremiereDate.Value.ToString("yyyy-MM-dd");
}
return GetEpisodeTvdbId(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken);
}
public async Task<string> GetEpisodeTvdbId(
int seriesTvdbId,
EpisodeQuery episodeQuery,
string language,
CancellationToken cancellationToken)
{
var episodePage =
await GetEpisodesPageAsync(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken)
.ConfigureAwait(false);
return episodePage.Data.FirstOrDefault()?.Id.ToString();
}
public Task<TvDbResponse<EpisodeRecord[]>> GetEpisodesPageAsync(
int tvdbId,
EpisodeQuery episodeQuery,
string language,
CancellationToken cancellationToken)
{
return GetEpisodesPageAsync(tvdbId, 1, episodeQuery, language, cancellationToken);
}
private async Task<T> TryGetValue<T>(string key, string language, Func<Task<T>> resultFactory)
{
if (_cache.TryGetValue(key, out T cachedValue))
{
return cachedValue;
}
await _cacheWriteLock.WaitAsync().ConfigureAwait(false);
try
{
if (_cache.TryGetValue(key, out cachedValue))
{
return cachedValue;
}
_tvDbClient.AcceptedLanguage = TvdbUtils.NormalizeLanguage(language) ?? DefaultLanguage;
var result = await resultFactory.Invoke().ConfigureAwait(false);
_cache.Set(key, result, TimeSpan.FromHours(1));
return result;
}
finally
{
_cacheWriteLock.Release();
}
}
private static string GenerateKey(params object[] objects)
{
var key = string.Empty;
foreach (var obj in objects)
{
var objType = obj.GetType();
if (objType.IsPrimitive || objType == typeof(string))
{
key += obj + ";";
}
else
{
foreach (PropertyInfo propertyInfo in objType.GetProperties())
{
var currentValue = propertyInfo.GetValue(obj, null);
if (currentValue == null)
{
continue;
}
key += propertyInfo.Name + "=" + currentValue + ";";
}
}
}
return key;
}
}
}

View File

@@ -1,123 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbEpisodeImageProvider : IRemoteImageProvider
{
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly TvDbClientManager _tvDbClientManager;
public TvdbEpisodeImageProvider(IHttpClient httpClient, ILogger<TvdbEpisodeImageProvider> logger, TvDbClientManager tvDbClientManager)
{
_httpClient = httpClient;
_logger = logger;
_tvDbClientManager = tvDbClientManager;
}
public string Name => "TheTVDB";
public bool Supports(BaseItem item)
{
return item is Episode;
}
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
{
return new List<ImageType>
{
ImageType.Primary
};
}
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{
var episode = (Episode)item;
var series = episode.Series;
var imageResult = new List<RemoteImageInfo>();
var language = item.GetPreferredMetadataLanguage();
if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
{
// Process images
try
{
var episodeInfo = new EpisodeInfo
{
IndexNumber = episode.IndexNumber.Value,
ParentIndexNumber = episode.ParentIndexNumber.Value,
SeriesProviderIds = series.ProviderIds,
SeriesDisplayOrder = series.DisplayOrder
};
string episodeTvdbId = await _tvDbClientManager
.GetEpisodeTvdbId(episodeInfo, language, cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(episodeTvdbId))
{
_logger.LogError(
"Episode {SeasonNumber}x{EpisodeNumber} not found for series {SeriesTvdbId}",
episodeInfo.ParentIndexNumber,
episodeInfo.IndexNumber,
series.GetProviderId(MetadataProviders.Tvdb));
return imageResult;
}
var episodeResult =
await _tvDbClientManager
.GetEpisodesAsync(Convert.ToInt32(episodeTvdbId), language, cancellationToken)
.ConfigureAwait(false);
var image = GetImageInfo(episodeResult.Data);
if (image != null)
{
imageResult.Add(image);
}
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}", series.GetProviderId(MetadataProviders.Tvdb));
}
}
return imageResult;
}
private RemoteImageInfo GetImageInfo(EpisodeRecord episode)
{
if (string.IsNullOrEmpty(episode.Filename))
{
return null;
}
return new RemoteImageInfo
{
Width = Convert.ToInt32(episode.ThumbWidth),
Height = Convert.ToInt32(episode.ThumbHeight),
ProviderName = Name,
Url = TvdbUtils.BannerUrl + episode.Filename,
Type = ImageType.Primary
};
}
public int Order => 0;
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url
});
}
}
}

View File

@@ -1,256 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
namespace MediaBrowser.Providers.TV.TheTVDB
{
/// <summary>
/// Class RemoteEpisodeProvider
/// </summary>
public class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
{
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly TvDbClientManager _tvDbClientManager;
public TvdbEpisodeProvider(IHttpClient httpClient, ILogger<TvdbEpisodeProvider> logger, TvDbClientManager tvDbClientManager)
{
_httpClient = httpClient;
_logger = logger;
_tvDbClientManager = tvDbClientManager;
}
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
var list = new List<RemoteSearchResult>();
// Either an episode number or date must be provided; and the dictionary of provider ids must be valid
if ((searchInfo.IndexNumber == null && searchInfo.PremiereDate == null)
|| !TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds))
{
return list;
}
var metadataResult = await GetEpisode(searchInfo, cancellationToken).ConfigureAwait(false);
if (!metadataResult.HasMetadata)
{
return list;
}
var item = metadataResult.Item;
list.Add(new RemoteSearchResult
{
IndexNumber = item.IndexNumber,
Name = item.Name,
ParentIndexNumber = item.ParentIndexNumber,
PremiereDate = item.PremiereDate,
ProductionYear = item.ProductionYear,
ProviderIds = item.ProviderIds,
SearchProviderName = Name,
IndexNumberEnd = item.IndexNumberEnd
});
return list;
}
public string Name => "TheTVDB";
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
var result = new MetadataResult<Episode>
{
QueriedById = true
};
if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) &&
(searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
{
result = await GetEpisode(searchInfo, cancellationToken).ConfigureAwait(false);
}
else
{
_logger.LogDebug("No series identity found for {EpisodeName}", searchInfo.Name);
}
return result;
}
private async Task<MetadataResult<Episode>> GetEpisode(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
var result = new MetadataResult<Episode>
{
QueriedById = true
};
string seriesTvdbId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
string episodeTvdbId = null;
try
{
episodeTvdbId = await _tvDbClientManager
.GetEpisodeTvdbId(searchInfo, searchInfo.MetadataLanguage, cancellationToken)
.ConfigureAwait(false);
if (string.IsNullOrEmpty(episodeTvdbId))
{
_logger.LogError("Episode {SeasonNumber}x{EpisodeNumber} not found for series {SeriesTvdbId}",
searchInfo.ParentIndexNumber, searchInfo.IndexNumber, seriesTvdbId);
return result;
}
var episodeResult = await _tvDbClientManager.GetEpisodesAsync(
Convert.ToInt32(episodeTvdbId), searchInfo.MetadataLanguage,
cancellationToken).ConfigureAwait(false);
result = MapEpisodeToResult(searchInfo, episodeResult.Data);
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to retrieve episode with id {EpisodeTvDbId}, series id {SeriesTvdbId}", episodeTvdbId, seriesTvdbId);
}
return result;
}
private static MetadataResult<Episode> MapEpisodeToResult(EpisodeInfo id, EpisodeRecord episode)
{
var result = new MetadataResult<Episode>
{
HasMetadata = true,
Item = new Episode
{
IndexNumber = id.IndexNumber,
ParentIndexNumber = id.ParentIndexNumber,
IndexNumberEnd = id.IndexNumberEnd,
AirsBeforeEpisodeNumber = episode.AirsBeforeEpisode,
AirsAfterSeasonNumber = episode.AirsAfterSeason,
AirsBeforeSeasonNumber = episode.AirsBeforeSeason,
Name = episode.EpisodeName,
Overview = episode.Overview,
CommunityRating = (float?)episode.SiteRating,
}
};
result.ResetPeople();
var item = result.Item;
item.SetProviderId(MetadataProviders.Tvdb, episode.Id.ToString());
item.SetProviderId(MetadataProviders.Imdb, episode.ImdbId);
if (string.Equals(id.SeriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase))
{
item.IndexNumber = Convert.ToInt32(episode.DvdEpisodeNumber ?? episode.AiredEpisodeNumber);
item.ParentIndexNumber = episode.DvdSeason ?? episode.AiredSeason;
}
else if (episode.AiredEpisodeNumber.HasValue)
{
item.IndexNumber = episode.AiredEpisodeNumber;
}
else if (episode.AiredSeason.HasValue)
{
item.ParentIndexNumber = episode.AiredSeason;
}
if (DateTime.TryParse(episode.FirstAired, out var date))
{
// dates from tvdb are UTC but without offset or Z
item.PremiereDate = date;
item.ProductionYear = date.Year;
}
foreach (var director in episode.Directors)
{
result.AddPerson(new PersonInfo
{
Name = director,
Type = PersonType.Director
});
}
// GuestStars is a weird list of names and roles
// Example:
// 1: Some Actor (Role1
// 2: Role2
// 3: Role3)
// 4: Another Actor (Role1
// ...
for (var i = 0; i < episode.GuestStars.Length; ++i)
{
var currentActor = episode.GuestStars[i];
var roleStartIndex = currentActor.IndexOf('(');
if (roleStartIndex == -1)
{
result.AddPerson(new PersonInfo
{
Type = PersonType.GuestStar,
Name = currentActor,
Role = string.Empty
});
continue;
}
var roles = new List<string> {currentActor.Substring(roleStartIndex + 1)};
// Fetch all roles
for (var j = i + 1; j < episode.GuestStars.Length; ++j)
{
var currentRole = episode.GuestStars[j];
var roleEndIndex = currentRole.IndexOf(')');
if (roleEndIndex == -1)
{
roles.Add(currentRole);
continue;
}
roles.Add(currentRole.TrimEnd(')'));
// Update the outer index (keep in mind it adds 1 after the iteration)
i = j;
break;
}
result.AddPerson(new PersonInfo
{
Type = PersonType.GuestStar,
Name = currentActor.Substring(0, roleStartIndex).Trim(),
Role = string.Join(", ", roles)
});
}
foreach (var writer in episode.Writers)
{
result.AddPerson(new PersonInfo
{
Name = writer,
Type = PersonType.Writer
});
}
result.ResultLanguage = episode.Language.EpisodeName;
return result;
}
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url
});
}
public int Order => 0;
}
}

View File

@@ -1,155 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
using RatingType = MediaBrowser.Model.Dto.RatingType;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly TvDbClientManager _tvDbClientManager;
public TvdbSeasonImageProvider(IHttpClient httpClient, ILogger<TvdbSeasonImageProvider> logger, TvDbClientManager tvDbClientManager)
{
_httpClient = httpClient;
_logger = logger;
_tvDbClientManager = tvDbClientManager;
}
public string Name => ProviderName;
public static string ProviderName => "TheTVDB";
public bool Supports(BaseItem item)
{
return item is Season;
}
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
{
return new List<ImageType>
{
ImageType.Primary,
ImageType.Banner,
ImageType.Backdrop
};
}
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{
var season = (Season)item;
var series = season.Series;
if (series == null || !season.IndexNumber.HasValue || !TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
{
return new RemoteImageInfo[] { };
}
var tvdbId = Convert.ToInt32(series.GetProviderId(MetadataProviders.Tvdb));
var seasonNumber = season.IndexNumber.Value;
var language = item.GetPreferredMetadataLanguage();
var remoteImages = new List<RemoteImageInfo>();
var keyTypes = new[] { KeyType.Season, KeyType.Seasonwide, KeyType.Fanart };
foreach (var keyType in keyTypes)
{
var imageQuery = new ImagesQuery
{
KeyType = keyType,
SubKey = seasonNumber.ToString()
};
try
{
var imageResults = await _tvDbClientManager
.GetImagesAsync(tvdbId, imageQuery, language, cancellationToken).ConfigureAwait(false);
remoteImages.AddRange(GetImages(imageResults.Data, language));
}
catch (TvDbServerException)
{
_logger.LogDebug("No images of type {KeyType} found for series {TvdbId}", keyType, tvdbId);
}
}
return remoteImages;
}
private IEnumerable<RemoteImageInfo> GetImages(Image[] images, string preferredLanguage)
{
var list = new List<RemoteImageInfo>();
var languages = _tvDbClientManager.GetLanguagesAsync(CancellationToken.None).Result.Data;
foreach (Image image in images)
{
var imageInfo = new RemoteImageInfo
{
RatingType = RatingType.Score,
CommunityRating = (double?)image.RatingsInfo.Average,
VoteCount = image.RatingsInfo.Count,
Url = TvdbUtils.BannerUrl + image.FileName,
ProviderName = ProviderName,
Language = languages.FirstOrDefault(lang => lang.Id == image.LanguageId)?.Abbreviation,
ThumbnailUrl = TvdbUtils.BannerUrl + image.Thumbnail
};
var resolution = image.Resolution.Split('x');
if (resolution.Length == 2)
{
imageInfo.Width = Convert.ToInt32(resolution[0]);
imageInfo.Height = Convert.ToInt32(resolution[1]);
}
imageInfo.Type = TvdbUtils.GetImageTypeFromKeyType(image.KeyType);
list.Add(imageInfo);
}
var isLanguageEn = string.Equals(preferredLanguage, "en", StringComparison.OrdinalIgnoreCase);
return list.OrderByDescending(i =>
{
if (string.Equals(preferredLanguage, i.Language, StringComparison.OrdinalIgnoreCase))
{
return 3;
}
if (!isLanguageEn)
{
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
{
return 2;
}
}
if (string.IsNullOrEmpty(i.Language))
{
return isLanguageEn ? 3 : 2;
}
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
.ThenByDescending(i => i.VoteCount ?? 0);
}
public int Order => 0;
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url
});
}
}
}

View File

@@ -1,152 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
using RatingType = MediaBrowser.Model.Dto.RatingType;
using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder
{
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly TvDbClientManager _tvDbClientManager;
public TvdbSeriesImageProvider(IHttpClient httpClient, ILogger<TvdbSeriesImageProvider> logger, TvDbClientManager tvDbClientManager)
{
_httpClient = httpClient;
_logger = logger;
_tvDbClientManager = tvDbClientManager;
}
public string Name => ProviderName;
public static string ProviderName => "TheTVDB";
public bool Supports(BaseItem item)
{
return item is Series;
}
public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
{
return new List<ImageType>
{
ImageType.Primary,
ImageType.Banner,
ImageType.Backdrop
};
}
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
{
if (!TvdbSeriesProvider.IsValidSeries(item.ProviderIds))
{
return Array.Empty<RemoteImageInfo>();
}
var language = item.GetPreferredMetadataLanguage();
var remoteImages = new List<RemoteImageInfo>();
var keyTypes = new[] { KeyType.Poster, KeyType.Series, KeyType.Fanart };
var tvdbId = Convert.ToInt32(item.GetProviderId(MetadataProviders.Tvdb));
foreach (KeyType keyType in keyTypes)
{
var imageQuery = new ImagesQuery
{
KeyType = keyType
};
try
{
var imageResults =
await _tvDbClientManager.GetImagesAsync(tvdbId, imageQuery, language, cancellationToken)
.ConfigureAwait(false);
remoteImages.AddRange(GetImages(imageResults.Data, language));
}
catch (TvDbServerException)
{
_logger.LogDebug("No images of type {KeyType} exist for series {TvDbId}", keyType,
tvdbId);
}
}
return remoteImages;
}
private IEnumerable<RemoteImageInfo> GetImages(Image[] images, string preferredLanguage)
{
var list = new List<RemoteImageInfo>();
var languages = _tvDbClientManager.GetLanguagesAsync(CancellationToken.None).Result.Data;
foreach (Image image in images)
{
var imageInfo = new RemoteImageInfo
{
RatingType = RatingType.Score,
CommunityRating = (double?)image.RatingsInfo.Average,
VoteCount = image.RatingsInfo.Count,
Url = TvdbUtils.BannerUrl + image.FileName,
ProviderName = Name,
Language = languages.FirstOrDefault(lang => lang.Id == image.LanguageId)?.Abbreviation,
ThumbnailUrl = TvdbUtils.BannerUrl + image.Thumbnail
};
var resolution = image.Resolution.Split('x');
if (resolution.Length == 2)
{
imageInfo.Width = Convert.ToInt32(resolution[0]);
imageInfo.Height = Convert.ToInt32(resolution[1]);
}
imageInfo.Type = TvdbUtils.GetImageTypeFromKeyType(image.KeyType);
list.Add(imageInfo);
}
var isLanguageEn = string.Equals(preferredLanguage, "en", StringComparison.OrdinalIgnoreCase);
return list.OrderByDescending(i =>
{
if (string.Equals(preferredLanguage, i.Language, StringComparison.OrdinalIgnoreCase))
{
return 3;
}
if (!isLanguageEn)
{
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
{
return 2;
}
}
if (string.IsNullOrEmpty(i.Language))
{
return isLanguageEn ? 3 : 2;
}
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
.ThenByDescending(i => i.VoteCount ?? 0);
}
public int Order => 0;
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url
});
}
}
}

View File

@@ -1,437 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
internal static TvdbSeriesProvider Current { get; private set; }
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localizationManager;
private readonly TvDbClientManager _tvDbClientManager;
public TvdbSeriesProvider(IHttpClient httpClient, ILogger<TvdbSeriesProvider> logger, ILibraryManager libraryManager, ILocalizationManager localizationManager, TvDbClientManager tvDbClientManager)
{
_httpClient = httpClient;
_logger = logger;
_libraryManager = libraryManager;
_localizationManager = localizationManager;
Current = this;
_tvDbClientManager = tvDbClientManager;
}
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
{
if (IsValidSeries(searchInfo.ProviderIds))
{
var metadata = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
if (metadata.HasMetadata)
{
return new List<RemoteSearchResult>
{
new RemoteSearchResult
{
Name = metadata.Item.Name,
PremiereDate = metadata.Item.PremiereDate,
ProductionYear = metadata.Item.ProductionYear,
ProviderIds = metadata.Item.ProviderIds,
SearchProviderName = Name
}
};
}
}
return await FindSeries(searchInfo.Name, searchInfo.Year, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
}
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken)
{
var result = new MetadataResult<Series>
{
QueriedById = true
};
if (!IsValidSeries(itemId.ProviderIds))
{
result.QueriedById = false;
await Identify(itemId).ConfigureAwait(false);
}
cancellationToken.ThrowIfCancellationRequested();
if (IsValidSeries(itemId.ProviderIds))
{
result.Item = new Series();
result.HasMetadata = true;
await FetchSeriesData(result, itemId.MetadataLanguage, itemId.ProviderIds, cancellationToken)
.ConfigureAwait(false);
}
return result;
}
private async Task FetchSeriesData(MetadataResult<Series> result, string metadataLanguage, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
{
var series = result.Item;
if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(tvdbId))
{
series.SetProviderId(MetadataProviders.Tvdb, tvdbId);
}
if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out var imdbId) && !string.IsNullOrEmpty(imdbId))
{
series.SetProviderId(MetadataProviders.Imdb, imdbId);
tvdbId = await GetSeriesByRemoteId(imdbId, MetadataProviders.Imdb.ToString(), metadataLanguage,
cancellationToken).ConfigureAwait(false);
}
if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out var zap2It) && !string.IsNullOrEmpty(zap2It))
{
series.SetProviderId(MetadataProviders.Zap2It, zap2It);
tvdbId = await GetSeriesByRemoteId(zap2It, MetadataProviders.Zap2It.ToString(), metadataLanguage,
cancellationToken).ConfigureAwait(false);
}
try
{
var seriesResult =
await _tvDbClientManager
.GetSeriesByIdAsync(Convert.ToInt32(tvdbId), metadataLanguage, cancellationToken)
.ConfigureAwait(false);
MapSeriesToResult(result, seriesResult.Data, metadataLanguage);
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to retrieve series with id {TvdbId}", tvdbId);
return;
}
cancellationToken.ThrowIfCancellationRequested();
result.ResetPeople();
try
{
var actorsResult = await _tvDbClientManager
.GetActorsAsync(Convert.ToInt32(tvdbId), metadataLanguage, cancellationToken).ConfigureAwait(false);
MapActorsToResult(result, actorsResult.Data);
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to retrieve actors for series {TvdbId}", tvdbId);
}
}
private async Task<string> GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken)
{
TvDbResponse<SeriesSearchResult[]> result = null;
try
{
if (string.Equals(idType, MetadataProviders.Zap2It.ToString(), StringComparison.OrdinalIgnoreCase))
{
result = await _tvDbClientManager.GetSeriesByZap2ItIdAsync(id, language, cancellationToken)
.ConfigureAwait(false);
}
else
{
result = await _tvDbClientManager.GetSeriesByImdbIdAsync(id, language, cancellationToken)
.ConfigureAwait(false);
}
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to retrieve series with remote id {RemoteId}", id);
}
return result?.Data.First().Id.ToString();
}
/// <summary>
/// Check whether a dictionary of provider IDs includes an entry for a valid TV metadata provider.
/// </summary>
/// <param name="seriesProviderIds">The dictionary to check.</param>
/// <returns>True, if the dictionary contains a valid TV provider ID, otherwise false.</returns>
internal static bool IsValidSeries(Dictionary<string, string> seriesProviderIds)
{
return seriesProviderIds.ContainsKey(MetadataProviders.Tvdb.ToString()) ||
seriesProviderIds.ContainsKey(MetadataProviders.Imdb.ToString()) ||
seriesProviderIds.ContainsKey(MetadataProviders.Zap2It.ToString());
}
/// <summary>
/// Finds the series.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="year">The year.</param>
/// <param name="language">The language.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.String}.</returns>
private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, int? year, string language, CancellationToken cancellationToken)
{
var results = await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false);
if (results.Count == 0)
{
var parsedName = _libraryManager.ParseName(name);
var nameWithoutYear = parsedName.Name;
if (!string.IsNullOrWhiteSpace(nameWithoutYear) && !string.Equals(nameWithoutYear, name, StringComparison.OrdinalIgnoreCase))
{
results = await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false);
}
}
return results.Where(i =>
{
if (year.HasValue && i.ProductionYear.HasValue)
{
// Allow one year tolerance
return Math.Abs(year.Value - i.ProductionYear.Value) <= 1;
}
return true;
});
}
private async Task<List<RemoteSearchResult>> FindSeriesInternal(string name, string language, CancellationToken cancellationToken)
{
var comparableName = GetComparableName(name);
var list = new List<Tuple<List<string>, RemoteSearchResult>>();
TvDbResponse<SeriesSearchResult[]> result;
try
{
result = await _tvDbClientManager.GetSeriesByNameAsync(comparableName, language, cancellationToken)
.ConfigureAwait(false);
}
catch (TvDbServerException e)
{
_logger.LogError(e, "No series results found for {Name}", comparableName);
return new List<RemoteSearchResult>();
}
foreach (var seriesSearchResult in result.Data)
{
var tvdbTitles = new List<string>
{
GetComparableName(seriesSearchResult.SeriesName)
};
tvdbTitles.AddRange(seriesSearchResult.Aliases.Select(GetComparableName));
DateTime.TryParse(seriesSearchResult.FirstAired, out var firstAired);
var remoteSearchResult = new RemoteSearchResult
{
Name = tvdbTitles.FirstOrDefault(),
ProductionYear = firstAired.Year,
SearchProviderName = Name,
ImageUrl = TvdbUtils.BannerUrl + seriesSearchResult.Banner
};
try
{
var seriesSesult =
await _tvDbClientManager.GetSeriesByIdAsync(seriesSearchResult.Id, language, cancellationToken)
.ConfigureAwait(false);
remoteSearchResult.SetProviderId(MetadataProviders.Imdb, seriesSesult.Data.ImdbId);
remoteSearchResult.SetProviderId(MetadataProviders.Zap2It, seriesSesult.Data.Zap2itId);
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Unable to retrieve series with id {TvdbId}", seriesSearchResult.Id);
}
remoteSearchResult.SetProviderId(MetadataProviders.Tvdb, seriesSearchResult.Id.ToString());
list.Add(new Tuple<List<string>, RemoteSearchResult>(tvdbTitles, remoteSearchResult));
}
return list
.OrderBy(i => i.Item1.Contains(comparableName, StringComparer.OrdinalIgnoreCase) ? 0 : 1)
.ThenBy(i => list.IndexOf(i))
.Select(i => i.Item2)
.ToList();
}
/// <summary>
/// The remove
/// </summary>
const string remove = "\"'!`?";
/// <summary>
/// The spacers
/// </summary>
const string spacers = "/,.:;\\(){}[]+-_=*"; // (there are two types of dashes, short and long)
/// <summary>
/// Gets the name of the comparable.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>System.String.</returns>
private string GetComparableName(string name)
{
name = name.ToLowerInvariant();
name = name.Normalize(NormalizationForm.FormKD);
var sb = new StringBuilder();
foreach (var c in name)
{
if (c >= 0x2B0 && c <= 0x0333)
{
// skip char modifier and diacritics
}
else if (remove.IndexOf(c) > -1)
{
// skip chars we are removing
}
else if (spacers.IndexOf(c) > -1)
{
sb.Append(" ");
}
else if (c == '&')
{
sb.Append(" and ");
}
else
{
sb.Append(c);
}
}
sb.Replace(", the", string.Empty).Replace("the ", " ").Replace(" the ", " ");
return Regex.Replace(sb.ToString().Trim(), @"\s+", " ");
}
private void MapSeriesToResult(MetadataResult<Series> result, TvDbSharper.Dto.Series tvdbSeries, string metadataLanguage)
{
Series series = result.Item;
series.SetProviderId(MetadataProviders.Tvdb, tvdbSeries.Id.ToString());
series.Name = tvdbSeries.SeriesName;
series.Overview = (tvdbSeries.Overview ?? string.Empty).Trim();
result.ResultLanguage = metadataLanguage;
series.AirDays = TVUtils.GetAirDays(tvdbSeries.AirsDayOfWeek);
series.AirTime = tvdbSeries.AirsTime;
series.CommunityRating = (float?)tvdbSeries.SiteRating;
series.SetProviderId(MetadataProviders.Imdb, tvdbSeries.ImdbId);
series.SetProviderId(MetadataProviders.Zap2It, tvdbSeries.Zap2itId);
if (Enum.TryParse(tvdbSeries.Status, true, out SeriesStatus seriesStatus))
{
series.Status = seriesStatus;
}
if (DateTime.TryParse(tvdbSeries.FirstAired, out var date))
{
// dates from tvdb are UTC but without offset or Z
series.PremiereDate = date;
series.ProductionYear = date.Year;
}
series.RunTimeTicks = TimeSpan.FromMinutes(Convert.ToDouble(tvdbSeries.Runtime)).Ticks;
foreach (var genre in tvdbSeries.Genre)
{
series.AddGenre(genre);
}
if (!string.IsNullOrEmpty(tvdbSeries.Network))
{
series.AddStudio(tvdbSeries.Network);
}
if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended)
{
try
{
var episodeSummary = _tvDbClientManager
.GetSeriesEpisodeSummaryAsync(tvdbSeries.Id, metadataLanguage, CancellationToken.None).Result.Data;
var maxSeasonNumber = episodeSummary.AiredSeasons.Select(s => Convert.ToInt32(s)).Max();
var episodeQuery = new EpisodeQuery
{
AiredSeason = maxSeasonNumber
};
var episodesPage =
_tvDbClientManager.GetEpisodesPageAsync(tvdbSeries.Id, episodeQuery, metadataLanguage, CancellationToken.None).Result.Data;
result.Item.EndDate = episodesPage.Select(e =>
{
DateTime.TryParse(e.FirstAired, out var firstAired);
return firstAired;
}).Max();
}
catch (TvDbServerException e)
{
_logger.LogError(e, "Failed to find series end date for series {TvdbId}", tvdbSeries.Id);
}
}
}
private static void MapActorsToResult(MetadataResult<Series> result, IEnumerable<Actor> actors)
{
foreach (Actor actor in actors)
{
var personInfo = new PersonInfo
{
Type = PersonType.Actor,
Name = (actor.Name ?? string.Empty).Trim(),
Role = actor.Role,
ImageUrl = TvdbUtils.BannerUrl + actor.Image,
SortOrder = actor.SortOrder
};
if (!string.IsNullOrWhiteSpace(personInfo.Name))
{
result.AddPerson(personInfo);
}
}
}
public string Name => "TheTVDB";
public async Task Identify(SeriesInfo info)
{
if (!string.IsNullOrWhiteSpace(info.GetProviderId(MetadataProviders.Tvdb)))
{
return;
}
var srch = await FindSeries(info.Name, info.Year, info.MetadataLanguage, CancellationToken.None)
.ConfigureAwait(false);
var entry = srch.FirstOrDefault();
if (entry != null)
{
var id = entry.GetProviderId(MetadataProviders.Tvdb);
info.SetProviderId(MetadataProviders.Tvdb, id);
}
}
public int Order => 0;
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url,
BufferContent = false
});
}
}
}

View File

@@ -1,35 +0,0 @@
using System;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Providers.TV.TheTVDB
{
public static class TvdbUtils
{
public const string TvdbApiKey = "OG4V3YJ3FAP7FP2K";
public const string TvdbBaseUrl = "https://www.thetvdb.com/";
public const string BannerUrl = TvdbBaseUrl + "banners/";
public static ImageType GetImageTypeFromKeyType(string keyType)
{
switch (keyType.ToLowerInvariant())
{
case "poster":
case "season": return ImageType.Primary;
case "series":
case "seasonwide": return ImageType.Banner;
case "fanart": return ImageType.Backdrop;
default: throw new ArgumentException($"Invalid or unknown keytype: {keyType}", nameof(keyType));
}
}
public static string NormalizeLanguage(string language)
{
if (string.IsNullOrWhiteSpace(language))
{
return null;
}
// pt-br is just pt to tvdb
return language.Split('-')[0].ToLowerInvariant();
}
}
}

View File

@@ -1,7 +1,7 @@
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.TV.TheTVDB;
using MediaBrowser.Providers.Plugins.TheTvdb;
namespace MediaBrowser.Providers.TV
{