diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 12aac0ccbd..a7bcbf821e 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Audio/{Id}/stream.flac", "GET")]
[Route("/Audio/{Id}/stream.ogg", "GET")]
[Route("/Audio/{Id}/stream.oga", "GET")]
- [Route("/Audio/{Id}/stream.webma", "GET")]
+ [Route("/Audio/{Id}/stream.webm", "GET")]
[Route("/Audio/{Id}/stream", "GET")]
[Route("/Audio/{Id}/stream.mp3", "HEAD")]
[Route("/Audio/{Id}/stream.wma", "HEAD")]
@@ -23,7 +23,7 @@ namespace MediaBrowser.Api.Playback.Progressive
[Route("/Audio/{Id}/stream.flac", "HEAD")]
[Route("/Audio/{Id}/stream.ogg", "HEAD")]
[Route("/Audio/{Id}/stream.oga", "HEAD")]
- [Route("/Audio/{Id}/stream.webma", "HEAD")]
+ [Route("/Audio/{Id}/stream.webm", "HEAD")]
[Route("/Audio/{Id}/stream", "HEAD")]
[Api(Description = "Gets an audio stream")]
public class GetAudioStream : StreamRequest
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index f2a9ca24b5..a27e3cc325 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -167,11 +167,9 @@ namespace MediaBrowser.Api
{
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
- var tasks = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).ToArray();
+ var users = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).ToArray();
- var task = Task.WhenAll(tasks);
-
- return ToOptimizedResult(task.Result);
+ return ToOptimizedResult(users);
}
///
@@ -188,7 +186,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
- var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(user).Result;
+ var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(user);
return ToOptimizedResult(result);
}
@@ -302,7 +300,7 @@ namespace MediaBrowser.Api
newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer);
- var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(newUser).Result;
+ var result = new DtoBuilder(Logger, _libraryManager, _userManager).GetUserDto(newUser);
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Common/Extensions/NamedLock.cs b/MediaBrowser.Common/Extensions/NamedLock.cs
deleted file mode 100644
index d0164c70d0..0000000000
--- a/MediaBrowser.Common/Extensions/NamedLock.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Extensions
-{
- ///
- /// Class NamedLock
- ///
- public class NamedLock : IDisposable
- {
- ///
- /// The _locks
- ///
- private readonly Dictionary _locks = new Dictionary();
-
- ///
- /// Waits the async.
- ///
- /// The name.
- /// Task.
- public Task WaitAsync(string name)
- {
- return GetLock(name).WaitAsync();
- }
-
- ///
- /// Releases the specified name.
- ///
- /// The name.
- public void Release(string name)
- {
- SemaphoreSlim semaphore;
-
- if (_locks.TryGetValue(name, out semaphore))
- {
- semaphore.Release();
- }
- }
-
- ///
- /// Gets the lock.
- ///
- /// The filename.
- /// System.Object.
- private SemaphoreSlim GetLock(string filename)
- {
- SemaphoreSlim fileLock;
- lock (_locks)
- {
- if (!_locks.TryGetValue(filename, out fileLock))
- {
- fileLock = new SemaphoreSlim(1,1);
- _locks[filename] = fileLock;
- }
- }
- return fileLock;
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
- {
- Dispose(true);
- }
-
- ///
- /// Releases unmanaged and - optionally - managed resources.
- ///
- /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- DisposeLocks();
- }
- }
-
- ///
- /// Disposes the locks.
- ///
- private void DisposeLocks()
- {
- lock (_locks)
- {
- foreach (var semaphore in _locks.Values)
- {
- semaphore.Dispose();
- }
-
- _locks.Clear();
- }
- }
- }
-}
diff --git a/MediaBrowser.Common/IO/FileSystemRepository.cs b/MediaBrowser.Common/IO/FileSystemRepository.cs
index 24ad04a926..3a4987a944 100644
--- a/MediaBrowser.Common/IO/FileSystemRepository.cs
+++ b/MediaBrowser.Common/IO/FileSystemRepository.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Concurrent;
using System.IO;
-using System.Threading.Tasks;
namespace MediaBrowser.Common.IO
{
@@ -18,11 +17,6 @@ namespace MediaBrowser.Common.IO
///
private readonly ConcurrentDictionary _subFolderPaths = new ConcurrentDictionary();
- ///
- /// The _file locks
- ///
- private readonly NamedLock _fileLocks = new NamedLock();
-
///
/// Gets or sets the path.
///
@@ -170,24 +164,6 @@ namespace MediaBrowser.Common.IO
return File.Exists(path);
}
- ///
- /// Waits for lock.
- ///
- /// The resource path.
- public Task WaitForLockAsync(string resourcePath)
- {
- return _fileLocks.WaitAsync(resourcePath);
- }
-
- ///
- /// Releases the lock.
- ///
- /// The resource path.
- public void ReleaseLock(string resourcePath)
- {
- _fileLocks.Release(resourcePath);
- }
-
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
@@ -204,7 +180,6 @@ namespace MediaBrowser.Common.IO
{
if (dispose)
{
- _fileLocks.Dispose();
}
}
}
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index a8fc4564c7..e9dda6bb77 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -61,7 +61,6 @@
-
diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Controller/Drawing/ImageManager.cs
index d78ff819bc..a5e36da329 100644
--- a/MediaBrowser.Controller/Drawing/ImageManager.cs
+++ b/MediaBrowser.Controller/Drawing/ImageManager.cs
@@ -15,6 +15,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Drawing
@@ -50,7 +51,7 @@ namespace MediaBrowser.Controller.Drawing
///
/// The cached imaged sizes
///
- private readonly ConcurrentDictionary> _cachedImagedSizes = new ConcurrentDictionary>();
+ private readonly ConcurrentDictionary _cachedImagedSizes = new ConcurrentDictionary();
///
/// The _logger
@@ -67,12 +68,18 @@ namespace MediaBrowser.Controller.Drawing
///
private readonly Kernel _kernel;
+ ///
+ /// The _locks
+ ///
+ private readonly ConcurrentDictionary _locks = new ConcurrentDictionary();
+
///
/// Initializes a new instance of the class.
///
/// The kernel.
/// The protobuf serializer.
/// The logger.
+ /// The app paths.
public ImageManager(Kernel kernel, IProtobufSerializer protobufSerializer, ILogger logger, IServerApplicationPaths appPaths)
{
_protobufSerializer = protobufSerializer;
@@ -117,15 +124,7 @@ namespace MediaBrowser.Controller.Drawing
if (cropWhitespace)
{
- try
- {
- originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- // We have to have a catch-all here because some of the .net image methods throw a plain old Exception
- _logger.ErrorException("Error cropping image", ex);
- }
+ originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
}
try
@@ -140,12 +139,12 @@ namespace MediaBrowser.Controller.Drawing
originalImagePath = ehnancedImagePath;
}
}
- catch
+ catch (Exception ex)
{
- _logger.Error("Error enhancing image");
+ _logger.Error("Error enhancing image", ex);
}
- var originalImageSize = await GetImageSize(originalImagePath, dateModified).ConfigureAwait(false);
+ var originalImageSize = GetImageSize(originalImagePath, dateModified);
// Determine the output size based on incoming parameters
var newSize = DrawingUtils.Resize(originalImageSize, width, height, maxWidth, maxHeight);
@@ -158,67 +157,102 @@ namespace MediaBrowser.Controller.Drawing
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality.Value, dateModified);
// Grab the cache file if it already exists
- try
+ if (File.Exists(cacheFilePath))
{
using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
+ return;
}
- return;
}
- catch (FileNotFoundException)
+
+ var semaphore = GetLock(cacheFilePath);
+
+ await semaphore.WaitAsync().ConfigureAwait(false);
+
+ // Check again in case of lock contention
+ if (File.Exists(cacheFilePath))
{
- // Cache file doesn't exist. No biggie.
+ try
+ {
+ using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
+ return;
+ }
+ }
+ finally
+ {
+ semaphore.Release();
+ }
}
- using (var fileStream = File.OpenRead(originalImagePath))
+ try
{
- using (var originalImage = Bitmap.FromStream(fileStream, true, false))
+ using (var fileStream = File.OpenRead(originalImagePath))
{
- var newWidth = Convert.ToInt32(newSize.Width);
- var newHeight = Convert.ToInt32(newSize.Height);
+ using (var originalImage = Image.FromStream(fileStream, true, false))
+ {
+ var newWidth = Convert.ToInt32(newSize.Width);
+ var newHeight = Convert.ToInt32(newSize.Height);
- // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
- var thumbnail = !ImageExtensions.IsPixelFormatSupportedByGraphicsObject(originalImage.PixelFormat) ? new Bitmap(originalImage, newWidth, newHeight) : new Bitmap(newWidth, newHeight, originalImage.PixelFormat);
+ // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
+ var thumbnail = !ImageExtensions.IsPixelFormatSupportedByGraphicsObject(originalImage.PixelFormat) ? new Bitmap(originalImage, newWidth, newHeight) : new Bitmap(newWidth, newHeight, originalImage.PixelFormat);
- // Preserve the original resolution
- thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
+ // Preserve the original resolution
+ thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
- var thumbnailGraph = Graphics.FromImage(thumbnail);
+ var thumbnailGraph = Graphics.FromImage(thumbnail);
- thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
- thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
- thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
- thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
- thumbnailGraph.CompositingMode = CompositingMode.SourceOver;
+ thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
+ thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
+ thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ thumbnailGraph.CompositingMode = CompositingMode.SourceOver;
- thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight);
+ thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight);
- var outputFormat = originalImage.RawFormat;
+ var outputFormat = originalImage.RawFormat;
- using (var memoryStream = new MemoryStream { })
- {
- // Save to the memory stream
- thumbnail.Save(outputFormat, memoryStream, quality.Value);
+ using (var memoryStream = new MemoryStream { })
+ {
+ // Save to the memory stream
+ thumbnail.Save(outputFormat, memoryStream, quality.Value);
- var bytes = memoryStream.ToArray();
+ var bytes = memoryStream.ToArray();
- var outputTask = Task.Run(async () => await toStream.WriteAsync(bytes, 0, bytes.Length));
+ var outputTask = toStream.WriteAsync(bytes, 0, bytes.Length);
- // Save to the cache location
- using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- // Save to the filestream
- await cacheFileStream.WriteAsync(bytes, 0, bytes.Length);
+ // kick off a task to cache the result
+ Task.Run(() => CacheResizedImage(cacheFilePath, bytes));
+
+ await outputTask.ConfigureAwait(false);
}
- await outputTask.ConfigureAwait(false);
+ thumbnailGraph.Dispose();
+ thumbnail.Dispose();
}
-
- thumbnailGraph.Dispose();
- thumbnail.Dispose();
}
}
+ finally
+ {
+ semaphore.Release();
+ }
+ }
+
+ ///
+ /// Caches the resized image.
+ ///
+ /// The cache file path.
+ /// The bytes.
+ private async void CacheResizedImage(string cacheFilePath, byte[] bytes)
+ {
+ // Save to the cache location
+ using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+ {
+ // Save to the filestream
+ await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ }
}
///
@@ -252,7 +286,7 @@ namespace MediaBrowser.Controller.Drawing
/// The date modified.
/// Task{ImageSize}.
/// imagePath
- public Task GetImageSize(string imagePath, DateTime dateModified)
+ public ImageSize GetImageSize(string imagePath, DateTime dateModified)
{
if (string.IsNullOrEmpty(imagePath))
{
@@ -261,18 +295,7 @@ namespace MediaBrowser.Controller.Drawing
var name = imagePath + "datemodified=" + dateModified.Ticks;
- return _cachedImagedSizes.GetOrAdd(name, keyName => GetImageSizeTask(keyName, imagePath));
- }
-
- ///
- /// Gets cached image dimensions, or results null if non-existant
- ///
- /// Name of the key.
- /// The image path.
- /// Task{ImageSize}.
- private Task GetImageSizeTask(string keyName, string imagePath)
- {
- return Task.Run(() => GetImageSize(keyName, imagePath));
+ return _cachedImagedSizes.GetOrAdd(name, keyName => GetImageSize(keyName, imagePath));
}
///
@@ -297,27 +320,14 @@ namespace MediaBrowser.Controller.Drawing
// Cache file doesn't exist no biggie
}
- var size = ImageHeader.GetDimensions(imagePath, _logger);
+ _logger.Debug("Getting image size for {0}", imagePath);
- var imageSize = new ImageSize { Width = size.Width, Height = size.Height };
+ var size = ImageHeader.GetDimensions(imagePath, _logger);
// Update the file system cache
- CacheImageSize(fullCachePath, size.Width, size.Height);
-
- return imageSize;
- }
+ Task.Run(() => _protobufSerializer.SerializeToFile(new[] { size.Width, size.Height }, fullCachePath));
- ///
- /// Caches image dimensions
- ///
- /// The cache path.
- /// The width.
- /// The height.
- private void CacheImageSize(string cachePath, int width, int height)
- {
- var output = new[] { width, height };
-
- _protobufSerializer.SerializeToFile(output, cachePath);
+ return new ImageSize { Width = size.Width, Height = size.Height };
}
///
@@ -367,7 +377,7 @@ namespace MediaBrowser.Controller.Drawing
return video.Chapters[imageIndex].ImagePath;
}
-
+
return item.GetImage(imageType);
}
@@ -409,7 +419,7 @@ namespace MediaBrowser.Controller.Drawing
{
throw new ArgumentNullException("imagePath");
}
-
+
var metaFileEntry = item.ResolveArgs.GetMetaFileByPath(imagePath);
// If we didn't the metafile entry, check the Season
@@ -440,38 +450,53 @@ namespace MediaBrowser.Controller.Drawing
var croppedImagePath = CroppedImageCache.GetResourcePath(name, Path.GetExtension(originalImagePath));
- if (!CroppedImageCache.ContainsFilePath(croppedImagePath))
+ if (CroppedImageCache.ContainsFilePath(croppedImagePath))
+ {
+ return croppedImagePath;
+ }
+
+ var semaphore = GetLock(croppedImagePath);
+
+ await semaphore.WaitAsync().ConfigureAwait(false);
+
+ // Check again in case of contention
+ if (CroppedImageCache.ContainsFilePath(croppedImagePath))
+ {
+ semaphore.Release();
+ return croppedImagePath;
+ }
+
+ try
{
using (var fileStream = File.OpenRead(originalImagePath))
{
- using (var originalImage = (Bitmap)Bitmap.FromStream(fileStream, true, false))
+ using (var originalImage = (Bitmap)Image.FromStream(fileStream, true, false))
{
var outputFormat = originalImage.RawFormat;
using (var croppedImage = originalImage.CropWhitespace())
{
- await SaveImageToFile(croppedImage, outputFormat, croppedImagePath).ConfigureAwait(false);
+ using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ croppedImage.Save(outputFormat, outputStream, 100);
+ }
}
}
}
}
-
- return croppedImagePath;
- }
-
- private async Task SaveImageToFile(Image image, ImageFormat outputFormat, string file)
- {
- using (var memoryStream = new MemoryStream())
+ catch (Exception ex)
{
- image.Save(outputFormat, memoryStream, 100);
+ // We have to have a catch-all here because some of the .net image methods throw a plain old Exception
+ _logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
- memoryStream.Position = 0;
-
- using (var cacheFileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- await memoryStream.CopyToAsync(cacheFileStream).ConfigureAwait(false);
- }
+ return originalImagePath;
+ }
+ finally
+ {
+ semaphore.Release();
}
+
+ return croppedImagePath;
}
///
@@ -509,7 +534,23 @@ namespace MediaBrowser.Controller.Drawing
// All enhanced images are saved as png to allow transparency
var enhancedImagePath = EnhancedImageCache.GetResourcePath(cacheGuid + ".png");
- if (!EnhancedImageCache.ContainsFilePath(enhancedImagePath))
+ if (EnhancedImageCache.ContainsFilePath(enhancedImagePath))
+ {
+ return enhancedImagePath;
+ }
+
+ var semaphore = GetLock(enhancedImagePath);
+
+ await semaphore.WaitAsync().ConfigureAwait(false);
+
+ // Check again in case of contention
+ if (EnhancedImageCache.ContainsFilePath(enhancedImagePath))
+ {
+ semaphore.Release();
+ return enhancedImagePath;
+ }
+
+ try
{
using (var fileStream = File.OpenRead(originalImagePath))
{
@@ -519,11 +560,18 @@ namespace MediaBrowser.Controller.Drawing
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false))
{
//And then save it in the cache
- await SaveImageToFile(newImage, ImageFormat.Png, enhancedImagePath).ConfigureAwait(false);
+ using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ newImage.Save(ImageFormat.Png, outputStream, 100);
+ }
}
}
}
}
+ finally
+ {
+ semaphore.Release();
+ }
return enhancedImagePath;
}
@@ -547,7 +595,7 @@ namespace MediaBrowser.Controller.Drawing
{
throw new ArgumentNullException("imagePath");
}
-
+
var dateModified = GetImageDateModified(item, imagePath);
var supportedEnhancers = _kernel.ImageEnhancers.Where(i => i.Supports(item, imageType));
@@ -624,6 +672,19 @@ namespace MediaBrowser.Controller.Drawing
return result;
}
+ ///
+ /// Gets the lock.
+ ///
+ /// The filename.
+ /// System.Object.
+ private SemaphoreSlim GetLock(string filename)
+ {
+ return _locks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
public void Dispose()
{
Dispose(true);
diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs
index d9244c64c2..e87282c1fb 100644
--- a/MediaBrowser.Controller/Library/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Library/DtoBuilder.cs
@@ -59,11 +59,21 @@ namespace MediaBrowser.Controller.Library
var tasks = new List();
+ if (fields.Contains(ItemFields.Studios))
+ {
+ dto.Studios = item.Studios;
+ }
+
+ if (fields.Contains(ItemFields.People))
+ {
+ tasks.Add(AttachPeople(dto, item));
+ }
+
if (fields.Contains(ItemFields.PrimaryImageAspectRatio))
{
try
{
- tasks.Add(AttachPrimaryImageAspectRatio(dto, item));
+ AttachPrimaryImageAspectRatio(dto, item);
}
catch (Exception ex)
{
@@ -72,16 +82,6 @@ namespace MediaBrowser.Controller.Library
}
}
- if (fields.Contains(ItemFields.Studios))
- {
- dto.Studios = item.Studios;
- }
-
- if (fields.Contains(ItemFields.People))
- {
- tasks.Add(AttachPeople(dto, item));
- }
-
AttachBasicFields(dto, item, fields);
// Make sure all the tasks we kicked off have completed.
@@ -120,19 +120,6 @@ namespace MediaBrowser.Controller.Library
var tasks = new List();
- if (fields.Contains(ItemFields.PrimaryImageAspectRatio))
- {
- try
- {
- tasks.Add(AttachPrimaryImageAspectRatio(dto, item));
- }
- catch (Exception ex)
- {
- // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
- _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, item.Name);
- }
- }
-
if (fields.Contains(ItemFields.Studios))
{
dto.Studios = item.Studios;
@@ -145,6 +132,19 @@ namespace MediaBrowser.Controller.Library
tasks.Add(AttachUserSpecificInfo(dto, item, user, fields));
+ if (fields.Contains(ItemFields.PrimaryImageAspectRatio))
+ {
+ try
+ {
+ AttachPrimaryImageAspectRatio(dto, item);
+ }
+ catch (Exception ex)
+ {
+ // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
+ _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, item.Name);
+ }
+ }
+
AttachBasicFields(dto, item, fields);
// Make sure all the tasks we kicked off have completed.
@@ -199,7 +199,7 @@ namespace MediaBrowser.Controller.Library
/// The dto.
/// The item.
/// Task.
- private async Task AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
+ private void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
{
var path = item.PrimaryImagePath;
@@ -217,7 +217,7 @@ namespace MediaBrowser.Controller.Library
try
{
- size = await Kernel.Instance.ImageManager.GetImageSize(path, dateModified).ConfigureAwait(false);
+ size = Kernel.Instance.ImageManager.GetImageSize(path, dateModified);
}
catch (FileNotFoundException)
{
@@ -771,7 +771,7 @@ namespace MediaBrowser.Controller.Library
/// The user.
/// DtoUser.
/// user
- public async Task GetUserDto(User user)
+ public UserDto GetUserDto(User user)
{
if (user == null)
{
@@ -796,7 +796,7 @@ namespace MediaBrowser.Controller.Library
try
{
- await AttachPrimaryImageAspectRatio(dto, user).ConfigureAwait(false);
+ AttachPrimaryImageAspectRatio(dto, user);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index ca3c1fe7cf..c5e4de2bc1 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -300,10 +300,18 @@ namespace MediaBrowser.Server.Implementations.Library
var activityDate = DateTime.UtcNow;
+ var lastActivityDate = user.LastActivityDate;
+
user.LastActivityDate = activityDate;
LogConnection(user.Id, clientType, deviceId, deviceName, activityDate);
+ // Don't log in the db anymore frequently than 10 seconds
+ if (lastActivityDate.HasValue && (activityDate - lastActivityDate.Value).TotalSeconds < 10)
+ {
+ return Task.FromResult(true);
+ }
+
// Save this directly. No need to fire off all the events for this.
return Kernel.UserRepository.SaveUser(user, CancellationToken.None);
}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
index 44674e125c..8a15d4028e 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
@@ -48,10 +48,10 @@ namespace MediaBrowser.Server.Implementations.Sqlite
///
/// The app paths.
/// The protobuf serializer.
- /// The logger.
+ /// The log manager.
/// protobufSerializer
- public SQLiteDisplayPreferencesRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger)
- : base(logger)
+ public SQLiteDisplayPreferencesRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogManager logManager)
+ : base(logManager)
{
if (protobufSerializer == null)
{
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
index 6a9a9f6f5d..3403cf79ff 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
@@ -56,10 +56,10 @@ namespace MediaBrowser.Server.Implementations.Sqlite
///
/// The app paths.
/// The json serializer.
- /// The logger.
+ /// The log manager.
/// appPaths
- public SQLiteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger)
- : base(logger)
+ public SQLiteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+ : base(logManager)
{
if (appPaths == null)
{
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
index 1173f3fc80..c5320a1f62 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
@@ -46,16 +46,16 @@ namespace MediaBrowser.Server.Implementations.Sqlite
///
/// Initializes a new instance of the class.
///
- /// The logger.
+ /// The log manager.
/// logger
- protected SqliteRepository(ILogger logger)
+ protected SqliteRepository(ILogManager logManager)
{
- if (logger == null)
+ if (logManager == null)
{
- throw new ArgumentNullException("logger");
+ throw new ArgumentNullException("logManager");
}
- Logger = logger;
+ Logger = logManager.GetLogger(GetType().Name);
}
///
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
index f3dede889d..2c8d7f437f 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
@@ -49,10 +49,10 @@ namespace MediaBrowser.Server.Implementations.Sqlite
///
/// The app paths.
/// The protobuf serializer.
- /// The logger.
+ /// The log manager.
/// protobufSerializer
- public SQLiteUserDataRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogger logger)
- : base(logger)
+ public SQLiteUserDataRepository(IApplicationPaths appPaths, IProtobufSerializer protobufSerializer, ILogManager logManager)
+ : base(logManager)
{
if (protobufSerializer == null)
{
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
index 43dffc5964..812c98789f 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
@@ -50,10 +50,10 @@ namespace MediaBrowser.Server.Implementations.Sqlite
///
/// The app paths.
/// The json serializer.
- /// The logger.
+ /// The log manager.
/// appPaths
- public SQLiteUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogger logger)
- : base(logger)
+ public SQLiteUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+ : base(logManager)
{
if (appPaths == null)
{
diff --git a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
index 9ddd14491e..98d7fb4775 100644
--- a/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
+++ b/MediaBrowser.ServerApplication/EntryPoints/WebSocketEvents.cs
@@ -172,9 +172,9 @@ namespace MediaBrowser.ServerApplication.EntryPoints
///
/// The sender.
/// The e.
- async void userManager_UserUpdated(object sender, GenericEventArgs e)
+ void userManager_UserUpdated(object sender, GenericEventArgs e)
{
- var dto = await new DtoBuilder(_logger, _libraryManager, _userManager).GetUserDto(e.Argument).ConfigureAwait(false);
+ var dto = new DtoBuilder(_logger, _libraryManager, _userManager).GetUserDto(e.Argument);
_serverManager.SendWebSocketMessage("UserUpdated", dto);
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
index 6109f73bbb..debe785996 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
@@ -40,9 +40,11 @@ namespace MediaBrowser.WebDashboard.Api
///
/// Initializes a new instance of the class.
///
+ /// The app host.
/// The logger.
/// The task manager.
/// The user manager.
+ /// The library manager.
public DashboardInfoWebSocketListener(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
: base(logger)
{
@@ -59,7 +61,7 @@ namespace MediaBrowser.WebDashboard.Api
/// Task{IEnumerable{TaskInfo}}.
protected override Task GetDataToSend(object state)
{
- return DashboardService.GetDashboardInfo(_appHost, Logger, _taskManager, _userManager, _libraryManager);
+ return Task.FromResult(DashboardService.GetDashboardInfo(_appHost, Logger, _taskManager, _userManager, _libraryManager));
}
}
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index f6c64b49eb..15ccbfb3e4 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -147,7 +147,7 @@ namespace MediaBrowser.WebDashboard.Api
/// System.Object.
public object Get(GetDashboardInfo request)
{
- return GetDashboardInfo(_appHost, Logger, _taskManager, _userManager, _libraryManager).Result;
+ return GetDashboardInfo(_appHost, Logger, _taskManager, _userManager, _libraryManager);
}
///
@@ -159,14 +159,13 @@ namespace MediaBrowser.WebDashboard.Api
/// The user manager.
/// The library manager.
/// DashboardInfo.
- public static async Task GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
+ public static DashboardInfo GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
{
var connections = userManager.RecentConnections.ToArray();
var dtoBuilder = new DtoBuilder(logger, libraryManager, userManager);
- var tasks = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetUserDto);
- var users = await Task.WhenAll(tasks).ConfigureAwait(false);
+ var users = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetUserDto);
return new DashboardInfo
{
@@ -180,7 +179,7 @@ namespace MediaBrowser.WebDashboard.Api
ActiveConnections = connections,
- Users = users
+ Users = users.ToArray()
};
}