diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 55c6f6455e..6365bd2940 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -51,6 +51,7 @@ namespace Emby.Drawing private readonly IJsonSerializer _jsonSerializer; private readonly IServerApplicationPaths _appPaths; private readonly IImageEncoder _imageEncoder; + private readonly SemaphoreSlim _imageProcessingSemaphore; public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IImageEncoder imageEncoder) { @@ -88,6 +89,8 @@ namespace Emby.Drawing } _cachedImagedSizes = new ConcurrentDictionary(sizeDictionary); + var count = Environment.ProcessorCount; + _imageProcessingSemaphore = new SemaphoreSlim(count, count); } public string[] SupportedInputFormats @@ -201,6 +204,8 @@ namespace Emby.Drawing await semaphore.WaitAsync().ConfigureAwait(false); + var imageProcessingLockTaken = false; + try { CheckDisposed(); @@ -212,11 +217,20 @@ namespace Emby.Drawing Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); + await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); + + imageProcessingLockTaken = true; + _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options); } } finally { + if (imageProcessingLockTaken) + { + _imageProcessingSemaphore.Release(); + } + semaphore.Release(); } @@ -254,10 +268,15 @@ namespace Emby.Drawing return GetResult(croppedImagePath); } + var imageProcessingLockTaken = false; + try { Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath)); + await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); + imageProcessingLockTaken = true; + _imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath); } catch (Exception ex) @@ -269,6 +288,11 @@ namespace Emby.Drawing } finally { + if (imageProcessingLockTaken) + { + _imageProcessingSemaphore.Release(); + } + semaphore.Release(); } @@ -592,13 +616,25 @@ namespace Emby.Drawing return enhancedImagePath; } + var imageProcessingLockTaken = false; + try { Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath)); + + await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); + + imageProcessingLockTaken = true; + await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false); } finally { + if (imageProcessingLockTaken) + { + _imageProcessingSemaphore.Release(); + } + semaphore.Release(); } @@ -717,9 +753,18 @@ namespace Emby.Drawing return Path.Combine(path, filename); } - public void CreateImageCollage(ImageCollageOptions options) + public async Task CreateImageCollage(ImageCollageOptions options) { - _imageEncoder.CreateImageCollage(options); + await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); + + try + { + _imageEncoder.CreateImageCollage(options); + } + finally + { + _imageProcessingSemaphore.Release(); + } } public IEnumerable GetSupportedEnhancers(IHasImages item, ImageType imageType) diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 685d2706da..aeb8173921 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -104,6 +104,6 @@ namespace MediaBrowser.Controller.Drawing /// Creates the image collage. /// /// The options. - void CreateImageCollage(ImageCollageOptions options); + Task CreateImageCollage(ImageCollageOptions options); } } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index c44a7c94d2..afd67eb153 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Model.Configuration DownMixAudioBoost = 2; EncodingQuality = EncodingQuality.Auto; EnableThrottling = true; - ThrottleThresholdSeconds = 90; + ThrottleThresholdSeconds = 120; } } } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 3fa0df7608..2106a58dee 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints NatUtility.UnhandledException += NatUtility_UnhandledException; NatUtility.StartDiscovery(); - _timer = new Timer(s => _createdRules = new List(), null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3)); + _timer = new Timer(s => _createdRules = new List(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); _lastConfigIdentifier = GetConfigIdentifier(); @@ -97,17 +97,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e) { - //var ex = e.ExceptionObject as Exception; + var ex = e.ExceptionObject as Exception; - //if (ex == null) - //{ - // _logger.Error("Unidentified error reported by Mono.Nat"); - //} - //else - //{ - // // Seeing some blank exceptions coming through here - // _logger.ErrorException("Error reported by Mono.Nat: ", ex); - //} + if (ex == null) + { + //_logger.Error("Unidentified error reported by Mono.Nat"); + } + else + { + // Seeing some blank exceptions coming through here + _logger.ErrorException("Error reported by Mono.Nat: ", ex); + } } void NatUtility_DeviceFound(object sender, DeviceEventArgs e) diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 03471a8e9b..02e1795f36 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -345,7 +345,7 @@ namespace MediaBrowser.Server.Implementations.Library { var name = MakeValidUsername(Environment.UserName); - var user = InstantiateNewUser(name, false); + var user = InstantiateNewUser(name); user.DateLastSaved = DateTime.UtcNow; @@ -552,7 +552,7 @@ namespace MediaBrowser.Server.Implementations.Library try { - var user = InstantiateNewUser(name, true); + var user = InstantiateNewUser(name); var list = Users.ToList(); list.Add(user); @@ -697,21 +697,13 @@ namespace MediaBrowser.Server.Implementations.Library /// Instantiates the new user. /// /// The name. - /// if set to true [check identifier]. /// User. - private User InstantiateNewUser(string name, bool checkId) + private User InstantiateNewUser(string name) { - var id = ("MBUser" + name).GetMD5(); - - if (checkId && Users.Select(i => i.Id).Contains(id)) - { - id = Guid.NewGuid(); - } - return new User { Name = name, - Id = id, + Id = Guid.NewGuid(), DateCreated = DateTime.UtcNow, DateModified = DateTime.UtcNow, UsesIdForConfigurationPath = true diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs index 15c43213f7..be71a6408a 100644 --- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs @@ -80,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.Photos { var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png"); Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - var imageCreated = CreateImage(item, itemsWithImages, outputPath, imageType, 0); + var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false); if (!imageCreated) { @@ -103,9 +103,9 @@ namespace MediaBrowser.Server.Implementations.Photos return parts.GetMD5().ToString("N"); } - protected void CreateThumbCollage(IHasImages primaryItem, List items, string outputPath, bool drawText) + protected Task CreateThumbCollage(IHasImages primaryItem, List items, string outputPath, bool drawText) { - CreateCollage(primaryItem, items, outputPath, 960, 540, drawText, primaryItem.Name); + return CreateCollage(primaryItem, items, outputPath, 960, 540, drawText, primaryItem.Name); } protected virtual IEnumerable GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable items) @@ -115,22 +115,22 @@ namespace MediaBrowser.Server.Implementations.Photos .Where(i => !string.IsNullOrWhiteSpace(i)); } - protected void CreatePosterCollage(IHasImages primaryItem, List items, string outputPath) + protected Task CreatePosterCollage(IHasImages primaryItem, List items, string outputPath) { - CreateCollage(primaryItem, items, outputPath, 600, 900, true, primaryItem.Name); + return CreateCollage(primaryItem, items, outputPath, 600, 900, true, primaryItem.Name); } - protected void CreateSquareCollage(IHasImages primaryItem, List items, string outputPath, bool drawText) + protected Task CreateSquareCollage(IHasImages primaryItem, List items, string outputPath, bool drawText) { - CreateCollage(primaryItem, items, outputPath, 800, 800, drawText, primaryItem.Name); + return CreateCollage(primaryItem, items, outputPath, 800, 800, drawText, primaryItem.Name); } - protected void CreateThumbCollage(IHasImages primaryItem, List items, string outputPath, int width, int height, bool drawText, string text) + protected Task CreateThumbCollage(IHasImages primaryItem, List items, string outputPath, int width, int height, bool drawText, string text) { - CreateCollage(primaryItem, items, outputPath, width, height, drawText, text); + return CreateCollage(primaryItem, items, outputPath, width, height, drawText, text); } - private void CreateCollage(IHasImages primaryItem, List items, string outputPath, int width, int height, bool drawText, string text) + private Task CreateCollage(IHasImages primaryItem, List items, string outputPath, int width, int height, bool drawText, string text) { Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); @@ -143,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.Photos InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray() }; - ImageProcessor.CreateImageCollage(options); + return ImageProcessor.CreateImageCollage(options); } public string Name @@ -151,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.Photos get { return "Dynamic Image Provider"; } } - protected virtual bool CreateImage(IHasImages item, + protected virtual async Task CreateImage(IHasImages item, List itemsWithImages, string outputPath, ImageType imageType, @@ -166,7 +166,7 @@ namespace MediaBrowser.Server.Implementations.Photos if (imageType == ImageType.Thumb) { - CreateThumbCollage(item, itemsWithImages, outputPath, drawText); + await CreateThumbCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false); return true; } @@ -174,15 +174,15 @@ namespace MediaBrowser.Server.Implementations.Photos { if (item is UserView) { - CreateSquareCollage(item, itemsWithImages, outputPath, drawText); + await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false); } else if (item is PhotoAlbum || item is Playlist) { - CreateSquareCollage(item, itemsWithImages, outputPath, drawText); + await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false); } else { - CreatePosterCollage(item, itemsWithImages, outputPath); + await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } return true; @@ -234,7 +234,7 @@ namespace MediaBrowser.Server.Implementations.Photos protected virtual List GetFinalItems(List items, int limit) { // Rotate the images once every x days - var random = DateTime.Now.DayOfYear % 5; + var random = DateTime.Now.DayOfYear % 7; return items .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5()) diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs index 4a4d90d14f..24dc2cc1d2 100644 --- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -216,7 +216,7 @@ namespace MediaBrowser.Server.Implementations.UserViews return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty); } - protected override bool CreateImage(IHasImages item, List itemsWithImages, string outputPath, ImageType imageType, int imageIndex) + protected override async Task CreateImage(IHasImages item, List itemsWithImages, string outputPath, ImageType imageType, int imageIndex) { var view = (UserView)item; if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) @@ -226,11 +226,11 @@ namespace MediaBrowser.Server.Implementations.UserViews return false; } - CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name); + await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name).ConfigureAwait(false); return true; } - return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex); + return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false); } protected override IEnumerable GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable items)