瀏覽代碼

initial commit

Claus Vium 6 年之前
父節點
當前提交
9729ae52a3
共有 2 個文件被更改,包括 180 次插入698 次删除
  1. 2 1
      MediaBrowser.Providers/MediaBrowser.Providers.csproj
  2. 178 697
      MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs

+ 2 - 1
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
@@ -12,6 +12,7 @@
 
   <ItemGroup>
     <PackageReference Include="PlaylistsNET" Version="1.0.2" />
+    <PackageReference Include="TvDbSharper" Version="2.0.0" />
   </ItemGroup>
 
   <PropertyGroup>

+ 178 - 697
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
         /// <returns>Task{System.Boolean}.</returns>
         private void FetchSeriesData(MetadataResult<Series> result, string metadataLanguage, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
         {
+            _tvDbClient.AcceptedLanguage = NormalizeLanguage(metadataLanguage);
             var series = result.Item;
+            TvDbResponse<SeriesSearchResult[]> 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<string> GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken)
+        private async Task<int> GetSeriesByRemoteId(string id, string idType, string language, CancellationToken cancellationToken)
         {
-            string url;
+            _tvDbClient.AcceptedLanguage = NormalizeLanguage(language);
+            TvDbResponse<SeriesSearchResult[]> 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<string, string> 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<string> EnsureSeriesInfo(Dictionary<string, string> 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
         /// <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));
+            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<List<RemoteSearchResult>> 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<Tuple<List<string>, RemoteSearchResult>>();
+            TvDbResponse<SeriesSearchResult[]> 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<string>
                 {
-                    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<List<string>, RemoteSearchResult>(tvdbTitles, remoteSearchResult));
             }
 
             return list
@@ -650,116 +411,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB
                 .ToList();
         }
 
-        private Tuple<List<string>, RemoteSearchResult> GetSeriesSearchResultFromSubTree(XmlReader reader)
-        {
-            var searchResult = new RemoteSearchResult
-            {
-                SearchProviderName = Name
-            };
-
-            var tvdbTitles = new List<string>();
-            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<List<string>, RemoteSearchResult>(tvdbTitles, searchResult);
-        }
-
         /// <summary>
         /// The remove
         /// </summary>
@@ -817,85 +468,141 @@ namespace MediaBrowser.Providers.TV.TheTVDB
             return name.Trim();
         }
 
-        private void FetchSeriesInfo(MetadataResult<Series> result, string seriesXmlPath, CancellationToken cancellationToken)
+        private void FetchSeriesInfo(MetadataResult<Series> result, TvDbResponse<TvDbSharper.Dto.Series> seriesResponse, CancellationToken cancellationToken)
         {
-            var settings = _xmlSettings.Create(false);
-
-            settings.CheckCharacters = false;
-            settings.IgnoreProcessingInstructions = true;
-            settings.IgnoreComments = true;
-
-            var episiodeAirDates = new List<DateTime>();
+            var episodeAirDates = new List<DateTime>();
+            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<string>();
+
+                    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<Series> result, XmlReader reader, CancellationToken cancellationToken)
+        private void FetchDataFromSeriesNode(MetadataResult<Series> 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<string>();
-
-                                        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();
-                }
-            }
         }
 
         /// <summary>