diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs new file mode 100644 index 0000000000..861cd3f5bd --- /dev/null +++ b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs @@ -0,0 +1,64 @@ +using System; +using MediaBrowser.Controller.Library; +using TvDbSharper; + +namespace MediaBrowser.Providers.TV +{ + public sealed class TvDbClientManager + { + private static volatile TvDbClientManager instance; + private static readonly object syncRoot = new object(); + private static TvDbClient tvDbClient; + private static DateTime tokenCreatedAt; + + private TvDbClientManager() + { + tvDbClient = new TvDbClient(); + tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + tokenCreatedAt = DateTime.Now; + } + + public static TvDbClientManager Instance + { + get + { + if (instance != null) + { + return instance; + } + + lock (syncRoot) + { + if (instance == null) + instance = new TvDbClientManager(); + } + + return instance; + } + } + + public TvDbClient TvDbClient + { + get + { + // Refresh if necessary + if (tokenCreatedAt > DateTime.Now.Subtract(TimeSpan.FromHours(20))) + { + try + { + tvDbClient.Authentication.RefreshTokenAsync(); + } + catch + { + tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + } + + tokenCreatedAt = DateTime.Now; + } + // Default to English + tvDbClient.AcceptedLanguage = "en"; + return tvDbClient; + } + } + } +} diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs index 75547610db..bc526e42a9 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs @@ -20,13 +20,12 @@ namespace MediaBrowser.Providers.TV.TheTVDB { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IHttpClient _httpClient; - private readonly TvDbClient _tvDbClient; + private readonly TvDbClientManager _tvDbClientManager; public TvdbEpisodeImageProvider(IHttpClient httpClient) { _httpClient = httpClient; - _tvDbClient = new TvDbClient(); - _tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + _tvDbClientManager = TvDbClientManager.Instance; } public string Name => "TheTVDB"; @@ -53,7 +52,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB { var tvdbId = episode.GetProviderId(MetadataProviders.Tvdb); // Process images - var episodeResult = await _tvDbClient.Episodes.GetAsync(Convert.ToInt32(tvdbId), cancellationToken); + var episodeResult = await _tvDbClientManager.TvDbClient.Episodes.GetAsync(Convert.ToInt32(tvdbId), cancellationToken); var image = GetImageInfo(episodeResult.Data); return new List diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index 7a1789e50f..c3a95f3856 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -1,872 +1,203 @@ -//using System; -//using System.Collections.Generic; -//using System.Globalization; -//using System.IO; -//using System.Linq; -//using System.Text; -//using System.Threading; -//using System.Threading.Tasks; -//using System.Xml; -//using MediaBrowser.Common.Net; -//using MediaBrowser.Controller.Configuration; -//using MediaBrowser.Controller.Entities; -//using MediaBrowser.Controller.Entities.TV; -//using MediaBrowser.Controller.Providers; -//using MediaBrowser.Model.Entities; -//using MediaBrowser.Model.IO; -//using MediaBrowser.Model.Providers; -//using MediaBrowser.Model.Xml; -//using Microsoft.Extensions.Logging; -// -//namespace MediaBrowser.Providers.TV -//{ -// -// /// -// /// Class RemoteEpisodeProvider -// /// -// class TvdbEpisodeProvider : IRemoteMetadataProvider -// { -// internal static TvdbEpisodeProvider Current; -// private readonly IServerConfigurationManager _config; -// private readonly IHttpClient _httpClient; -// private readonly ILogger _logger; -// -// public TvdbEpisodeProvider(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger) -// { -// _config = config; -// _httpClient = httpClient; -// _logger = logger; -// Current = this; -// } -// -// public Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) -// { -// var list = new List(); -// -// // The search query must either provide an episode number or date -// if (!searchInfo.IndexNumber.HasValue && !searchInfo.PremiereDate.HasValue) -// { -// return Task.FromResult((IEnumerable)list); -// } -// -// if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds)) -// { -// try -// { -// var metadataResult = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); -// -// if (metadataResult.HasMetadata) -// { -// 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 -// }); -// } -// } -// catch (FileNotFoundException) -// { -// // Don't fail the provider because this will just keep on going and going. -// } -// catch (IOException) -// { -// // Don't fail the provider because this will just keep on going and going. -// } -// } -// -// return Task.FromResult((IEnumerable)list); -// } -// -// public string Name => "TheTVDB"; -// -// 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)) -// { -// result = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); -// } -// else -// { -// _logger.LogDebug("No series identity found for {0}", searchInfo.Name); -// } -// -// return result; -// } -// -// /// -// /// Gets the episode XML files. -// /// -// /// The series data path. -// /// The search information. -// /// List{FileInfo}. -// internal List GetEpisodeXmlNodes(string seriesDataPath, EpisodeInfo searchInfo) -// { -// var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage); -// -// try -// { -// return GetXmlNodes(seriesXmlPath, searchInfo); -// } -// catch (FileNotFoundException) -// { -// return new List(); -// } -// catch (IOException) -// { -// return new List(); -// } -// } -// -// /// -// /// Fetches the episode data. -// /// -// /// The identifier. -// /// The series data path. -// /// The cancellation token. -// /// Task{System.Boolean}. -// private MetadataResult FetchEpisodeData(EpisodeInfo id, string seriesDataPath, CancellationToken cancellationToken) -// { -// var result = new MetadataResult() -// { -// Item = new Episode -// { -// IndexNumber = id.IndexNumber, -// ParentIndexNumber = id.ParentIndexNumber, -// IndexNumberEnd = id.IndexNumberEnd -// } -// }; -// -// var xmlNodes = GetEpisodeXmlNodes(seriesDataPath, id); -// -// if (xmlNodes.Count > 0) -// { -// FetchMainEpisodeInfo(result, xmlNodes[0], id.SeriesDisplayOrder, cancellationToken); -// -// result.HasMetadata = true; -// } -// +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.Dto; + +namespace MediaBrowser.Providers.TV +{ + + /// + /// Class RemoteEpisodeProvider + /// + class TvdbEpisodeProvider : IRemoteMetadataProvider, IHasOrder + { + internal static TvdbEpisodeProvider Current; + private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + private readonly TvDbClientManager _tvDbClientManager; + + public TvdbEpisodeProvider(IHttpClient httpClient, ILogger logger) + { + _httpClient = httpClient; + _logger = logger; + Current = this; + _tvDbClientManager = TvDbClientManager.Instance; + } + + public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) + { + var list = new List(); + + // The search query must either provide an episode number or date + // TODO premieredate functionality is ded + if (!searchInfo.IndexNumber.HasValue || !searchInfo.PremiereDate.HasValue) + { + return list; + } + + if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds)) + { + var episodeResult = + await _tvDbClientManager.TvDbClient.Episodes.GetAsync((int)searchInfo.IndexNumber, cancellationToken); + var metadataResult = MapEpisodeToResult(searchInfo, episodeResult.Data); + + if (metadataResult.HasMetadata) + { + 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> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken) + { + var result = new MetadataResult + { + QueriedById = true + }; + + if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && + (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue)) + { + var episodeResult = await _tvDbClientManager.TvDbClient.Episodes.GetAsync(Convert.ToInt32(searchInfo.GetProviderId(MetadataProviders.Tvdb)), + cancellationToken); + + result = MapEpisodeToResult(searchInfo, episodeResult.Data); + } + else + { + _logger.LogDebug("No series identity found for {0}", searchInfo.Name); + } + + return result; + } + + private static MetadataResult MapEpisodeToResult(EpisodeInfo id, EpisodeRecord episode) + { + var result = new MetadataResult + { + 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)) + { + date = date.ToUniversalTime(); + + item.PremiereDate = date; + item.ProductionYear = date.Year; + } + + foreach (var director in episode.Directors) + { + result.AddPerson(new PersonInfo + { + Name = director, + Type = PersonType.Director + }); + } + foreach (var person in episode.GuestStars) + { + var index = person.IndexOf('('); + string role = null; + var name = person; + + if (index != -1) + { + role = person.Substring(index + 1).Trim().TrimEnd(')'); + + name = person.Substring(0, index).Trim(); + } + + result.AddPerson(new PersonInfo + { + Type = PersonType.GuestStar, + Name = name, + Role = role + }); + } + foreach (var writer in episode.Writers) + { + result.AddPerson(new PersonInfo + { + Name = writer, + Type = PersonType.Writer + }); + } + // TODO result.ResultLanguage = episode. + + // TODO wtf is additional part info? // foreach (var node in xmlNodes.Skip(1)) // { // FetchAdditionalPartInfo(result, node, cancellationToken); // } -// -// return result; -// } -// -// private List GetXmlNodes(string xmlFile, EpisodeInfo searchInfo) -// { -// var list = new List(); -// -// if (searchInfo.IndexNumber.HasValue) -// { -// var files = GetEpisodeXmlFiles(searchInfo.SeriesDisplayOrder, searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, Path.GetDirectoryName(xmlFile)); -// -// list = files.Select(GetXmlReader).ToList(); -// } -// -// if (list.Count == 0 && searchInfo.PremiereDate.HasValue) -// { -// list = GetXmlNodesByPremiereDate(xmlFile, searchInfo.PremiereDate.Value); -// } -// -// return list; -// } -// -// private string GetEpisodeFileName(string seriesDisplayOrder, int? seasonNumber, int? episodeNumber) -// { -// if (string.Equals(seriesDisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase)) -// { -// return string.Format("episode-abs-{0}.xml", episodeNumber); -// } -// else if (string.Equals(seriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase)) -// { -// return string.Format("episode-dvd-{0}-{1}.xml", seasonNumber.Value, episodeNumber); -// } -// else -// { -// return string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber); -// } -// } -// -// private FileSystemMetadata GetEpisodeFileInfoWithFallback(string seriesDataPath, string seriesDisplayOrder, int? seasonNumber, int? episodeNumber) -// { -// var file = Path.Combine(seriesDataPath, GetEpisodeFileName(seriesDisplayOrder, seasonNumber, episodeNumber)); -// var fileInfo = _fileSystem.GetFileInfo(file); -// -// if (fileInfo.Exists) -// { -// return fileInfo; -// } -// -// if (!seasonNumber.HasValue) -// { -// return fileInfo; -// } -// -// // revert to aired order -// if (string.Equals(seriesDisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase) || string.Equals(seriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase)) -// { -// file = Path.Combine(seriesDataPath, GetEpisodeFileName(null, seasonNumber, episodeNumber)); -// return _fileSystem.GetFileInfo(file); -// } -// -// return fileInfo; -// } -// -// private List GetEpisodeXmlFiles(string seriesDisplayOrder, int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath) -// { -// var files = new List(); -// -// if (episodeNumber == null) -// { -// return files; -// } -// -// if (!seasonNumber.HasValue) -// { -// seriesDisplayOrder = "absolute"; -// } -// -// var fileInfo = GetEpisodeFileInfoWithFallback(seriesDataPath, seriesDisplayOrder, seasonNumber, episodeNumber); -// -// if (fileInfo.Exists) -// { -// files.Add(fileInfo); -// } -// -// var end = endingEpisodeNumber ?? episodeNumber; -// episodeNumber++; -// -// while (episodeNumber <= end) -// { -// fileInfo = GetEpisodeFileInfoWithFallback(seriesDataPath, seriesDisplayOrder, seasonNumber, episodeNumber); -// -// if (fileInfo.Exists) -// { -// files.Add(fileInfo); -// } -// else -// { -// break; -// } -// -// episodeNumber++; -// } -// -// return files; -// } -// -// private XmlReader GetXmlReader(FileSystemMetadata xmlFile) -// { -// return GetXmlReader(File.ReadAllText(xmlFile.FullName, Encoding.UTF8)); -// } -// -// private XmlReader GetXmlReader(string xml) -// { -// var streamReader = new StringReader(xml); -// -// var settings = _xmlSettings.Create(false); -// -// settings.CheckCharacters = false; -// settings.IgnoreProcessingInstructions = true; -// settings.IgnoreComments = true; -// -// return XmlReader.Create(streamReader, settings); -// } -// -// private List GetXmlNodesByPremiereDate(string xmlFile, DateTime premiereDate) -// { -// var list = new List(); -// -// using (var fileStream = _fileSystem.GetFileStream(xmlFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read)) -// { -// using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) -// { -// // Use XmlReader for best performance -// -// var settings = _xmlSettings.Create(false); -// -// settings.CheckCharacters = false; -// settings.IgnoreProcessingInstructions = true; -// settings.IgnoreComments = true; -// -// using (var reader = XmlReader.Create(streamReader, settings)) -// { -// reader.MoveToContent(); -// reader.Read(); -// -// // Loop through each element -// while (!reader.EOF && reader.ReadState == ReadState.Interactive) -// { -// if (reader.NodeType == XmlNodeType.Element) -// { -// switch (reader.Name) -// { -// case "Episode": -// { -// var outerXml = reader.ReadOuterXml(); -// -// var airDate = GetEpisodeAirDate(outerXml); -// -// if (airDate.HasValue && premiereDate.Date == airDate.Value.Date) -// { -// list.Add(GetXmlReader(outerXml)); -// return list; -// } -// -// break; -// } -// -// default: -// reader.Skip(); -// break; -// } -// } -// else -// { -// reader.Read(); -// } -// } -// } -// } -// } -// -// return list; -// } -// -// private DateTime? GetEpisodeAirDate(string xml) -// { -// using (var streamReader = new StringReader(xml)) -// { -// var settings = _xmlSettings.Create(false); -// -// settings.CheckCharacters = false; -// settings.IgnoreProcessingInstructions = true; -// settings.IgnoreComments = true; -// -// // Use XmlReader for best performance -// using (var reader = XmlReader.Create(streamReader, settings)) -// { -// reader.MoveToContent(); -// reader.Read(); -// -// // Loop through each element -// while (!reader.EOF && reader.ReadState == ReadState.Interactive) -// { -// if (reader.NodeType == XmlNodeType.Element) -// { -// switch (reader.Name) -// { -// case "FirstAired": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (DateTime.TryParse(val, out var date)) -// { -// date = date.ToUniversalTime(); -// -// return date; -// } -// } -// -// break; -// } -// -// default: -// reader.Skip(); -// break; -// } -// } -// else -// { -// reader.Read(); -// } -// } -// } -// } -// return null; -// } -// -// private readonly CultureInfo _usCulture = new CultureInfo("en-US"); -// -// private void FetchMainEpisodeInfo(MetadataResult result, XmlReader reader, string seriesOrder, CancellationToken cancellationToken) -// { -// var item = result.Item; -// -// int? episodeNumber = null; -// int? seasonNumber = null; -// int? combinedEpisodeNumber = null; -// int? combinedSeasonNumber = null; -// -// // Use XmlReader for best performance -// using (reader) -// { -// result.ResetPeople(); -// -// reader.MoveToContent(); -// reader.Read(); -// -// // Loop through each element -// while (!reader.EOF && reader.ReadState == ReadState.Interactive) -// { -// cancellationToken.ThrowIfCancellationRequested(); -// -// if (reader.NodeType == XmlNodeType.Element) -// { -// switch (reader.Name) -// { -// case "id": -// { -// var val = reader.ReadElementContentAsString(); -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.SetProviderId(MetadataProviders.Tvdb, val); -// } -// break; -// } -// -// case "IMDB_ID": -// { -// var val = reader.ReadElementContentAsString(); -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.SetProviderId(MetadataProviders.Imdb, val); -// } -// break; -// } -// -// case "EpisodeNumber": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// episodeNumber = rval; -// } -// } -// -// break; -// } -// -// case "SeasonNumber": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// seasonNumber = rval; -// } -// } -// -// break; -// } -// -// case "Combined_episodenumber": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (float.TryParse(val, NumberStyles.Any, _usCulture, out var num)) -// { -// combinedEpisodeNumber = Convert.ToInt32(num); -// } -// } -// -// break; -// } -// -// case "Combined_season": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (float.TryParse(val, NumberStyles.Any, _usCulture, out var num)) -// { -// combinedSeasonNumber = Convert.ToInt32(num); -// } -// } -// -// break; -// } -// -// case "airsbefore_episode": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// item.AirsBeforeEpisodeNumber = rval; -// } -// } -// -// break; -// } -// -// case "airsafter_season": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// item.AirsAfterSeasonNumber = rval; -// } -// } -// -// break; -// } -// -// case "airsbefore_season": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// item.AirsBeforeSeasonNumber = rval; -// } -// } -// -// break; -// } -// -// case "EpisodeName": -// { -// var val = reader.ReadElementContentAsString(); -// if (!item.LockedFields.Contains(MetadataFields.Name)) -// { -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.Name = val; -// } -// } -// break; -// } -// -// case "Overview": -// { -// var val = reader.ReadElementContentAsString(); -// if (!item.LockedFields.Contains(MetadataFields.Overview)) -// { -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.Overview = val; -// } -// } -// break; -// } -// case "Rating": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // float.TryParse is local aware, so it can be probamatic, force us culture -// if (float.TryParse(val, NumberStyles.AllowDecimalPoint, _usCulture, out var rval)) -// { -// item.CommunityRating = rval; -// } -// } -// break; -// } -// case "RatingCount": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// // int.TryParse is local aware, so it can be probamatic, force us culture -// if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var rval)) -// { -// //item.VoteCount = rval; -// } -// } -// -// break; -// } -// -// case "FirstAired": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (DateTime.TryParse(val, out var date)) -// { -// date = date.ToUniversalTime(); -// -// item.PremiereDate = date; -// item.ProductionYear = date.Year; -// } -// } -// -// break; -// } -// -// case "Director": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// AddPeople(result, val, PersonType.Director); -// } -// } -// -// break; -// } -// case "GuestStars": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// AddGuestStars(result, val); -// } -// } -// -// break; -// } -// case "Writer": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// //AddPeople(result, val, PersonType.Writer); -// } -// } -// -// break; -// } -// case "Language": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// result.ResultLanguage = val; -// } -// -// break; -// } -// -// default: -// reader.Skip(); -// break; -// } -// } -// else -// { -// reader.Read(); -// } -// } -// } -// -// if (string.Equals(seriesOrder, "dvd", StringComparison.OrdinalIgnoreCase)) -// { -// episodeNumber = combinedEpisodeNumber ?? episodeNumber; -// seasonNumber = combinedSeasonNumber ?? seasonNumber; -// } -// -// if (episodeNumber.HasValue) -// { -// item.IndexNumber = episodeNumber; -// } -// -// if (seasonNumber.HasValue) -// { -// item.ParentIndexNumber = seasonNumber; -// } -// } -// -// private void AddPeople(MetadataResult result, string val, string personType) -// { -// // Sometimes tvdb actors have leading spaces -// foreach (var person in val.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) -// .Where(i => !string.IsNullOrWhiteSpace(i)) -// .Select(str => new PersonInfo { Type = personType, Name = str.Trim() })) -// { -// result.AddPerson(person); -// } -// } -// -// private void AddGuestStars(MetadataResult result, string val) -// where T : BaseItem -// { -// // example: -// // |Mark C. Thomas| Dennis Kiefer| David Nelson (David)| Angela Nicholas| Tzi Ma| Kevin P. Kearns (Pasco)| -// var persons = val.Split('|') -// .Select(i => i.Trim()) -// .Where(i => !string.IsNullOrWhiteSpace(i)) -// .ToList(); -// -// foreach (var person in persons) -// { -// var index = person.IndexOf('('); -// string role = null; -// var name = person; -// -// if (index != -1) -// { -// role = person.Substring(index + 1).Trim().TrimEnd(')'); -// -// name = person.Substring(0, index).Trim(); -// } -// -// result.AddPerson(new PersonInfo -// { -// Type = PersonType.GuestStar, -// Name = name, -// Role = role -// }); -// } -// } -// -// private void FetchAdditionalPartInfo(MetadataResult result, XmlReader reader, CancellationToken cancellationToken) -// { -// var item = result.Item; -// -// // Use XmlReader for best performance -// using (reader) -// { -// reader.MoveToContent(); -// reader.Read(); -// -// // Loop through each element -// while (!reader.EOF && reader.ReadState == ReadState.Interactive) -// { -// cancellationToken.ThrowIfCancellationRequested(); -// -// if (reader.NodeType == XmlNodeType.Element) -// { -// switch (reader.Name) -// { -// case "EpisodeName": -// { -// var val = reader.ReadElementContentAsString(); -// if (!item.LockedFields.Contains(MetadataFields.Name)) -// { -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.Name += ", " + val; -// } -// } -// break; -// } -// -// case "Overview": -// { -// var val = reader.ReadElementContentAsString(); -// if (!item.LockedFields.Contains(MetadataFields.Overview)) -// { -// if (!string.IsNullOrWhiteSpace(val)) -// { -// item.Overview += Environment.NewLine + Environment.NewLine + val; -// } -// } -// break; -// } -// case "Director": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// AddPeople(result, val, PersonType.Director); -// } -// } -// -// break; -// } -// case "GuestStars": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// AddGuestStars(result, val); -// } -// } -// -// break; -// } -// case "Writer": -// { -// var val = reader.ReadElementContentAsString(); -// -// if (!string.IsNullOrWhiteSpace(val)) -// { -// if (!item.LockedFields.Contains(MetadataFields.Cast)) -// { -// //AddPeople(result, val, PersonType.Writer); -// } -// } -// -// break; -// } -// -// default: -// reader.Skip(); -// break; -// } -// } -// else -// { -// reader.Read(); -// } -// } -// } -// } -// -// public Task GetImageResponse(string url, CancellationToken cancellationToken) -// { -// return _httpClient.GetResponse(new HttpRequestOptions -// { -// CancellationToken = cancellationToken, -// Url = url -// }); -// } -// -// public int Order => 0; -// } -//} + + return result; + } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url + }); + } + + public int Order => 0; + } +} diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs index 1c5fde0d20..e592b20042 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs @@ -22,13 +22,12 @@ namespace MediaBrowser.Providers.TV.TheTVDB private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private readonly IHttpClient _httpClient; - private readonly TvDbClient _tvDbClient; + private readonly TvDbClientManager _tvDbClientManager; public TvdbSeasonImageProvider(IHttpClient httpClient) { _httpClient = httpClient; - _tvDbClient = new TvDbClient(); - _tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + _tvDbClientManager = TvDbClientManager.Instance; } public string Name => ProviderName; @@ -62,7 +61,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB var seasonNumber = season.IndexNumber.Value; var language = item.GetPreferredMetadataLanguage(); - _tvDbClient.AcceptedLanguage = language; + _tvDbClientManager.TvDbClient.AcceptedLanguage = language; var remoteImages = new List(); var keyTypes = new[] {KeyType.Season, KeyType.Seasonwide, KeyType.Fanart}; // TODO error handling @@ -73,10 +72,18 @@ namespace MediaBrowser.Providers.TV.TheTVDB KeyType = keyType, SubKey = seasonNumber.ToString() }; - var imageResults = - await _tvDbClient.Series.GetImagesAsync(Convert.ToInt32(series.GetProviderId(MetadataProviders.Tvdb)), imageQuery, cancellationToken); - - remoteImages.AddRange(GetImages(imageResults.Data, language)); + try + { + var imageResults = + await _tvDbClientManager.TvDbClient.Series.GetImagesAsync( + Convert.ToInt32(series.GetProviderId(MetadataProviders.Tvdb)), imageQuery, + cancellationToken); + remoteImages.AddRange(GetImages(imageResults.Data, language)); + } + catch (TvDbServerException e) + { + // TODO log + } } return remoteImages; @@ -88,7 +95,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB foreach (Image image in images) { - var resolution = image.Resolution.Split('x'); var imageInfo = new RemoteImageInfo { RatingType = RatingType.Score, @@ -97,11 +103,16 @@ namespace MediaBrowser.Providers.TV.TheTVDB Url = TVUtils.BannerUrl + image.FileName, ProviderName = ProviderName, // TODO Language = image.LanguageId, - Width = Convert.ToInt32(resolution[0]), - Height = Convert.ToInt32(resolution[1]), ThumbnailUrl = TVUtils.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]); + } + if (string.Equals(image.KeyType, "season", StringComparison.OrdinalIgnoreCase)) { imageInfo.Type = ImageType.Primary; diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs index 999598ff82..be968e5248 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs @@ -21,12 +21,12 @@ namespace MediaBrowser.Providers.TV.TheTVDB { private readonly IHttpClient _httpClient; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly TvDbClient _tvDbClient = new TvDbClient(); + private readonly TvDbClientManager _tvDbClientManager; public TvdbSeriesImageProvider(IHttpClient httpClient) { _httpClient = httpClient; - _tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + _tvDbClientManager = TvDbClientManager.Instance; } public string Name => ProviderName; @@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB } var language = item.GetPreferredMetadataLanguage(); - _tvDbClient.AcceptedLanguage = language; + _tvDbClientManager.TvDbClient.AcceptedLanguage = language; var remoteImages = new List(); var keyTypes = new[] {KeyType.Poster, KeyType.Series, KeyType.Fanart}; // TODO error handling @@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB KeyType = keyType }; var imageResults = - await _tvDbClient.Series.GetImagesAsync(Convert.ToInt32(item.GetProviderId(MetadataProviders.Tvdb)), imageQuery, cancellationToken); + await _tvDbClientManager.TvDbClient.Series.GetImagesAsync(Convert.ToInt32(item.GetProviderId(MetadataProviders.Tvdb)), imageQuery, cancellationToken); remoteImages.AddRange(GetImages(imageResults.Data, language)); } @@ -80,7 +80,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB foreach (Image image in images) { - var resolution = image.Resolution.Split('x'); var imageInfo = new RemoteImageInfo { RatingType = RatingType.Score, @@ -89,11 +88,16 @@ namespace MediaBrowser.Providers.TV.TheTVDB Url = TVUtils.BannerUrl + image.FileName, ProviderName = Name, // TODO Language = image.LanguageId, - Width = Convert.ToInt32(resolution[0]), - Height = Convert.ToInt32(resolution[1]), ThumbnailUrl = TVUtils.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]); + } + if (string.Equals(image.KeyType, "poster", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 4aa2d10622..d0a1f5ec19 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -1,25 +1,17 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; -using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; -using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; using TvDbSharper; using TvDbSharper.Dto; @@ -35,7 +27,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; - private readonly TvDbClient _tvDbClient; + private readonly TvDbClientManager _tvDbClientManager; public TvdbSeriesProvider(IHttpClient httpClient, ILogger logger, ILibraryManager libraryManager, ILocalizationManager localizationManager) { @@ -44,8 +36,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB _libraryManager = libraryManager; _localizationManager = localizationManager; Current = this; - _tvDbClient = new TvDbClient(); - _tvDbClient.Authentication.AuthenticateAsync(TVUtils.TvdbApiKey); + _tvDbClientManager = TvDbClientManager.Instance; } private string NormalizeLanguage(string language) @@ -112,7 +103,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB private async Task FetchSeriesData(MetadataResult result, string metadataLanguage, Dictionary seriesProviderIds, CancellationToken cancellationToken) { - _tvDbClient.AcceptedLanguage = NormalizeLanguage(metadataLanguage); + _tvDbClientManager.TvDbClient.AcceptedLanguage = NormalizeLanguage(metadataLanguage); var series = result.Item; if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(tvdbId)) @@ -133,7 +124,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB } // TODO call this function elsewhere? - var seriesResult = await _tvDbClient.Series.GetAsync(Convert.ToInt32(tvdbId), cancellationToken); + var seriesResult = await _tvDbClientManager.TvDbClient.Series.GetAsync(Convert.ToInt32(tvdbId), cancellationToken); // TODO error handling MapSeriesToResult(result, seriesResult.Data, cancellationToken); @@ -142,22 +133,22 @@ namespace MediaBrowser.Providers.TV.TheTVDB result.ResetPeople(); - var actorsResult = await _tvDbClient.Series.GetActorsAsync(Convert.ToInt32(tvdbId), cancellationToken); + var actorsResult = await _tvDbClientManager.TvDbClient.Series.GetActorsAsync(Convert.ToInt32(tvdbId), cancellationToken); MapActorsToResult(result, actorsResult.Data); } private async Task GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken) { - _tvDbClient.AcceptedLanguage = NormalizeLanguage(language); + _tvDbClientManager.TvDbClient.AcceptedLanguage = NormalizeLanguage(language); TvDbResponse result; if (string.Equals(idType, MetadataProviders.Zap2It.ToString(), StringComparison.OrdinalIgnoreCase)) { - result = await _tvDbClient.Search.SearchSeriesByZap2ItIdAsync(id, cancellationToken); + result = await _tvDbClientManager.TvDbClient.Search.SearchSeriesByZap2ItIdAsync(id, cancellationToken); } else { - result = await _tvDbClient.Search.SearchSeriesByImdbIdAsync(id, cancellationToken); + result = await _tvDbClientManager.TvDbClient.Search.SearchSeriesByImdbIdAsync(id, cancellationToken); } return result.Data.First().Id.ToString(); @@ -252,10 +243,10 @@ namespace MediaBrowser.Providers.TV.TheTVDB private async Task> FindSeriesInternal(string name, string language, CancellationToken cancellationToken) { - _tvDbClient.AcceptedLanguage = NormalizeLanguage(language); + _tvDbClientManager.TvDbClient.AcceptedLanguage = NormalizeLanguage(language); var comparableName = GetComparableName(name); var list = new List, RemoteSearchResult>>(); - TvDbResponse result = await _tvDbClient.Search.SearchSeriesByNameAsync(comparableName, cancellationToken); + TvDbResponse result = await _tvDbClientManager.TvDbClient.Search.SearchSeriesByNameAsync(comparableName, cancellationToken); foreach (var seriesSearchResult in result.Data) {