ソースを参照

continue reworking provider project

Luke Pulverenti 8 年 前
コミット
872aec9352

+ 0 - 12
MediaBrowser.Controller/Library/ItemResolveArgs.cs

@@ -98,18 +98,6 @@ namespace MediaBrowser.Controller.Library
             }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is hidden.
-        /// </summary>
-        /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
-        public bool IsHidden
-        {
-            get
-            {
-                return FileInfo.IsHidden;
-            }
-        }
-
         /// <summary>
         /// Gets a value indicating whether this instance is vf.
         /// </summary>

+ 2 - 0
MediaBrowser.Model/Globalization/ILocalizationManager.cs

@@ -52,5 +52,7 @@ namespace MediaBrowser.Model.Globalization
         IEnumerable<LocalizatonOption> GetLocalizationOptions();
 
         string RemoveDiacritics(string text);
+
+        string NormalizeFormKD(string text);
     }
 }

+ 11 - 29
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -863,8 +863,8 @@ namespace MediaBrowser.Providers.Manager
         private readonly ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue =
             new ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>>();
 
-        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<Guid, MetadataRefreshOptions>(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<Guid, MetadataRefreshOptions> 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();
         }
     }
 }

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

@@ -131,7 +131,6 @@
     <Compile Include="TV\FanArt\FanArtSeasonProvider.cs" />
     <Compile Include="TV\FanArt\FanartSeriesProvider.cs" />
     <Compile Include="TV\MissingEpisodeProvider.cs" />
-    <Compile Include="TV\SeriesPostScanTask.cs" />
     <Compile Include="TV\TheMovieDb\MovieDbProviderBase.cs" />
     <Compile Include="TV\TheMovieDb\MovieDbEpisodeImageProvider.cs" />
     <Compile Include="TV\TheMovieDb\MovieDbSeasonProvider.cs" />

+ 1 - 18
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<Model.MediaInfo.MediaInfo>(cachePath);
-            }
-            catch (FileNotFoundException)
-            {
-
-            }
-            catch (DirectoryNotFoundException)
-            {
-            }
-
             var protocol = item.LocationType == LocationType.Remote
                 ? MediaProtocol.Http
                 : MediaProtocol.File;
@@ -655,7 +638,7 @@ namespace MediaBrowser.Providers.MediaInfo
         /// <returns>System.Nullable{IsoType}.</returns>
         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))

+ 2 - 15
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
         /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
         private bool HasDiacritics(string text)
         {
-            return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
-        }
-
-        /// <summary>
-        /// Removes the diacritics.
-        /// </summary>
-        /// <param name="text">The text.</param>
-        /// <returns>System.String.</returns>
-        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);
         }
 
         /// <summary>

+ 4 - 3
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();

ファイルの差分が大きいため隠しています
+ 519 - 498
MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs


+ 33 - 29
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<RemoteImageInfo> GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken)
+        internal static IEnumerable<RemoteImageInfo> 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<RemoteImageInfo>();
 
-            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;
+                                }
                             }
                         }
                     }

+ 32 - 28
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<RemoteImageInfo> 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<RemoteImageInfo>();
 
-            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;
+                                }
                             }
                         }
                     }

+ 190 - 121
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
         /// </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,58 +677,59 @@ 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))
             {
-                // 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
         /// <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);
+
+            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
         /// <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))
             {
-                // 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
             }

+ 5 - 0
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);
+        }
+
         /// <summary>
         /// Gets the cultures.
         /// </summary>

+ 5 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -278,6 +278,7 @@
     <Compile Include="Sync\SyncJobOptions.cs" />
     <Compile Include="Sync\SyncNotificationEntryPoint.cs" />
     <Compile Include="Threading\PeriodicTimer.cs" />
+    <Compile Include="TV\SeriesPostScanTask.cs" />
     <Compile Include="UserViews\CollectionFolderImageProvider.cs" />
     <Compile Include="UserViews\DynamicImageProvider.cs" />
     <Compile Include="News\NewsEntryPoint.cs" />
@@ -383,6 +384,10 @@
       <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
+      <Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
+      <Name>MediaBrowser.Providers</Name>
+    </ProjectReference>
     <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
       <Project>{d7453b88-2266-4805-b39b-2b5a2a33e1ba}</Project>
       <Name>Mono.Nat</Name>

+ 10 - 11
MediaBrowser.Providers/TV/SeriesPostScanTask.cs → 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<Series>, IGrouping<string, Series>
     {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません