diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index 3cb927716a..763d27ebaf 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -98,18 +98,6 @@ namespace MediaBrowser.Controller.Library
}
}
- ///
- /// Gets a value indicating whether this instance is hidden.
- ///
- /// true if this instance is hidden; otherwise, false.
- public bool IsHidden
- {
- get
- {
- return FileInfo.IsHidden;
- }
- }
-
///
/// Gets a value indicating whether this instance is vf.
///
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index b0e1d7fa68..4477d8de35 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -52,5 +52,7 @@ namespace MediaBrowser.Model.Globalization
IEnumerable GetLocalizationOptions();
string RemoveDiacritics(string text);
+
+ string NormalizeFormKD(string text);
}
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 92ce0a036a..ba4b624e3c 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -863,8 +863,8 @@ namespace MediaBrowser.Providers.Manager
private readonly ConcurrentQueue> _refreshQueue =
new ConcurrentQueue>();
- private readonly object _refreshTimerLock = new object();
- private Timer _refreshTimer;
+ private readonly object _refreshQueueLock = new object();
+ private bool _isProcessingRefreshQueue;
public void QueueRefresh(Guid id, MetadataRefreshOptions options)
{
@@ -874,38 +874,18 @@ namespace MediaBrowser.Providers.Manager
}
_refreshQueue.Enqueue(new Tuple(id, options));
- StartRefreshTimer();
- }
-
- private void StartRefreshTimer()
- {
- if (_disposed)
- {
- return;
- }
-
- lock (_refreshTimerLock)
- {
- if (_refreshTimer == null)
- {
- _refreshTimer = new Timer(RefreshTimerCallback, null, 100, Timeout.Infinite);
- }
- }
- }
- private void StopRefreshTimer()
- {
- lock (_refreshTimerLock)
+ lock (_refreshQueueLock)
{
- if (_refreshTimer != null)
+ if (!_isProcessingRefreshQueue)
{
- _refreshTimer.Dispose();
- _refreshTimer = null;
+ _isProcessingRefreshQueue = true;
+ Task.Run(() => StartProcessingRefreshQueue());
}
}
}
- private async void RefreshTimerCallback(object state)
+ private async Task StartProcessingRefreshQueue()
{
Tuple refreshItem;
var libraryManager = _libraryManagerFactory();
@@ -939,7 +919,10 @@ namespace MediaBrowser.Providers.Manager
}
}
- StopRefreshTimer();
+ lock (_refreshQueueLock)
+ {
+ _isProcessingRefreshQueue = false;
+ }
}
private async Task RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
@@ -1018,7 +1001,6 @@ namespace MediaBrowser.Providers.Manager
public void Dispose()
{
_disposed = true;
- StopRefreshTimer();
}
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 016fa2ebd0..e2ee40139c 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -131,7 +131,6 @@
-
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 8dc4c42902..45fcbc251e 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -134,23 +134,6 @@ namespace MediaBrowser.Providers.MediaInfo
{
cancellationToken.ThrowIfCancellationRequested();
- //var idString = item.Id.ToString("N");
- //var cachePath = Path.Combine(_appPaths.CachePath,
- // "ffprobe-video",
- // idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
-
- try
- {
- //return _json.DeserializeFromFile(cachePath);
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (DirectoryNotFoundException)
- {
- }
-
var protocol = item.LocationType == LocationType.Remote
? MediaProtocol.Http
: MediaProtocol.File;
@@ -655,7 +638,7 @@ namespace MediaBrowser.Providers.MediaInfo
/// System.Nullable{IsoType}.
private IsoType? DetermineIsoType(IIsoMount isoMount)
{
- var fileSystemEntries = Directory.EnumerateFileSystemEntries(isoMount.MountedPath).Select(Path.GetFileName).ToList();
+ var fileSystemEntries = _fileSystem.GetFileSystemEntryPaths(isoMount.MountedPath).Select(Path.GetFileName).ToList();
if (fileSystemEntries.Contains("video_ts", StringComparer.OrdinalIgnoreCase) ||
fileSystemEntries.Contains("VIDEO_TS.IFO", StringComparer.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 88128bdc7a..adb771e7c6 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -12,6 +12,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using MediaBrowser.Controller.Extensions;
namespace MediaBrowser.Providers.Music
{
@@ -159,21 +160,7 @@ namespace MediaBrowser.Providers.Music
/// true if the specified text has diacritics; otherwise, false.
private bool HasDiacritics(string text)
{
- return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
- }
-
- ///
- /// Removes the diacritics.
- ///
- /// The text.
- /// System.String.
- private string RemoveDiacritics(string text)
- {
- return String.Concat(
- text.Normalize(NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
- UnicodeCategory.NonSpacingMark)
- ).Normalize(NormalizationForm.FormC);
+ return !String.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal);
}
///
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index d0321ea339..b82320fae2 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -20,7 +20,7 @@ using MediaBrowser.Model.Globalization;
namespace MediaBrowser.Providers.TV
{
- class MissingEpisodeProvider
+ public class MissingEpisodeProvider
{
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
@@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.TV
{
break;
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
//_logger.Warn("Series files missing for series id {0}", seriesGroup.Key);
}
@@ -80,7 +80,8 @@ namespace MediaBrowser.Providers.TV
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);
- var episodeFiles = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly)
+ var episodeFiles = _fileSystem.GetFilePaths(seriesDataPath)
+ .Where(i => string.Equals(Path.GetExtension(i), ".xml", StringComparison.OrdinalIgnoreCase))
.Select(Path.GetFileNameWithoutExtension)
.Where(i => i.StartsWith("episode-", StringComparison.OrdinalIgnoreCase))
.ToList();
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
index 7f13edf602..139daf9a39 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
@@ -19,6 +19,7 @@ using System.Xml;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Xml;
namespace MediaBrowser.Providers.TV
{
@@ -35,13 +36,15 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
+ private readonly IXmlReaderSettingsFactory _xmlSettings;
- public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
+ public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger, IXmlReaderSettingsFactory xmlSettings)
{
_fileSystem = fileSystem;
_config = config;
_httpClient = httpClient;
_logger = logger;
+ _xmlSettings = xmlSettings;
Current = this;
}
@@ -49,11 +52,11 @@ namespace MediaBrowser.Providers.TV
{
var list = new List();
- // The search query must either provide an episode number or date
- if (!searchInfo.IndexNumber.HasValue && !searchInfo.PremiereDate.HasValue)
- {
- return list;
- }
+ // The search query must either provide an episode number or date
+ if (!searchInfo.IndexNumber.HasValue && !searchInfo.PremiereDate.HasValue)
+ {
+ return list;
+ }
if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds))
{
@@ -61,12 +64,13 @@ namespace MediaBrowser.Providers.TV
var searchNumbers = new EpisodeNumbers();
- if (searchInfo.IndexNumber.HasValue) {
- searchNumbers.EpisodeNumber = searchInfo.IndexNumber.Value;
- }
-
+ if (searchInfo.IndexNumber.HasValue)
+ {
+ searchNumbers.EpisodeNumber = searchInfo.IndexNumber.Value;
+ }
+
searchNumbers.SeasonNumber = searchInfo.ParentIndexNumber;
- searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;
+ searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;
try
{
@@ -93,7 +97,7 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
// Don't fail the provider because this will just keep on going and going.
}
@@ -112,19 +116,20 @@ namespace MediaBrowser.Providers.TV
var result = new MetadataResult();
result.QueriedById = true;
- if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) &&
- (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
+ if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) &&
+ (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
{
await TvdbSeriesProvider.Current.EnsureSeriesInfo(searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, searchInfo.SeriesProviderIds);
var searchNumbers = new EpisodeNumbers();
- if (searchInfo.IndexNumber.HasValue) {
- searchNumbers.EpisodeNumber = searchInfo.IndexNumber.Value;
- }
+ if (searchInfo.IndexNumber.HasValue)
+ {
+ searchNumbers.EpisodeNumber = searchInfo.IndexNumber.Value;
+ }
searchNumbers.SeasonNumber = searchInfo.ParentIndexNumber;
- searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;
+ searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;
try
{
@@ -134,7 +139,7 @@ namespace MediaBrowser.Providers.TV
{
// Don't fail the provider because this will just keep on going and going.
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
// Don't fail the provider because this will just keep on going and going.
}
@@ -155,20 +160,20 @@ namespace MediaBrowser.Providers.TV
/// List{FileInfo}.
internal List GetEpisodeXmlNodes(string seriesDataPath, EpisodeInfo searchInfo)
{
- var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath (searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage);
-
- try
- {
- return GetXmlNodes(seriesXmlPath, searchInfo);
- }
- catch (DirectoryNotFoundException)
- {
- return new List ();
- }
- catch (FileNotFoundException)
- {
- return new List ();
- }
+ var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage);
+
+ try
+ {
+ return GetXmlNodes(seriesXmlPath, searchInfo);
+ }
+ catch (FileNotFoundException)
+ {
+ return new List();
+ }
+ catch (IOException)
+ {
+ return new List();
+ }
}
private class EpisodeNumbers
@@ -188,59 +193,62 @@ namespace MediaBrowser.Providers.TV
/// Task{System.Boolean}.
private MetadataResult FetchEpisodeData(EpisodeInfo id, EpisodeNumbers searchNumbers, string seriesDataPath, CancellationToken cancellationToken)
{
- var result = new MetadataResult()
- {
- Item = new Episode
- {
- IndexNumber = id.IndexNumber,
- ParentIndexNumber = id.ParentIndexNumber,
- IndexNumberEnd = id.IndexNumberEnd
- }
- };
+ var result = new MetadataResult()
+ {
+ Item = new Episode
+ {
+ IndexNumber = id.IndexNumber,
+ ParentIndexNumber = id.ParentIndexNumber,
+ IndexNumberEnd = id.IndexNumberEnd
+ }
+ };
- var xmlNodes = GetEpisodeXmlNodes (seriesDataPath, id);
+ var xmlNodes = GetEpisodeXmlNodes(seriesDataPath, id);
- if (xmlNodes.Count > 0) {
- FetchMainEpisodeInfo(result, xmlNodes[0], cancellationToken);
+ if (xmlNodes.Count > 0)
+ {
+ FetchMainEpisodeInfo(result, xmlNodes[0], cancellationToken);
- result.HasMetadata = true;
- }
+ result.HasMetadata = true;
+ }
- foreach (var node in xmlNodes.Skip(1)) {
- FetchAdditionalPartInfo(result, node, cancellationToken);
- }
+ foreach (var node in xmlNodes.Skip(1))
+ {
+ FetchAdditionalPartInfo(result, node, cancellationToken);
+ }
return result;
}
- private List GetXmlNodes(string xmlFile, EpisodeInfo searchInfo)
- {
- var list = new List ();
+ private List GetXmlNodes(string xmlFile, EpisodeInfo searchInfo)
+ {
+ var list = new List();
- if (searchInfo.IndexNumber.HasValue)
- {
- var files = GetEpisodeXmlFiles (searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, Path.GetDirectoryName (xmlFile));
+ if (searchInfo.IndexNumber.HasValue)
+ {
+ var files = GetEpisodeXmlFiles(searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, Path.GetDirectoryName(xmlFile));
- list = files.Select (GetXmlReader).ToList ();
- }
+ list = files.Select(GetXmlReader).ToList();
+ }
- if (list.Count == 0 && searchInfo.PremiereDate.HasValue) {
- list = GetXmlNodesByPremiereDate (xmlFile, searchInfo.PremiereDate.Value);
- }
+ if (list.Count == 0 && searchInfo.PremiereDate.HasValue)
+ {
+ list = GetXmlNodesByPremiereDate(xmlFile, searchInfo.PremiereDate.Value);
+ }
- return list;
- }
+ return list;
+ }
- private List GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
- {
- var files = new List();
+ private List GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
+ {
+ var files = new List();
- if (episodeNumber == null)
- {
- return files;
- }
+ if (episodeNumber == null)
+ {
+ return files;
+ }
- var usingAbsoluteData = false;
+ var usingAbsoluteData = false;
if (seasonNumber.HasValue)
{
@@ -263,230 +271,283 @@ namespace MediaBrowser.Providers.TV
}
}
- var end = endingEpisodeNumber ?? episodeNumber;
- episodeNumber++;
+ var end = endingEpisodeNumber ?? episodeNumber;
+ episodeNumber++;
- while (episodeNumber <= end)
- {
+ while (episodeNumber <= end)
+ {
string file;
- if (usingAbsoluteData)
- {
- file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", episodeNumber));
- }
- else
- {
- file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
- }
-
- var fileInfo = _fileSystem.GetFileInfo(file);
- if (fileInfo.Exists)
- {
- files.Add(fileInfo);
- }
- else
- {
- break;
- }
-
- episodeNumber++;
- }
-
- return files;
- }
-
- private XmlReader GetXmlReader(FileSystemMetadata xmlFile)
- {
- return GetXmlReader (_fileSystem.ReadAllText(xmlFile.FullName, Encoding.UTF8));
- }
-
- private XmlReader GetXmlReader(String xml)
- {
- var streamReader = new StringReader (xml);
-
- return XmlReader.Create (streamReader, new XmlReaderSettings {
- CheckCharacters = false,
- IgnoreProcessingInstructions = true,
- IgnoreComments = true,
- ValidationType = ValidationType.None
- });
- }
-
- private List GetXmlNodesByPremiereDate(string xmlFile, DateTime premiereDate)
- {
- var list = new List ();
-
- using (var streamReader = new StreamReader (xmlFile, Encoding.UTF8)) {
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create (streamReader, new XmlReaderSettings {
- CheckCharacters = false,
- IgnoreProcessingInstructions = true,
- IgnoreComments = true,
- ValidationType = ValidationType.None
- }))
- {
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "Episode":
- {
- var outerXml = reader.ReadOuterXml();
-
- var airDate = GetEpisodeAirDate (outerXml);
-
- if (airDate.HasValue && premiereDate.Date == airDate.Value.Date)
- {
- list.Add (GetXmlReader(outerXml));
- return list;
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
- }
- }
- }
- }
-
- return list;
- }
-
- private DateTime? GetEpisodeAirDate(string xml)
- {
- using (var streamReader = new StringReader (xml))
- {
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create (streamReader, new XmlReaderSettings {
- CheckCharacters = false,
- IgnoreProcessingInstructions = true,
- IgnoreComments = true,
- ValidationType = ValidationType.None
- }))
- {
- reader.MoveToContent ();
-
- // Loop through each element
- while (reader.Read ()) {
-
- if (reader.NodeType == XmlNodeType.Element) {
- switch (reader.Name) {
-
- case "FirstAired":
- {
- var val = reader.ReadElementContentAsString ();
-
- if (!string.IsNullOrWhiteSpace (val)) {
- DateTime date;
- if (DateTime.TryParse (val, out date)) {
- date = date.ToUniversalTime ();
-
- return date;
- }
- }
-
- break;
- }
-
- default:
- reader.Skip ();
- break;
- }
- }
- }
- }
- }
- return null;
- }
+ if (usingAbsoluteData)
+ {
+ file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", episodeNumber));
+ }
+ else
+ {
+ file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
+ }
+
+ var fileInfo = _fileSystem.GetFileInfo(file);
+ if (fileInfo.Exists)
+ {
+ files.Add(fileInfo);
+ }
+ else
+ {
+ break;
+ }
+
+ episodeNumber++;
+ }
+
+ return files;
+ }
+
+ private XmlReader GetXmlReader(FileSystemMetadata xmlFile)
+ {
+ return GetXmlReader(_fileSystem.ReadAllText(xmlFile.FullName, Encoding.UTF8));
+ }
+
+ private XmlReader GetXmlReader(String xml)
+ {
+ var streamReader = new StringReader(xml);
+
+ var settings = _xmlSettings.Create(false);
+
+ settings.CheckCharacters = false;
+ settings.IgnoreProcessingInstructions = true;
+ settings.IgnoreComments = true;
+
+ return XmlReader.Create(streamReader, settings);
+ }
+
+ private List GetXmlNodesByPremiereDate(string xmlFile, DateTime premiereDate)
+ {
+ var list = new List();
+
+ using (var fileStream = _fileSystem.GetFileStream(xmlFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
+ {
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
+ {
+ // Use XmlReader for best performance
+
+ var settings = _xmlSettings.Create(false);
+
+ settings.CheckCharacters = false;
+ settings.IgnoreProcessingInstructions = true;
+ settings.IgnoreComments = true;
+
+ using (var reader = XmlReader.Create(streamReader, settings))
+ {
+ reader.MoveToContent();
+
+ // Loop through each element
+ while (reader.Read())
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "Episode":
+ {
+ var outerXml = reader.ReadOuterXml();
+
+ var airDate = GetEpisodeAirDate(outerXml);
+
+ if (airDate.HasValue && premiereDate.Date == airDate.Value.Date)
+ {
+ list.Add(GetXmlReader(outerXml));
+ return list;
+ }
+
+ break;
+ }
+
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return list;
+ }
+
+ private DateTime? GetEpisodeAirDate(string xml)
+ {
+ using (var streamReader = new StringReader(xml))
+ {
+ var settings = _xmlSettings.Create(false);
+
+ settings.CheckCharacters = false;
+ settings.IgnoreProcessingInstructions = true;
+ settings.IgnoreComments = true;
+
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
+ {
+ reader.MoveToContent();
+
+ // Loop through each element
+ while (reader.Read())
+ {
+
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+
+ case "FirstAired":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ DateTime date;
+ if (DateTime.TryParse(val, out date))
+ {
+ date = date.ToUniversalTime();
+
+ return date;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private void FetchMainEpisodeInfo(MetadataResult result, XmlReader reader, CancellationToken cancellationToken)
+ private void FetchMainEpisodeInfo(MetadataResult result, XmlReader reader, CancellationToken cancellationToken)
{
var item = result.Item;
- // Use XmlReader for best performance
- using (reader)
- {
- reader.MoveToContent();
-
- result.ResetPeople();
-
- // Loop through each element
- while (reader.Read())
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "id":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.SetProviderId(MetadataProviders.Tvdb, val);
- }
- break;
- }
-
- case "IMDB_ID":
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.SetProviderId(MetadataProviders.Imdb, val);
- }
- break;
- }
-
- case "DVD_episodenumber":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- float num;
-
- if (float.TryParse(val, NumberStyles.Any, _usCulture, out num))
- {
- item.DvdEpisodeNumber = num;
- }
- }
-
- break;
- }
-
- case "DVD_season":
- {
- var val = reader.ReadElementContentAsString();
+ // Use XmlReader for best performance
+ using (reader)
+ {
+ reader.MoveToContent();
+
+ result.ResetPeople();
+
+ // Loop through each element
+ while (reader.Read())
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- if (!string.IsNullOrWhiteSpace(val))
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "id":
{
- float num;
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.SetProviderId(MetadataProviders.Tvdb, val);
+ }
+ break;
+ }
- if (float.TryParse(val, NumberStyles.Any, _usCulture, out num))
+ case "IMDB_ID":
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
{
- item.DvdSeasonNumber = Convert.ToInt32(num);
+ item.SetProviderId(MetadataProviders.Imdb, val);
}
+ break;
}
- break;
- }
+ case "DVD_episodenumber":
+ {
+ var val = reader.ReadElementContentAsString();
- case "EpisodeNumber":
- {
- if (!item.IndexNumber.HasValue)
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ float num;
+
+ if (float.TryParse(val, NumberStyles.Any, _usCulture, out num))
+ {
+ item.DvdEpisodeNumber = num;
+ }
+ }
+
+ break;
+ }
+
+ case "DVD_season":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ float num;
+
+ if (float.TryParse(val, NumberStyles.Any, _usCulture, out num))
+ {
+ item.DvdSeasonNumber = Convert.ToInt32(num);
+ }
+ }
+
+ break;
+ }
+
+ case "EpisodeNumber":
+ {
+ if (!item.IndexNumber.HasValue)
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ int rval;
+
+ // int.TryParse is local aware, so it can be probamatic, force us culture
+ if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ {
+ item.IndexNumber = rval;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case "SeasonNumber":
+ {
+ if (!item.ParentIndexNumber.HasValue)
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ int rval;
+
+ // int.TryParse is local aware, so it can be probamatic, force us culture
+ if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ {
+ item.ParentIndexNumber = rval;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case "absolute_number":
{
var val = reader.ReadElementContentAsString();
@@ -497,17 +558,32 @@ namespace MediaBrowser.Providers.TV
// int.TryParse is local aware, so it can be probamatic, force us culture
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
{
- item.IndexNumber = rval;
+ item.AbsoluteEpisodeNumber = rval;
}
}
+
+ break;
}
- break;
- }
+ case "airsbefore_episode":
+ {
+ var val = reader.ReadElementContentAsString();
- case "SeasonNumber":
- {
- if (!item.ParentIndexNumber.HasValue)
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ int rval;
+
+ // int.TryParse is local aware, so it can be probamatic, force us culture
+ if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ {
+ item.AirsBeforeEpisodeNumber = rval;
+ }
+ }
+
+ break;
+ }
+
+ case "airsafter_season":
{
var val = reader.ReadElementContentAsString();
@@ -518,225 +594,170 @@ namespace MediaBrowser.Providers.TV
// int.TryParse is local aware, so it can be probamatic, force us culture
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
{
- item.ParentIndexNumber = rval;
+ item.AirsAfterSeasonNumber = rval;
}
}
+
+ break;
}
- break;
- }
+ case "airsbefore_season":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ int rval;
+
+ // int.TryParse is local aware, so it can be probamatic, force us culture
+ if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ {
+ item.AirsBeforeSeasonNumber = rval;
+ }
+ }
+
+ break;
+ }
+
+ case "EpisodeName":
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Name))
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.Name = val;
+ }
+ }
+ break;
+ }
+
+ case "Overview":
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Overview))
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.Overview = val;
+ }
+ }
+ break;
+ }
+ case "Rating":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ float rval;
+
+ // float.TryParse is local aware, so it can be probamatic, force us culture
+ if (float.TryParse(val, NumberStyles.AllowDecimalPoint, _usCulture, out rval))
+ {
+ item.CommunityRating = rval;
+ }
+ }
+ break;
+ }
+ case "RatingCount":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ int rval;
+
+ // int.TryParse is local aware, so it can be probamatic, force us culture
+ if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+ {
+ item.VoteCount = rval;
+ }
+ }
+
+ break;
+ }
+
+ case "FirstAired":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ DateTime date;
+ if (DateTime.TryParse(val, out date))
+ {
+ date = date.ToUniversalTime();
+
+ item.PremiereDate = date;
+ item.ProductionYear = date.Year;
+ }
+ }
+
+ break;
+ }
+
+ case "Director":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddPeople(result, val, PersonType.Director);
+ }
+ }
- case "absolute_number":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int rval;
-
- // int.TryParse is local aware, so it can be probamatic, force us culture
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
- {
- item.AbsoluteEpisodeNumber = rval;
- }
- }
-
- break;
- }
-
- case "airsbefore_episode":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int rval;
-
- // int.TryParse is local aware, so it can be probamatic, force us culture
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
- {
- item.AirsBeforeEpisodeNumber = rval;
- }
- }
-
- break;
- }
-
- case "airsafter_season":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int rval;
-
- // int.TryParse is local aware, so it can be probamatic, force us culture
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
- {
- item.AirsAfterSeasonNumber = rval;
- }
- }
-
- break;
- }
-
- case "airsbefore_season":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int rval;
-
- // int.TryParse is local aware, so it can be probamatic, force us culture
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
- {
- item.AirsBeforeSeasonNumber = rval;
- }
- }
-
- break;
- }
-
- case "EpisodeName":
- {
- if (!item.LockedFields.Contains(MetadataFields.Name))
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.Name = val;
- }
- }
- break;
- }
-
- case "Overview":
- {
- if (!item.LockedFields.Contains(MetadataFields.Overview))
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.Overview = val;
- }
- }
- break;
- }
- case "Rating":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- float rval;
-
- // float.TryParse is local aware, so it can be probamatic, force us culture
- if (float.TryParse(val, NumberStyles.AllowDecimalPoint, _usCulture, out rval))
- {
- item.CommunityRating = rval;
- }
- }
- break;
- }
- case "RatingCount":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int rval;
-
- // int.TryParse is local aware, so it can be probamatic, force us culture
- if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
- {
- item.VoteCount = rval;
- }
- }
-
- break;
- }
-
- case "FirstAired":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- DateTime date;
- if (DateTime.TryParse(val, out date))
- {
- date = date.ToUniversalTime();
-
- item.PremiereDate = date;
- item.ProductionYear = date.Year;
- }
- }
-
- break;
- }
-
- case "Director":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddPeople(result, val, PersonType.Director);
- }
- }
-
- break;
- }
- case "GuestStars":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddGuestStars(result, val);
- }
- }
-
- break;
- }
- case "Writer":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddPeople(result, val, PersonType.Writer);
- }
- }
-
- break;
- }
- case "Language":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- result.ResultLanguage = val;
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
- }
- }
- }
+ break;
+ }
+ case "GuestStars":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddGuestStars(result, val);
+ }
+ }
+
+ break;
+ }
+ case "Writer":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddPeople(result, val, PersonType.Writer);
+ }
+ }
+
+ break;
+ }
+ case "Language":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ result.ResultLanguage = val;
+ }
+
+ break;
+ }
+
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ }
+ }
}
private void AddPeople(MetadataResult result, string val, string personType)
@@ -780,99 +801,99 @@ namespace MediaBrowser.Providers.TV
}
}
- private void FetchAdditionalPartInfo(MetadataResult result, XmlReader reader, CancellationToken cancellationToken)
+ private void FetchAdditionalPartInfo(MetadataResult result, XmlReader reader, CancellationToken cancellationToken)
{
var item = result.Item;
- // Use XmlReader for best performance
- using (reader)
- {
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "EpisodeName":
- {
- if (!item.LockedFields.Contains(MetadataFields.Name))
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.Name += ", " + val;
- }
- }
- break;
- }
-
- case "Overview":
- {
- if (!item.LockedFields.Contains(MetadataFields.Overview))
- {
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.Overview += Environment.NewLine + Environment.NewLine + val;
- }
- }
- break;
- }
- case "Director":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddPeople(result, val, PersonType.Director);
- }
- }
-
- break;
- }
- case "GuestStars":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddGuestStars(result, val);
- }
- }
-
- break;
- }
- case "Writer":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (!item.LockedFields.Contains(MetadataFields.Cast))
- {
- AddPeople(result, val, PersonType.Writer);
- }
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
- }
- }
- }
+ // Use XmlReader for best performance
+ using (reader)
+ {
+ reader.MoveToContent();
+
+ // Loop through each element
+ while (reader.Read())
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "EpisodeName":
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Name))
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.Name += ", " + val;
+ }
+ }
+ break;
+ }
+
+ case "Overview":
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Overview))
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.Overview += Environment.NewLine + Environment.NewLine + val;
+ }
+ }
+ break;
+ }
+ case "Director":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddPeople(result, val, PersonType.Director);
+ }
+ }
+
+ break;
+ }
+ case "GuestStars":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddGuestStars(result, val);
+ }
+ }
+
+ break;
+ }
+ case "Writer":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ if (!item.LockedFields.Contains(MetadataFields.Cast))
+ {
+ AddPeople(result, val, PersonType.Writer);
+ }
+ }
+
+ break;
+ }
+
+ default:
+ reader.Skip();
+ break;
+ }
+ }
+ }
+ }
}
public Task GetImageResponse(string url, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
index 766fc951b0..1a611ee9b9 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
@@ -19,6 +19,7 @@ using System.Xml;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Xml;
namespace MediaBrowser.Providers.TV
{
@@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
+ private readonly IXmlReaderSettingsFactory _xmlSettings;
- public TvdbSeasonImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
+ public TvdbSeasonImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlSettings)
{
_config = config;
_httpClient = httpClient;
_fileSystem = fileSystem;
+ _xmlSettings = xmlSettings;
}
public string Name
@@ -80,13 +83,13 @@ namespace MediaBrowser.Providers.TV
try
{
- return GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, cancellationToken);
+ return GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, _xmlSettings, _fileSystem, cancellationToken);
}
catch (FileNotFoundException)
{
// No tvdb data yet. Don't blow up
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
// No tvdb data yet. Don't blow up
}
@@ -105,45 +108,46 @@ namespace MediaBrowser.Providers.TV
return seasonNumber;
}
- internal static IEnumerable GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken)
+ internal static IEnumerable GetImages(string xmlPath, string preferredLanguage, int seasonNumber, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem, CancellationToken cancellationToken)
{
- var settings = new XmlReaderSettings
- {
- CheckCharacters = false,
- IgnoreProcessingInstructions = true,
- IgnoreComments = true,
- ValidationType = ValidationType.None
- };
+ var settings = xmlReaderSettingsFactory.Create(false);
+
+ settings.CheckCharacters = false;
+ settings.IgnoreProcessingInstructions = true;
+ settings.IgnoreComments = true;
var list = new List();
- using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
+ using (var fileStream = fileSystem.GetFileStream(xmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
{
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader, settings))
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- cancellationToken.ThrowIfCancellationRequested();
+ reader.MoveToContent();
- if (reader.NodeType == XmlNodeType.Element)
+ // Loop through each element
+ while (reader.Read())
{
- switch (reader.Name)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
{
- case "Banner":
- {
- using (var subtree = reader.ReadSubtree())
+ switch (reader.Name)
+ {
+ case "Banner":
{
- AddImage(subtree, list, seasonNumber);
+ using (var subtree = reader.ReadSubtree())
+ {
+ AddImage(subtree, list, seasonNumber);
+ }
+ break;
}
+ default:
+ reader.Skip();
break;
- }
- default:
- reader.Skip();
- break;
+ }
}
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
index b3a84f304a..f6cdacd424 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
@@ -19,6 +19,7 @@ using System.Xml;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Xml;
namespace MediaBrowser.Providers.TV
{
@@ -28,12 +29,14 @@ namespace MediaBrowser.Providers.TV
private readonly IHttpClient _httpClient;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IFileSystem _fileSystem;
+ private readonly IXmlReaderSettingsFactory _xmlReaderSettingsFactory;
- public TvdbSeriesImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
+ public TvdbSeriesImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
{
_config = config;
_httpClient = httpClient;
_fileSystem = fileSystem;
+ _xmlReaderSettingsFactory = xmlReaderSettingsFactory;
}
public string Name
@@ -75,7 +78,7 @@ namespace MediaBrowser.Providers.TV
{
var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(item.ProviderIds);
if (seriesOffset != null && seriesOffset.Value != 0)
- return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, cancellationToken);
+ return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, _xmlReaderSettingsFactory, _fileSystem, cancellationToken);
return GetImages(path, language, cancellationToken);
}
@@ -83,7 +86,7 @@ namespace MediaBrowser.Providers.TV
{
// No tvdb data yet. Don't blow up
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
// No tvdb data yet. Don't blow up
}
@@ -94,43 +97,44 @@ namespace MediaBrowser.Providers.TV
private IEnumerable GetImages(string xmlPath, string preferredLanguage, CancellationToken cancellationToken)
{
- var settings = new XmlReaderSettings
- {
- CheckCharacters = false,
- IgnoreProcessingInstructions = true,
- IgnoreComments = true,
- ValidationType = ValidationType.None
- };
+ var settings = _xmlReaderSettingsFactory.Create(false);
+
+ settings.CheckCharacters = false;
+ settings.IgnoreProcessingInstructions = true;
+ settings.IgnoreComments = true;
var list = new List();
- using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
+ using (var fileStream = _fileSystem.GetFileStream(xmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
{
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader, settings))
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- cancellationToken.ThrowIfCancellationRequested();
+ reader.MoveToContent();
- if (reader.NodeType == XmlNodeType.Element)
+ // Loop through each element
+ while (reader.Read())
{
- switch (reader.Name)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
{
- case "Banner":
- {
- using (var subtree = reader.ReadSubtree())
+ switch (reader.Name)
+ {
+ case "Banner":
{
- AddImage(subtree, list);
+ using (var subtree = reader.ReadSubtree())
+ {
+ AddImage(subtree, list);
+ }
+ break;
}
+ default:
+ reader.Skip();
break;
- }
- default:
- reader.Skip();
- break;
+ }
}
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index afa223f63c..3618e4ddc2 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -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);
+ }
+ }
+
+ 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;
- if (doc.HasChildNodes)
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- var node = doc.SelectSingleNode("//Series/seriesid");
+ 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();
- if (node != null)
+ // Loop through each element
+ while (reader.Read())
+ {
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
{
- var idResult = node.InnerText;
+ case "seriesid":
+ {
+ var val = reader.ReadElementContentAsString();
- _logger.Info("Tvdb GetSeriesByRemoteId produced id of {0}", idResult ?? string.Empty);
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ return val;
+ }
+
+ 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
///
/// The name.
/// System.String.
- 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,58 +677,59 @@ namespace MediaBrowser.Providers.TV
private void FetchSeriesInfo(MetadataResult 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();
- using (var streamReader = new StreamReader(seriesXmlPath, Encoding.UTF8))
+ using (var fileStream = _fileSystem.GetFileStream(seriesXmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
{
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader, settings))
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- cancellationToken.ThrowIfCancellationRequested();
+ reader.MoveToContent();
- if (reader.NodeType == XmlNodeType.Element)
+ // Loop through each element
+ while (reader.Read())
{
- switch (reader.Name)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
{
- case "Series":
- {
- using (var subtree = reader.ReadSubtree())
+ switch (reader.Name)
+ {
+ case "Series":
{
- FetchDataFromSeriesNode(result, subtree, cancellationToken);
+ using (var subtree = reader.ReadSubtree())
+ {
+ FetchDataFromSeriesNode(result, subtree, cancellationToken);
+ }
+ break;
}
- break;
- }
- case "Episode":
- {
- using (var subtree = reader.ReadSubtree())
+ case "Episode":
{
- var date = GetFirstAiredDateFromEpisodeNode(subtree, cancellationToken);
-
- if (date.HasValue)
+ using (var subtree = reader.ReadSubtree())
{
- episiodeAirDates.Add(date.Value);
+ var date = GetFirstAiredDateFromEpisodeNode(subtree, cancellationToken);
+
+ if (date.HasValue)
+ {
+ episiodeAirDates.Add(date.Value);
+ }
}
+ break;
}
- break;
- }
- default:
- reader.Skip();
- break;
+ default:
+ reader.Skip();
+ break;
+ }
}
}
}
@@ -751,39 +814,40 @@ namespace MediaBrowser.Providers.TV
/// The actors XML path.
private void FetchActors(MetadataResult result, string actorsXmlPath)
{
- 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;
- using (var streamReader = new StreamReader(actorsXmlPath, Encoding.UTF8))
+ using (var fileStream = _fileSystem.GetFileStream(actorsXmlPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
{
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader, settings))
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- if (reader.NodeType == XmlNodeType.Element)
+ reader.MoveToContent();
+
+ // Loop through each element
+ while (reader.Read())
{
- switch (reader.Name)
+ if (reader.NodeType == XmlNodeType.Element)
{
- case "Actor":
- {
- using (var subtree = reader.ReadSubtree())
+ switch (reader.Name)
+ {
+ case "Actor":
{
- FetchDataFromActorNode(result, subtree);
+ using (var subtree = reader.ReadSubtree())
+ {
+ FetchDataFromActorNode(result, subtree);
+ }
+ break;
}
+ default:
+ reader.Skip();
break;
- }
- default:
- reader.Skip();
- break;
+ }
}
}
}
@@ -1112,39 +1176,40 @@ namespace MediaBrowser.Providers.TV
/// Task.
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))
{
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader, settings))
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
- reader.MoveToContent();
-
- // Loop through each element
- while (reader.Read())
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(streamReader, settings))
{
- if (reader.NodeType == XmlNodeType.Element)
+ reader.MoveToContent();
+
+ // Loop through each element
+ while (reader.Read())
{
- switch (reader.Name)
+ if (reader.NodeType == XmlNodeType.Element)
{
- case "Episode":
- {
- var outerXml = reader.ReadOuterXml();
+ switch (reader.Name)
+ {
+ case "Episode":
+ {
+ var outerXml = reader.ReadOuterXml();
- await SaveEpsiodeXml(seriesDataPath, outerXml, lastTvDbUpdateTime).ConfigureAwait(false);
- break;
- }
+ await SaveEpsiodeXml(seriesDataPath, outerXml, lastTvDbUpdateTime).ConfigureAwait(false);
+ break;
+ }
- default:
- reader.Skip();
- break;
+ default:
+ reader.Skip();
+ break;
+ }
}
}
}
@@ -1154,13 +1219,11 @@ 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,13 +1316,16 @@ 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
- {
- Encoding = Encoding.UTF8,
- Async = true
- }))
+ using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
{
- await writer.WriteRawAsync(xml).ConfigureAwait(false);
+ using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings
+ {
+ Encoding = Encoding.UTF8,
+ Async = true
+ }))
+ {
+ await writer.WriteRawAsync(xml).ConfigureAwait(false);
+ }
}
}
@@ -1270,13 +1336,16 @@ 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
- {
- Encoding = Encoding.UTF8,
- Async = true
- }))
+ using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true))
{
- await writer.WriteRawAsync(xml).ConfigureAwait(false);
+ using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings
+ {
+ Encoding = Encoding.UTF8,
+ Async = true
+ }))
+ {
+ await writer.WriteRawAsync(xml).ConfigureAwait(false);
+ }
}
}
}
@@ -1339,7 +1408,7 @@ namespace MediaBrowser.Providers.TV
_fileSystem.DeleteFile(file);
}
}
- catch (DirectoryNotFoundException)
+ catch (IOException)
{
// No biggie
}
diff --git a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
index 0b1878c060..e4db98b3fc 100644
--- a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
+++ b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
@@ -118,6 +118,11 @@ namespace MediaBrowser.Server.Implementations.Localization
).Normalize(NormalizationForm.FormC);
}
+ public string NormalizeFormKD(string text)
+ {
+ return text.Normalize(NormalizationForm.FormKD);
+ }
+
///
/// Gets the cultures.
///
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 23d373ac45..71e964eec6 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -278,6 +278,7 @@
+
@@ -383,6 +384,10 @@
{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}
MediaBrowser.Model
+
+ {442b5058-dcaf-4263-bb6a-f21e31120a1b}
+ MediaBrowser.Providers
+
{d7453b88-2266-4805-b39b-2b5a2a33e1ba}
Mono.Nat
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Server.Implementations/TV/SeriesPostScanTask.cs
similarity index 97%
rename from MediaBrowser.Providers/TV/SeriesPostScanTask.cs
rename to MediaBrowser.Server.Implementations/TV/SeriesPostScanTask.cs
index 018f4aa944..f4ee3e1afc 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/TV/SeriesPostScanTask.cs
@@ -1,23 +1,22 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
+using MediaBrowser.Providers.TV;
-namespace MediaBrowser.Providers.TV
+namespace MediaBrowser.Server.Implementations.TV
{
class SeriesGroup : List, IGrouping
{