diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs index 84f9f8827..6e33f52e6 100644 --- a/MediaBrowser.Controller/Dto/DtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs @@ -664,22 +664,6 @@ namespace MediaBrowser.Controller.Dto return null; } - /// - /// Gets the library update info. - /// - /// The instance containing the event data. - /// LibraryUpdateInfo. - public static LibraryUpdateInfo GetLibraryUpdateInfo(ChildrenChangedEventArgs changeEvent) - { - return new LibraryUpdateInfo - { - Folder = GetBaseItemInfo(changeEvent.Folder), - ItemsAdded = changeEvent.ItemsAdded.Select(GetBaseItemInfo), - ItemsRemoved = changeEvent.ItemsRemoved.Select(i => i.Id), - ItemsUpdated = changeEvent.ItemsUpdated.Select(i => i.Id) - }; - } - /// /// Converts a UserItemData to a DTOUserItemData /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b7508a641..f8db07fe3 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -659,7 +659,7 @@ namespace MediaBrowser.Controller.Entities foreach (var tuple in list) { - if (tasks.Count > 50) + if (tasks.Count > 5) { await Task.WhenAll(tasks).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index e0091cd80..d5df769a9 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -49,8 +49,17 @@ namespace MediaBrowser.Controller.Providers throw new ArgumentNullException(); } + var settings = new XmlReaderSettings + { + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + IgnoreWhitespace = true, + ValidationType = ValidationType.None + }; + // Use XmlReader for best performance - using (var reader = XmlReader.Create(metadataFile)) + using (var reader = XmlReader.Create(metadataFile, settings)) { reader.MoveToContent(); @@ -93,7 +102,7 @@ namespace MediaBrowser.Controller.Providers { var type = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none",StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none", StringComparison.OrdinalIgnoreCase)) { item.DisplayMediaType = type; } diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 3f71e398a..b69ece418 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Providers /// protected readonly Guid Id; + protected static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(5, 5); + /// /// Supportses the specified item. /// diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index d2c2d5b15..99744390a 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers /// Task{System.Boolean}. public override Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - return Task.Run(() => Fetch(item, cancellationToken)); + return Fetch(item, cancellationToken); } /// @@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers /// The item. /// The cancellation token. /// true if XXXX, false otherwise - private bool Fetch(BaseItem item, CancellationToken cancellationToken) + private async Task Fetch(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -76,7 +76,18 @@ namespace MediaBrowser.Controller.Providers if (metadataFile.HasValue) { var path = metadataFile.Value.Path; - new BaseItemXmlParser(Logger).Fetch((Folder)item, path, cancellationToken); + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + new BaseItemXmlParser(Logger).Fetch((Folder)item, path, cancellationToken); + } + finally + { + XmlParsingResourcePool.Release(); + } + SetLastRefreshed(item, DateTime.UtcNow); return true; } diff --git a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs index 279533636..1ed003e87 100644 --- a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers.Movies /// Task{System.Boolean}. public override Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - return Task.Run(() => Fetch(item, cancellationToken)); + return Fetch(item, cancellationToken); } /// @@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers.Movies /// The item. /// The cancellation token. /// true if XXXX, false otherwise - private bool Fetch(BaseItem item, CancellationToken cancellationToken) + private async Task Fetch(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -77,14 +77,25 @@ namespace MediaBrowser.Controller.Providers.Movies { var path = metadataFile.Value.Path; var boxset = item as BoxSet; - if (boxset != null) + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try { - new BaseItemXmlParser(Logger).Fetch(boxset, path, cancellationToken); + if (boxset != null) + { + new BaseItemXmlParser(Logger).Fetch(boxset, path, cancellationToken); + } + else + { + new BaseItemXmlParser(Logger).Fetch((Movie)item, path, cancellationToken); + } } - else + finally { - new BaseItemXmlParser(Logger).Fetch((Movie)item, path, cancellationToken); + XmlParsingResourcePool.Release(); } + SetLastRefreshed(item, DateTime.UtcNow); return true; } diff --git a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs index 483d1ddce..e6fb2eb4f 100644 --- a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs @@ -15,7 +15,8 @@ namespace MediaBrowser.Controller.Providers.TV /// public class EpisodeProviderFromXml : BaseMetadataProvider { - public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) : base(logManager, configurationManager) + public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) + : base(logManager, configurationManager) { } @@ -55,7 +56,7 @@ namespace MediaBrowser.Controller.Providers.TV /// Task{System.Boolean}. public override Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - return Task.Run(() => Fetch(item, cancellationToken)); + return Fetch(item, cancellationToken); } /// @@ -84,42 +85,31 @@ namespace MediaBrowser.Controller.Providers.TV /// The item. /// The cancellation token. /// true if XXXX, false otherwise - private bool Fetch(BaseItem item, CancellationToken cancellationToken) + private async Task Fetch(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - + var metadataFile = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml")); - var episode = (Episode)item; - - if (!FetchMetadata(episode, item.ResolveArgs.Parent, metadataFile, cancellationToken)) - { - // Don't set last refreshed if we didn't do anything - return false; - } - - SetLastRefreshed(item, DateTime.UtcNow); - return true; - } - - /// - /// Fetches the metadata. - /// - /// The item. - /// The parent. - /// The metadata file. - /// The cancellation token. - /// true if XXXX, false otherwise - private bool FetchMetadata(Episode item, Folder parent, string metadataFile, CancellationToken cancellationToken) - { - var file = parent.ResolveArgs.GetMetaFileByPath(metadataFile); + var file = item.ResolveArgs.Parent.ResolveArgs.GetMetaFileByPath(metadataFile); if (!file.HasValue) { return false; } - new EpisodeXmlParser(Logger).Fetch(item, metadataFile, cancellationToken); + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + new EpisodeXmlParser(Logger).Fetch((Episode)item, metadataFile, cancellationToken); + } + finally + { + XmlParsingResourcePool.Release(); + } + + SetLastRefreshed(item, DateTime.UtcNow); return true; } } diff --git a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs index 8e42e9d55..556ef24c9 100644 --- a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs @@ -59,7 +59,7 @@ namespace MediaBrowser.Controller.Providers.TV /// Task{System.Boolean}. public override Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - return Task.Run(() => Fetch(item, cancellationToken)); + return Fetch(item, cancellationToken); } /// @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Providers.TV /// The item. /// The cancellation token. /// true if XXXX, false otherwise - private bool Fetch(BaseItem item, CancellationToken cancellationToken) + private async Task Fetch(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -78,7 +78,17 @@ namespace MediaBrowser.Controller.Providers.TV { var path = metadataFile.Value.Path; - new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken); + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken); + } + finally + { + XmlParsingResourcePool.Release(); + } + SetLastRefreshed(item, DateTime.UtcNow); return true; diff --git a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs index 1ad117009..e98b7ae2c 100644 --- a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs +++ b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs @@ -9,27 +9,35 @@ namespace MediaBrowser.Model.Entities public class LibraryUpdateInfo { /// - /// Gets or sets the folder. + /// Gets or sets the folders. /// - /// The folder. - public BaseItemInfo Folder { get; set; } + /// The folders. + public List Folders { get; set; } /// /// Gets or sets the items added. /// /// The items added. - public IEnumerable ItemsAdded { get; set; } + public List ItemsAdded { get; set; } /// /// Gets or sets the items removed. /// /// The items removed. - public IEnumerable ItemsRemoved { get; set; } + public List ItemsRemoved { get; set; } /// /// Gets or sets the items updated. /// /// The items updated. - public IEnumerable ItemsUpdated { get; set; } + public List ItemsUpdated { get; set; } + + public LibraryUpdateInfo() + { + Folders = new List(); + ItemsAdded = new List(); + ItemsRemoved = new List(); + ItemsUpdated = new List(); + } } } diff --git a/MediaBrowser.Model/Weather/WeatherInfo.cs b/MediaBrowser.Model/Weather/WeatherInfo.cs index b423380f5..57a9432f6 100644 --- a/MediaBrowser.Model/Weather/WeatherInfo.cs +++ b/MediaBrowser.Model/Weather/WeatherInfo.cs @@ -21,5 +21,13 @@ namespace MediaBrowser.Model.Weather /// The forecasts. [ProtoMember(2)] public WeatherForecast[] Forecasts { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public WeatherInfo() + { + Forecasts = new WeatherForecast[] {}; + } } } diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index 08e2eb774..709c21f50 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder /// /// The audio image resource pool /// - private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(2, 2); + private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(1, 1); /// /// The _subtitle extraction resource pool diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs index db809a47b..66ca9db9a 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs @@ -147,6 +147,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks { // Image is already in the cache item.PrimaryImagePath = path; + + await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index d46d4ec8a..7f158f1f2 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -60,40 +61,27 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// The cancellation token. /// The progress. /// Task. - public Task Execute(CancellationToken cancellationToken, IProgress progress) + public async Task Execute(CancellationToken cancellationToken, IProgress progress) { - var videos = _libraryManager.RootFolder.RecursiveChildren.OfType