From 9729ae52a3351b389869fd032da2ebca5ab3b77e Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 29 Jan 2019 23:09:48 +0100 Subject: [PATCH] initial commit --- .../MediaBrowser.Providers.csproj | 3 +- .../TV/TheTVDB/TvdbSeriesProvider.cs | 875 ++++-------------- 2 files changed, 180 insertions(+), 698 deletions(-) diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index e6ef889c3e..1cf1ab256a 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -1,4 +1,4 @@ - + @@ -12,6 +12,7 @@ + diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 52e60a8eda..858a4fa9d1 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -12,7 +12,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -22,6 +21,9 @@ using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; +using TvDbSharper; +using TvDbSharper.Dto; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Providers.TV.TheTVDB { @@ -37,6 +39,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; + private readonly TvDbClient _tvDbClient; public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IXmlReaderSettingsFactory xmlSettings, ILocalizationManager localizationManager) { @@ -49,15 +52,9 @@ namespace MediaBrowser.Providers.TV.TheTVDB _xmlSettings = xmlSettings; _localizationManager = localizationManager; Current = this; + _tvDbClient = new TvDbClient(); } - public const string TvdbBaseUrl = "https://www.thetvdb.com/"; - - private const string SeriesSearchUrl = TvdbBaseUrl + "api/GetSeries.php?seriesname={0}&language={1}"; - private const string SeriesGetZip = TvdbBaseUrl + "api/{0}/series/{1}/all/{2}.zip"; - private const string GetSeriesByImdbId = TvdbBaseUrl + "api/GetSeriesByRemoteID.php?imdbid={0}&language={1}"; - private const string GetSeriesByZap2ItId = TvdbBaseUrl + "api/GetSeriesByRemoteID.php?zap2it={0}&language={1}"; - private string NormalizeLanguage(string language) { if (string.IsNullOrWhiteSpace(language)) @@ -135,29 +132,34 @@ namespace MediaBrowser.Providers.TV.TheTVDB /// Task{System.Boolean}. private void FetchSeriesData(MetadataResult result, string metadataLanguage, Dictionary seriesProviderIds, CancellationToken cancellationToken) { + _tvDbClient.AcceptedLanguage = NormalizeLanguage(metadataLanguage); var series = result.Item; + TvDbResponse searchResult; - if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out string id) && !string.IsNullOrEmpty(id)) + if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(id)) { - series.SetProviderId(MetadataProviders.Tvdb, id); + series.SetProviderId(MetadataProviders.Tvdb, tvdbId); } - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id) && !string.IsNullOrEmpty(id)) + if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out var imdbId) && !string.IsNullOrEmpty(id)) { - series.SetProviderId(MetadataProviders.Imdb, id); + series.SetProviderId(MetadataProviders.Imdb, imdbId); + tvdbId = GetSeriesByRemoteId(imdbId, MetadataProviders.Imdb.ToString(), metadataLanguage, cancellationToken).Result.ToString(); } - if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out id) && !string.IsNullOrEmpty(id)) + if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out var zap2It) && !string.IsNullOrEmpty(id)) { - series.SetProviderId(MetadataProviders.Zap2It, id); + series.SetProviderId(MetadataProviders.Zap2It, zap2It); + tvdbId = GetSeriesByRemoteId(zap2It, MetadataProviders.Zap2It.ToString(), metadataLanguage, cancellationToken).Result.ToString(); } - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - - var seriesXmlPath = GetSeriesXmlPath(seriesProviderIds, metadataLanguage); - var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml"); + var seriesResult = _tvDbClient.Series.GetAsync(Convert.ToInt32(tvdbId), cancellationToken).Result; +// var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); +// +// var seriesXmlPath = GetSeriesXmlPath(seriesProviderIds, metadataLanguage); +// var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml"); - FetchSeriesInfo(result, seriesXmlPath, cancellationToken); + FetchSeriesInfo(result, searchResult, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); @@ -199,7 +201,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB if (!string.Equals(idType, "tvdb", StringComparison.OrdinalIgnoreCase)) { - seriesId = await GetSeriesByRemoteId(seriesId, idType, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + seriesId = (await GetSeriesByRemoteId(seriesId, idType, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false)).ToString(); } // If searching by remote id came up empty, then do a regular search @@ -269,227 +271,31 @@ namespace MediaBrowser.Providers.TV.TheTVDB await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false); } - private async Task GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken) + private async Task GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken) { - string url; + _tvDbClient.AcceptedLanguage = NormalizeLanguage(language); + TvDbResponse result; + if (string.Equals(idType, MetadataProviders.Zap2It.ToString(), StringComparison.OrdinalIgnoreCase)) { - url = string.Format(GetSeriesByZap2ItId, id, NormalizeLanguage(language)); + result = await _tvDbClient.Search.SearchSeriesByZap2ItIdAsync(id, cancellationToken); } else { - url = string.Format(GetSeriesByImdbId, id, NormalizeLanguage(language)); - } - - using (var response = await _httpClient.SendAsync(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = false - - }, "GET").ConfigureAwait(false)) - { - using (var result = response.Content) - { - return FindSeriesId(result); - } - } - } - - private string FindSeriesId(Stream stream) - { - using (var streamReader = new StreamReader(stream, Encoding.UTF8)) - { - 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 "Series": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } - using (var subtree = reader.ReadSubtree()) - { - return FindSeriesId(subtree); - } - } - - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } - } - } - - return null; - } - - private string FindSeriesId(XmlReader reader) - { - reader.MoveToContent(); - reader.Read(); - - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "seriesid": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - return val; - } - - return null; - } - - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } + result = await _tvDbClient.Search.SearchSeriesByImdbIdAsync(id, cancellationToken); } - return null; + return result.Data.First().Id; } internal static bool IsValidSeries(Dictionary seriesProviderIds) { - if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out string id)) - { - // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet. - if (!string.IsNullOrWhiteSpace(id)) - { - return true; - } - } - - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id)) - { - // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet. - if (!string.IsNullOrWhiteSpace(id)) - { - return true; - } - } - - if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out id)) - { - // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet. - if (!string.IsNullOrWhiteSpace(id)) - { - return true; - } - } - return false; - } - - private SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1); - internal async Task EnsureSeriesInfo(Dictionary seriesProviderIds, string seriesName, int? seriesYear, string preferredMetadataLanguage, CancellationToken cancellationToken) - { - await _ensureSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out string seriesId) && !string.IsNullOrWhiteSpace(seriesId)) - { - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - - // Only download if not already there - // The post-scan task will take care of updates so we don't need to re-download here - if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) - { - await DownloadSeriesZip(seriesId, MetadataProviders.Tvdb.ToString(), seriesName, seriesYear, seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); - } - - return seriesDataPath; - } - - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out seriesId) && !string.IsNullOrWhiteSpace(seriesId)) - { - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - - // Only download if not already there - // The post-scan task will take care of updates so we don't need to re-download here - if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) - { - try - { - await DownloadSeriesZip(seriesId, MetadataProviders.Imdb.ToString(), seriesName, seriesYear, seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); - } - catch (ArgumentNullException) - { - // Unable to determine tvdb id based on imdb id - return null; - } - } - - return seriesDataPath; - } - - if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out seriesId) && !string.IsNullOrWhiteSpace(seriesId)) - { - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - - // Only download if not already there - // The post-scan task will take care of updates so we don't need to re-download here - if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) - { - try - { - await DownloadSeriesZip(seriesId, MetadataProviders.Zap2It.ToString(), seriesName, seriesYear, seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); - } - catch (ArgumentNullException) - { - // Unable to determine tvdb id based on Zap2It id - return null; - } - } - - return seriesDataPath; - } - - return null; - } - finally - { - _ensureSemaphore.Release(); - } + return seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out _) || + seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out _) || + seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out _); } + // TODO caching private bool IsCacheValid(string seriesDataPath, string preferredMetadataLanguage) { try @@ -543,7 +349,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB /// Task{System.String}. private async Task> FindSeries(string name, int? year, string language, CancellationToken cancellationToken) { - var results = (await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false)); + var results = await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false); if (results.Count == 0) { @@ -552,7 +358,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB if (!string.IsNullOrWhiteSpace(nameWithoutYear) && !string.Equals(nameWithoutYear, name, StringComparison.OrdinalIgnoreCase)) { - results = (await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false)); + results = await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false); } } @@ -570,77 +376,32 @@ namespace MediaBrowser.Providers.TV.TheTVDB private async Task> FindSeriesInternal(string name, string language, CancellationToken cancellationToken) { - var url = string.Format(SeriesSearchUrl, WebUtility.UrlEncode(name), NormalizeLanguage(language)); - + _tvDbClient.AcceptedLanguage = NormalizeLanguage(language); var comparableName = GetComparableName(name); - var list = new List, RemoteSearchResult>>(); + TvDbResponse result = await _tvDbClient.Search.SearchSeriesByNameAsync(comparableName, cancellationToken); - using (var response = await _httpClient.SendAsync(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = false - - }, "GET").ConfigureAwait(false)) + foreach (var seriesSearchResult in result.Data) { - using (var stream = response.Content) + var tvdbTitles = new List { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - using (var streamReader = new StreamReader(stream, Encoding.UTF8)) - { - // 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) - { - cancellationToken.ThrowIfCancellationRequested(); + GetComparableName(seriesSearchResult.SeriesName) + }; + tvdbTitles.AddRange(seriesSearchResult.Aliases.Select(GetComparableName)); - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "Series": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } - using (var subtree = reader.ReadSubtree()) - { - var searchResultInfo = GetSeriesSearchResultFromSubTree(subtree); - if (searchResultInfo != null) - { - searchResultInfo.Item2.SearchProviderName = Name; - list.Add(searchResultInfo); - } - } - break; - } + DateTime.TryParse(seriesSearchResult.FirstAired, out var firstAired); + var remoteSearchResult = new RemoteSearchResult + { + Name = tvdbTitles.FirstOrDefault(), + ProductionYear = firstAired.Year, + SearchProviderName = Name, + ImageUrl = seriesSearchResult.Banner - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } - } - } - } + }; + // TODO requires another query + // remoteSearchResult.SetProviderId(MetadataProviders.Imdb, seriesSearchResult.Id); + remoteSearchResult.SetProviderId(MetadataProviders.Tvdb, seriesSearchResult.Id.ToString()); + list.Add(new Tuple, RemoteSearchResult>(tvdbTitles, remoteSearchResult)); } return list @@ -650,116 +411,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB .ToList(); } - private Tuple, RemoteSearchResult> GetSeriesSearchResultFromSubTree(XmlReader reader) - { - var searchResult = new RemoteSearchResult - { - SearchProviderName = Name - }; - - var tvdbTitles = new List(); - string seriesId = null; - - reader.MoveToContent(); - reader.Read(); - - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "SeriesName": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - tvdbTitles.Add(GetComparableName(val)); - } - break; - } - - case "AliasNames": - { - var val = reader.ReadElementContentAsString(); - - var alias = (val ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).Select(GetComparableName); - tvdbTitles.AddRange(alias); - break; - } - - case "IMDB_ID": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - searchResult.SetProviderId(MetadataProviders.Imdb, val); - } - break; - } - - case "banner": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - searchResult.ImageUrl = TVUtils.BannerUrl + val; - } - break; - } - - case "FirstAired": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - if (DateTime.TryParse(val, out var date)) - { - searchResult.ProductionYear = date.Year; - } - } - break; - } - - case "id": - case "seriesid": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - seriesId = val; - } - break; - } - - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } - - if (tvdbTitles.Count == 0) - { - return null; - } - - searchResult.Name = tvdbTitles.FirstOrDefault(); - searchResult.SetProviderId(MetadataProviders.Tvdb, seriesId); - - return new Tuple, RemoteSearchResult>(tvdbTitles, searchResult); - } - /// /// The remove /// @@ -817,85 +468,141 @@ namespace MediaBrowser.Providers.TV.TheTVDB return name.Trim(); } - private void FetchSeriesInfo(MetadataResult result, string seriesXmlPath, CancellationToken cancellationToken) + private void FetchSeriesInfo(MetadataResult result, TvDbResponse seriesResponse, CancellationToken cancellationToken) { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - var episiodeAirDates = new List(); + var episodeAirDates = new List(); + var series = result.Item; + Series item = result.Item; + series.SetProviderId(MetadataProviders.Tvdb, seriesResponse.Data.Id.ToString()); + series.Name = seriesResponse.Data.SeriesName; + series.Overview = (seriesResponse.Data.Overview ?? string.Empty).Trim(); + // TODO result.ResultLanguage = (seriesResponse.Data. ?? string.Empty).Trim(); + series.AirDays = TVUtils.GetAirDays(seriesResponse.Data.AirsDayOfWeek); + series.AirTime = seriesResponse.Data.AirsTime; + + series.CommunityRating = (float?)seriesResponse.Data.SiteRating; + series.SetProviderId(MetadataProviders.Imdb, seriesResponse.Data.ImdbId); + series.SetProviderId(MetadataProviders.Zap2It, seriesResponse.Data.Zap2itId); + if (Enum.TryParse(seriesResponse.Data.Status, true, out SeriesStatus seriesStatus)) + { + series.Status = seriesStatus; + } - using (var fileStream = _fileSystem.GetFileStream(seriesXmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read)) + if (DateTime.TryParse(seriesResponse.Data.FirstAired, out var date)) { - using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) - { - // Use XmlReader for best performance - using (var reader = XmlReader.Create(streamReader, settings)) - { - reader.MoveToContent(); - reader.Read(); + date = date.ToUniversalTime(); - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) - { - cancellationToken.ThrowIfCancellationRequested(); + series.PremiereDate = date; + series.ProductionYear = date.Year; + } - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "Series": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } - using (var subtree = reader.ReadSubtree()) - { - FetchDataFromSeriesNode(result, subtree, cancellationToken); - } - break; - } + series.RunTimeTicks = TimeSpan.FromMinutes(Convert.ToDouble(seriesResponse.Data.Runtime)).Ticks; - case "Episode": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } - using (var subtree = reader.ReadSubtree()) - { - var date = GetFirstAiredDateFromEpisodeNode(subtree, cancellationToken); - if (date.HasValue) - { - episiodeAirDates.Add(date.Value); - } - } - break; - } + if (!string.IsNullOrWhiteSpace(val)) + { + var vals = val + .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) + .Select(i => i.Trim()) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } + if (vals.Count > 0) + { + item.Genres = Array.Empty(); + + foreach (var genre in vals) + { + item.AddGenre(genre); } } } - if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0) + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) { - result.Item.EndDate = episiodeAirDates.Max(); + var vals = val + .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) + .Select(i => i.Trim()) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); + + if (vals.Count > 0) + { + item.SetStudios(vals); + } + } + +// using (var fileStream = _fileSystem.GetFileStream(seriesXmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read)) +// { +// using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) +// { +// // 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) +// { +// cancellationToken.ThrowIfCancellationRequested(); +// +// if (reader.NodeType == XmlNodeType.Element) +// { +// switch (reader.Name) +// { +// case "Series": +// { +// if (reader.IsEmptyElement) +// { +// reader.Read(); +// continue; +// } +// using (var subtree = reader.ReadSubtree()) +// { +// FetchDataFromSeriesNode(result, subtree, cancellationToken); +// } +// break; +// } +// +// case "Episode": +// { +// if (reader.IsEmptyElement) +// { +// reader.Read(); +// continue; +// } +// using (var subtree = reader.ReadSubtree()) +// { +// var date = GetFirstAiredDateFromEpisodeNode(subtree, cancellationToken); +// +// if (date.HasValue) +// { +// episiodeAirDates.Add(date.Value); +// } +// } +// break; +// } +// +// default: +// reader.Skip(); +// break; +// } +// } +// else +// { +// reader.Read(); +// } +// } +// } +// } +// } + + if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended && episodeAirDates.Count > 0) + { + result.Item.EndDate = episodeAirDates.Max(); } } @@ -1107,237 +814,11 @@ namespace MediaBrowser.Providers.TV.TheTVDB } } - private void FetchDataFromSeriesNode(MetadataResult result, XmlReader reader, CancellationToken cancellationToken) + private void FetchDataFromSeriesNode(MetadataResult result, CancellationToken cancellationToken) { - Series item = result.Item; - - 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": - { - item.SetProviderId(MetadataProviders.Tvdb.ToString(), (reader.ReadElementContentAsString() ?? string.Empty).Trim()); - break; - } - - case "SeriesName": - { - item.Name = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); - break; - } - - case "Overview": - { - item.Overview = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); - break; - } - - case "Language": - { - result.ResultLanguage = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); - break; - } - - case "Airs_DayOfWeek": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - item.AirDays = TVUtils.GetAirDays(val); - } - break; - } - - case "Airs_Time": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - item.AirTime = val; - } - break; - } - - case "ContentRating": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - item.OfficialRating = 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 "IMDB_ID": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.Imdb, val); - } - - break; - } - - case "zap2it_id": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.Zap2It, val); - } - - break; - } - - case "Status": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - if (Enum.TryParse(val, true, out SeriesStatus seriesStatus)) - item.Status = seriesStatus; - } - - 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 "Runtime": - { - 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.RunTimeTicks = TimeSpan.FromMinutes(rval).Ticks; - } - } - - break; - } - - case "Genre": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - var vals = val - .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) - .Select(i => i.Trim()) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .ToList(); - - if (vals.Count > 0) - { - item.Genres = Array.Empty(); - - foreach (var genre in vals) - { - item.AddGenre(genre); - } - } - } - - break; - } - - case "Network": - { - var val = reader.ReadElementContentAsString(); - - if (!string.IsNullOrWhiteSpace(val)) - { - var vals = val - .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) - .Select(i => i.Trim()) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .ToList(); - - if (vals.Count > 0) - { - item.SetStudios(vals); - } - } + cancellationToken.ThrowIfCancellationRequested(); - break; - } - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } } ///