|
|
|
@ -20,9 +20,8 @@ using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using MediaBrowser.Model.IO;
|
|
|
|
|
using MediaBrowser.Common.IO;
|
|
|
|
|
using MediaBrowser.Controller.IO;
|
|
|
|
|
using MediaBrowser.Model.Globalization;
|
|
|
|
|
using MediaBrowser.Model.Xml;
|
|
|
|
|
|
|
|
|
|
namespace MediaBrowser.Providers.TV
|
|
|
|
|
{
|
|
|
|
@ -41,8 +40,10 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
private readonly ILibraryManager _libraryManager;
|
|
|
|
|
private readonly IMemoryStreamProvider _memoryStreamProvider;
|
|
|
|
|
private readonly IXmlReaderSettingsFactory _xmlSettings;
|
|
|
|
|
private readonly ILocalizationManager _localizationManager;
|
|
|
|
|
|
|
|
|
|
public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IMemoryStreamProvider memoryStreamProvider)
|
|
|
|
|
public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IMemoryStreamProvider memoryStreamProvider, IXmlReaderSettingsFactory xmlSettings, ILocalizationManager localizationManager)
|
|
|
|
|
{
|
|
|
|
|
_zipClient = zipClient;
|
|
|
|
|
_httpClient = httpClient;
|
|
|
|
@ -51,6 +52,8 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_libraryManager = libraryManager;
|
|
|
|
|
_memoryStreamProvider = memoryStreamProvider;
|
|
|
|
|
_xmlSettings = xmlSettings;
|
|
|
|
|
_localizationManager = localizationManager;
|
|
|
|
|
Current = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -252,7 +255,8 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanitize all files, except for extracted episode files
|
|
|
|
|
foreach (var file in Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.AllDirectories).ToList()
|
|
|
|
|
foreach (var file in _fileSystem.GetFilePaths(seriesDataPath, true).ToList()
|
|
|
|
|
.Where(i => string.Equals(Path.GetExtension(i), ".xml", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
.Where(i => !Path.GetFileName(i).StartsWith("episode-", StringComparison.OrdinalIgnoreCase)))
|
|
|
|
|
{
|
|
|
|
|
await SanitizeXmlFile(file).ConfigureAwait(false);
|
|
|
|
@ -281,20 +285,78 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
|
|
|
|
|
}).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
var doc = new XmlDocument();
|
|
|
|
|
doc.Load(result);
|
|
|
|
|
return FindSeriesId(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doc.HasChildNodes)
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
|
while (reader.Read())
|
|
|
|
|
{
|
|
|
|
|
if (reader.NodeType == XmlNodeType.Element)
|
|
|
|
|
{
|
|
|
|
|
switch (reader.Name)
|
|
|
|
|
{
|
|
|
|
|
case "Series":
|
|
|
|
|
{
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
|
{
|
|
|
|
|
return FindSeriesId(subtree);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
reader.Skip();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string FindSeriesId(XmlReader reader)
|
|
|
|
|
{
|
|
|
|
|
reader.MoveToContent();
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
|
while (reader.Read())
|
|
|
|
|
{
|
|
|
|
|
if (reader.NodeType == XmlNodeType.Element)
|
|
|
|
|
{
|
|
|
|
|
var node = doc.SelectSingleNode("//Series/seriesid");
|
|
|
|
|
switch (reader.Name)
|
|
|
|
|
{
|
|
|
|
|
case "seriesid":
|
|
|
|
|
{
|
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
if (node != null)
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
{
|
|
|
|
|
var idResult = node.InnerText;
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logger.Info("Tvdb GetSeriesByRemoteId produced id of {0}", idResult ?? string.Empty);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return idResult;
|
|
|
|
|
default:
|
|
|
|
|
reader.Skip();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -402,11 +464,11 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (DirectoryNotFoundException)
|
|
|
|
|
catch (FileNotFoundException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
catch (FileNotFoundException)
|
|
|
|
|
catch (IOException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -570,10 +632,10 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">The name.</param>
|
|
|
|
|
/// <returns>System.String.</returns>
|
|
|
|
|
internal static string GetComparableName(string name)
|
|
|
|
|
private string GetComparableName(string name)
|
|
|
|
|
{
|
|
|
|
|
name = name.ToLower();
|
|
|
|
|
name = name.Normalize(NormalizationForm.FormKD);
|
|
|
|
|
name = _localizationManager.NormalizeFormKD(name);
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
foreach (var c in name)
|
|
|
|
|
{
|
|
|
|
@ -615,17 +677,17 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
|
|
|
|
|
private void FetchSeriesInfo(MetadataResult<Series> result, string seriesXmlPath, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var settings = new XmlReaderSettings
|
|
|
|
|
{
|
|
|
|
|
CheckCharacters = false,
|
|
|
|
|
IgnoreProcessingInstructions = true,
|
|
|
|
|
IgnoreComments = true,
|
|
|
|
|
ValidationType = ValidationType.None
|
|
|
|
|
};
|
|
|
|
|
var settings = _xmlSettings.Create(false);
|
|
|
|
|
|
|
|
|
|
settings.CheckCharacters = false;
|
|
|
|
|
settings.IgnoreProcessingInstructions = true;
|
|
|
|
|
settings.IgnoreComments = true;
|
|
|
|
|
|
|
|
|
|
var episiodeAirDates = new List<DateTime>();
|
|
|
|
|
|
|
|
|
|
using (var streamReader = new StreamReader(seriesXmlPath, Encoding.UTF8))
|
|
|
|
|
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))
|
|
|
|
@ -672,6 +734,7 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0)
|
|
|
|
|
{
|
|
|
|
@ -751,15 +814,15 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
/// <param name="actorsXmlPath">The actors XML path.</param>
|
|
|
|
|
private void FetchActors(MetadataResult<Series> result, string actorsXmlPath)
|
|
|
|
|
{
|
|
|
|
|
var settings = new XmlReaderSettings
|
|
|
|
|
{
|
|
|
|
|
CheckCharacters = false,
|
|
|
|
|
IgnoreProcessingInstructions = true,
|
|
|
|
|
IgnoreComments = true,
|
|
|
|
|
ValidationType = ValidationType.None
|
|
|
|
|
};
|
|
|
|
|
var settings = _xmlSettings.Create(false);
|
|
|
|
|
|
|
|
|
|
using (var streamReader = new StreamReader(actorsXmlPath, Encoding.UTF8))
|
|
|
|
|
settings.CheckCharacters = false;
|
|
|
|
|
settings.IgnoreProcessingInstructions = true;
|
|
|
|
|
settings.IgnoreComments = true;
|
|
|
|
|
|
|
|
|
|
using (var fileStream = _fileSystem.GetFileStream(actorsXmlPath, 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))
|
|
|
|
@ -790,6 +853,7 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Fetches the data from actor node.
|
|
|
|
@ -1112,15 +1176,15 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
/// <returns>Task.</returns>
|
|
|
|
|
private async Task ExtractEpisodes(string seriesDataPath, string xmlFile, long? lastTvDbUpdateTime)
|
|
|
|
|
{
|
|
|
|
|
var settings = new XmlReaderSettings
|
|
|
|
|
{
|
|
|
|
|
CheckCharacters = false,
|
|
|
|
|
IgnoreProcessingInstructions = true,
|
|
|
|
|
IgnoreComments = true,
|
|
|
|
|
ValidationType = ValidationType.None
|
|
|
|
|
};
|
|
|
|
|
var settings = _xmlSettings.Create(false);
|
|
|
|
|
|
|
|
|
|
using (var streamReader = new StreamReader(xmlFile, Encoding.UTF8))
|
|
|
|
|
settings.CheckCharacters = false;
|
|
|
|
|
settings.IgnoreProcessingInstructions = true;
|
|
|
|
|
settings.IgnoreComments = true;
|
|
|
|
|
|
|
|
|
|
using (var fileStream = _fileSystem.GetFileStream(xmlFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
|
|
|
|
|
{
|
|
|
|
|
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
|
|
|
|
|
{
|
|
|
|
|
// Use XmlReader for best performance
|
|
|
|
|
using (var reader = XmlReader.Create(streamReader, settings))
|
|
|
|
@ -1151,16 +1215,15 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task SaveEpsiodeXml(string seriesDataPath, string xml, long? lastTvDbUpdateTime)
|
|
|
|
|
{
|
|
|
|
|
var settings = new XmlReaderSettings
|
|
|
|
|
{
|
|
|
|
|
CheckCharacters = false,
|
|
|
|
|
IgnoreProcessingInstructions = true,
|
|
|
|
|
IgnoreComments = true,
|
|
|
|
|
ValidationType = ValidationType.None
|
|
|
|
|
};
|
|
|
|
|
var settings = _xmlSettings.Create(false);
|
|
|
|
|
|
|
|
|
|
settings.CheckCharacters = false;
|
|
|
|
|
settings.IgnoreProcessingInstructions = true;
|
|
|
|
|
settings.IgnoreComments = true;
|
|
|
|
|
|
|
|
|
|
var seasonNumber = -1;
|
|
|
|
|
var episodeNumber = -1;
|
|
|
|
@ -1253,7 +1316,9 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
// Only save the file if not already there, or if the episode has changed
|
|
|
|
|
if (hasEpisodeChanged || !_fileSystem.FileExists(file))
|
|
|
|
|
{
|
|
|
|
|
using (var writer = XmlWriter.Create(file, new XmlWriterSettings
|
|
|
|
|
using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
|
|
|
|
|
{
|
|
|
|
|
using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings
|
|
|
|
|
{
|
|
|
|
|
Encoding = Encoding.UTF8,
|
|
|
|
|
Async = true
|
|
|
|
@ -1262,6 +1327,7 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
await writer.WriteRawAsync(xml).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (absoluteNumber != -1)
|
|
|
|
|
{
|
|
|
|
@ -1270,7 +1336,9 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
// Only save the file if not already there, or if the episode has changed
|
|
|
|
|
if (hasEpisodeChanged || !_fileSystem.FileExists(file))
|
|
|
|
|
{
|
|
|
|
|
using (var writer = XmlWriter.Create(file, new XmlWriterSettings
|
|
|
|
|
using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
|
|
|
|
|
{
|
|
|
|
|
using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings
|
|
|
|
|
{
|
|
|
|
|
Encoding = Encoding.UTF8,
|
|
|
|
|
Async = true
|
|
|
|
@ -1281,6 +1349,7 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the series data path.
|
|
|
|
@ -1339,7 +1408,7 @@ namespace MediaBrowser.Providers.TV
|
|
|
|
|
_fileSystem.DeleteFile(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (DirectoryNotFoundException)
|
|
|
|
|
catch (IOException)
|
|
|
|
|
{
|
|
|
|
|
// No biggie
|
|
|
|
|
}
|
|
|
|
|