aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2019-02-01 17:43:31 +0100
committerBond-009 <bond.009@outlook.com>2019-03-07 12:04:14 +0100
commita9302b8b53e8393fbedeefb3be75ae6eba8ae815 (patch)
treebeb4b37d19fe9a258161110933da683b50a9b3d1 /MediaBrowser.Providers
parent276428878e2f61c59177d5ab23265a637a3eb7e5 (diff)
Remove useless abstraction around XmlReaderSettings
This removes the amount of stuff that needs to be passed around Also removes some unneeded `ManagedFileSystem` usage
Diffstat (limited to 'MediaBrowser.Providers')
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs171
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs19
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs396
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs1
6 files changed, 486 insertions, 108 deletions
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index e4bb52217c..335f2c5395 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -15,7 +15,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.Music
@@ -28,17 +27,15 @@ namespace MediaBrowser.Providers.Music
private readonly IApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IJsonSerializer _json;
- private readonly IXmlReaderSettingsFactory _xmlSettings;
public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org";
- public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json, IXmlReaderSettingsFactory xmlSettings)
+ public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json)
{
_httpClient = httpClient;
_appHost = appHost;
_logger = logger;
_json = json;
- _xmlSettings = xmlSettings;
Current = this;
}
@@ -101,11 +98,13 @@ namespace MediaBrowser.Providers.Music
{
using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- var settings = _xmlSettings.Create(false);
-
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ var settings = new XmlReaderSettings()
+ {
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
using (var reader = XmlReader.Create(oReader, settings))
{
@@ -240,22 +239,20 @@ namespace MediaBrowser.Providers.Music
artistId);
using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false))
+ using (var stream = response.Content)
+ using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- using (var stream = response.Content)
+ var settings = new XmlReaderSettings()
{
- using (var oReader = new StreamReader(stream, Encoding.UTF8))
- {
- var settings = _xmlSettings.Create(false);
-
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
- using (var reader = XmlReader.Create(oReader, settings))
- {
- return ReleaseResult.Parse(reader).FirstOrDefault();
- }
- }
+ using (var reader = XmlReader.Create(oReader, settings))
+ {
+ return ReleaseResult.Parse(reader).FirstOrDefault();
}
}
}
@@ -267,22 +264,20 @@ namespace MediaBrowser.Providers.Music
WebUtility.UrlEncode(artistName));
using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false))
+ using (var stream = response.Content)
+ using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- using (var stream = response.Content)
+ var settings = new XmlReaderSettings()
{
- using (var oReader = new StreamReader(stream, Encoding.UTF8))
- {
- var settings = _xmlSettings.Create(false);
-
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
- using (var reader = XmlReader.Create(oReader, settings))
- {
- return ReleaseResult.Parse(reader).FirstOrDefault();
- }
- }
+ using (var reader = XmlReader.Create(oReader, settings))
+ {
+ return ReleaseResult.Parse(reader).FirstOrDefault();
}
}
}
@@ -590,26 +585,24 @@ namespace MediaBrowser.Providers.Music
var url = string.Format("/ws/2/release?release-group={0}", releaseGroupId);
using (var response = await GetMusicBrainzResponse(url, true, true, cancellationToken).ConfigureAwait(false))
+ using (var stream = response.Content)
+ using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- using (var stream = response.Content)
+ var settings = new XmlReaderSettings()
{
- using (var oReader = new StreamReader(stream, Encoding.UTF8))
- {
- var settings = _xmlSettings.Create(false);
-
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
- using (var reader = XmlReader.Create(oReader, settings))
- {
- var result = ReleaseResult.Parse(reader).FirstOrDefault();
+ using (var reader = XmlReader.Create(oReader, settings))
+ {
+ var result = ReleaseResult.Parse(reader).FirstOrDefault();
- if (result != null)
- {
- return result.ReleaseId;
- }
- }
+ if (result != null)
+ {
+ return result.ReleaseId;
}
}
}
@@ -628,56 +621,54 @@ namespace MediaBrowser.Providers.Music
var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId);
using (var response = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false))
+ using (var stream = response.Content)
+ using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- using (var stream = response.Content)
+ var settings = new XmlReaderSettings()
{
- using (var oReader = new StreamReader(stream, Encoding.UTF8))
- {
- var settings = _xmlSettings.Create(false);
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ using (var reader = XmlReader.Create(oReader, settings))
+ {
+ reader.MoveToContent();
+ reader.Read();
- using (var reader = XmlReader.Create(oReader, settings))
+ // Loop through each element
+ while (!reader.EOF && reader.ReadState == ReadState.Interactive)
+ {
+ if (reader.NodeType == XmlNodeType.Element)
{
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
+ switch (reader.Name)
{
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
+ case "release-group-list":
{
- case "release-group-list":
- {
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
- using (var subReader = reader.ReadSubtree())
- {
- return GetFirstReleaseGroupId(subReader);
- }
- }
- default:
- {
- reader.Skip();
- break;
- }
+ if (reader.IsEmptyElement)
+ {
+ reader.Read();
+ continue;
+ }
+ using (var subReader = reader.ReadSubtree())
+ {
+ return GetFirstReleaseGroupId(subReader);
+ }
+ }
+ default:
+ {
+ reader.Skip();
+ break;
}
- }
- else
- {
- reader.Read();
- }
}
- return null;
+ }
+ else
+ {
+ reader.Read();
}
}
+ return null;
}
}
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 8d10834c32..924b712507 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -13,17 +13,14 @@ using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Xml;
namespace MediaBrowser.Providers.Music
{
public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist, ArtistInfo>
{
- private readonly IXmlReaderSettingsFactory _xmlSettings;
-
- public MusicBrainzArtistProvider(IXmlReaderSettingsFactory xmlSettings)
+ public MusicBrainzArtistProvider()
{
- _xmlSettings = xmlSettings;
+
}
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
@@ -84,11 +81,13 @@ namespace MediaBrowser.Providers.Music
{
using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
- var settings = _xmlSettings.Create(false);
-
- settings.CheckCharacters = false;
- settings.IgnoreProcessingInstructions = true;
- settings.IgnoreComments = true;
+ var settings = new XmlReaderSettings()
+ {
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
using (var reader = XmlReader.Create(oReader, settings))
{
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 0a2975e0f9..752c0941d0 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -1,12 +1,9 @@
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.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index afbd838e4b..d5b0b6fd89 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.TV.TheTVDB;
using Microsoft.Extensions.Logging;
@@ -18,7 +17,6 @@ namespace MediaBrowser.Providers.TV
public class SeriesMetadataService : MetadataService<Series, SeriesInfo>
{
private readonly ILocalizationManager _localization;
- private readonly IXmlReaderSettingsFactory _xmlSettings;
private readonly TvDbClientManager _tvDbClientManager;
public SeriesMetadataService(
@@ -29,13 +27,11 @@ namespace MediaBrowser.Providers.TV
IUserDataManager userDataManager,
ILibraryManager libraryManager,
ILocalizationManager localization,
- IXmlReaderSettingsFactory xmlSettings,
TvDbClientManager tvDbClientManager
)
: base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
{
_localization = localization;
- _xmlSettings = xmlSettings;
_tvDbClientManager = tvDbClientManager;
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
new file mode 100644
index 0000000000..c8ae585740
--- /dev/null
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
@@ -0,0 +1,396 @@
+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.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Providers.TV.TheTVDB;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.TV
+{
+ /// <summary>
+ /// Class TvdbPrescanTask
+ /// </summary>
+ public class TvdbPrescanTask : ILibraryPostScanTask
+ {
+ public const string TvdbBaseUrl = "https://thetvdb.com/";
+
+ /// <summary>
+ /// The server time URL
+ /// </summary>
+ private const string ServerTimeUrl = TvdbBaseUrl + "api/Updates.php?type=none";
+
+ /// <summary>
+ /// The updates URL
+ /// </summary>
+ private const string UpdatesUrl = TvdbBaseUrl + "api/Updates.php?type=all&time={0}";
+
+ /// <summary>
+ /// The _HTTP client
+ /// </summary>
+ private readonly IHttpClient _httpClient;
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+ /// <summary>
+ /// The _config
+ /// </summary>
+ private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TvdbPrescanTask"/> class.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ /// <param name="httpClient">The HTTP client.</param>
+ /// <param name="config">The config.</param>
+ public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IFileSystem fileSystem, ILibraryManager libraryManager)
+ {
+ _logger = logger;
+ _httpClient = httpClient;
+ _config = config;
+ _fileSystem = fileSystem;
+ _libraryManager = libraryManager;
+ }
+
+ protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
+ /// <summary>
+ /// Runs the specified progress.
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
+
+ Directory.CreateDirectory(path);
+
+ var timestampFile = Path.Combine(path, "time.txt");
+
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
+
+ // Don't check for tvdb updates anymore frequently than 24 hours
+ if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
+ {
+ return;
+ }
+
+ // Find out the last time we queried tvdb for updates
+ var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+
+ string newUpdateTime;
+
+ var existingDirectories = _fileSystem.GetDirectoryPaths(path)
+ .Select(Path.GetFileName)
+ .ToList();
+
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false,
+ DtoOptions = new DtoOptions(false)
+ {
+ EnableImages = false
+ }
+
+ }).Cast<Series>()
+ .ToList();
+
+ var seriesIdsInLibrary = seriesList
+ .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
+ .Select(i => i.GetProviderId(MetadataProviders.Tvdb))
+ .ToList();
+
+ var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ var enableInternetProviders = seriesList.Count == 0 ? false : seriesList[0].IsMetadataFetcherEnabled(_libraryManager.GetLibraryOptions(seriesList[0]), TvdbSeriesProvider.Current.Name);
+ if (!enableInternetProviders)
+ {
+ progress.Report(100);
+ return;
+ }
+
+ // If this is our first time, update all series
+ if (string.IsNullOrEmpty(lastUpdateTime))
+ {
+ // First get tvdb server time
+ using (var response = await _httpClient.SendAsync(new HttpRequestOptions
+ {
+ Url = ServerTimeUrl,
+ CancellationToken = cancellationToken,
+ EnableHttpCompression = true,
+ BufferContent = false
+
+ }, "GET").ConfigureAwait(false))
+ {
+ // First get tvdb server time
+ using (var stream = response.Content)
+ {
+ newUpdateTime = GetUpdateTime(stream);
+ }
+ }
+
+ existingDirectories.AddRange(missingSeries);
+
+ await UpdateSeries(existingDirectories, path, null, progress, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);
+
+ newUpdateTime = seriesToUpdate.Item2;
+
+ long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out var lastUpdateValue);
+
+ var nullableUpdateValue = lastUpdateValue == 0 ? (long?)null : lastUpdateValue;
+
+ var listToUpdate = seriesToUpdate.Item1.ToList();
+ listToUpdate.AddRange(missingSeries);
+
+ await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false);
+ }
+
+ File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ progress.Report(100);
+ }
+
+ /// <summary>
+ /// Gets the update time.
+ /// </summary>
+ /// <param name="response">The response.</param>
+ /// <returns>System.String.</returns>
+ private string GetUpdateTime(Stream response)
+ {
+ // Use XmlReader for best performance
+ var settings = new XmlReaderSettings()
+ {
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
+
+ using (var streamReader = new StreamReader(response, Encoding.UTF8))
+ 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 "Time":
+ {
+ return (reader.ReadElementContentAsString() ?? string.Empty).Trim();
+ }
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ else
+ {
+ reader.Read();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets the series ids to update.
+ /// </summary>
+ /// <param name="existingSeriesIds">The existing series ids.</param>
+ /// <param name="lastUpdateTime">The last update time.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{IEnumerable{System.String}}.</returns>
+ private async Task<Tuple<IEnumerable<string>, string>> GetSeriesIdsToUpdate(IEnumerable<string> existingSeriesIds, string lastUpdateTime, CancellationToken cancellationToken)
+ {
+ // First get last time
+ using (var response = await _httpClient.SendAsync(new HttpRequestOptions
+ {
+ Url = string.Format(UpdatesUrl, lastUpdateTime),
+ CancellationToken = cancellationToken,
+ EnableHttpCompression = true,
+ BufferContent = false
+
+ }, "GET").ConfigureAwait(false))
+ {
+ using (var stream = response.Content)
+ {
+ var data = GetUpdatedSeriesIdList(stream);
+
+ var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+
+ var seriesList = data.ids
+ .Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i));
+
+ return new Tuple<IEnumerable<string>, string>(seriesList, data.updateTime);
+ }
+ }
+ }
+
+ private (List<string> ids, string updateTime) GetUpdatedSeriesIdList(Stream stream)
+ {
+ string updateTime = null;
+ var idList = new List<string>();
+
+ // Use XmlReader for best performance
+ var settings = new XmlReaderSettings()
+ {
+ ValidationType = ValidationType.None,
+ CheckCharacters = false,
+ IgnoreProcessingInstructions = true,
+ IgnoreComments = true
+ };
+
+ using (var streamReader = new StreamReader(stream, Encoding.UTF8))
+ 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 "Time":
+ {
+ updateTime = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
+ break;
+ }
+ case "Series":
+ {
+ var id = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
+ idList.Add(id);
+ break;
+ }
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ else
+ {
+ reader.Read();
+ }
+ }
+ }
+
+ return (idList, updateTime);
+ }
+
+ /// <summary>
+ /// Updates the series.
+ /// </summary>
+ /// <param name="seriesIds">The series ids.</param>
+ /// <param name="seriesDataPath">The series data path.</param>
+ /// <param name="lastTvDbUpdateTime">The last tv db update time.</param>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ private async Task UpdateSeries(List<string> seriesIds, string seriesDataPath, long? lastTvDbUpdateTime, IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var numComplete = 0;
+
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false,
+ DtoOptions = new DtoOptions(false)
+ {
+ EnableImages = false
+ }
+
+ }).Cast<Series>();
+
+ // Gather all series into a lookup by tvdb id
+ var allSeries = seriesList
+ .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
+ .ToLookup(i => i.GetProviderId(MetadataProviders.Tvdb));
+
+ foreach (var seriesId in seriesIds)
+ {
+ // Find the preferred language(s) for the movie in the library
+ var languages = allSeries[seriesId]
+ .Select(i => i.GetPreferredMetadataLanguage())
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ foreach (var language in languages)
+ {
+ try
+ {
+ await UpdateSeries(seriesId, seriesDataPath, lastTvDbUpdateTime, language, cancellationToken).ConfigureAwait(false);
+ }
+ catch (HttpException ex)
+ {
+ _logger.LogError(ex, "Error updating tvdb series id {ID}, language {Language}", seriesId, language);
+
+ // Already logged at lower levels, but don't fail the whole operation, unless timed out
+ // We have to fail this to make it run again otherwise new episode data could potentially be missing
+ if (ex.IsTimedOut)
+ {
+ throw;
+ }
+ }
+ }
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= seriesIds.Count;
+ percent *= 100;
+
+ progress.Report(percent);
+ }
+ }
+
+ /// <summary>
+ /// Updates the series.
+ /// </summary>
+ /// <param name="id">The id.</param>
+ /// <param name="seriesDataPath">The series data path.</param>
+ /// <param name="lastTvDbUpdateTime">The last tv db update time.</param>
+ /// <param name="preferredMetadataLanguage">The preferred metadata language.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ private Task UpdateSeries(string id, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Updating series from tvdb " + id + ", language " + preferredMetadataLanguage);
+
+ seriesDataPath = Path.Combine(seriesDataPath, id);
+
+ Directory.CreateDirectory(seriesDataPath);
+
+ return TvdbSeriesProvider.Current.DownloadSeriesZip(id, MetadataProviders.Tvdb.ToString(), null, null, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, cancellationToken);
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 9c24e4c987..09b056c0cb 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -23,7 +23,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB
{
internal static TvdbSeriesProvider Current { get; private set; }
private readonly IHttpClient _httpClient;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localizationManager;