فهرست منبع

optimize image processor when gdi can be skipped

Luke Pulverenti 11 سال پیش
والد
کامیت
2fc662c9e9

+ 61 - 3
MediaBrowser.Model/Drawing/DrawingUtils.cs

@@ -1,4 +1,5 @@
-
+using System.Globalization;
+
 namespace MediaBrowser.Model.Drawing
 namespace MediaBrowser.Model.Drawing
 {
 {
     /// <summary>
     /// <summary>
@@ -131,20 +132,77 @@ namespace MediaBrowser.Model.Drawing
     /// </summary>
     /// </summary>
     public struct ImageSize
     public struct ImageSize
     {
     {
+        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
+        private double _height;
+        private double _width;
+
         /// <summary>
         /// <summary>
         /// Gets or sets the height.
         /// Gets or sets the height.
         /// </summary>
         /// </summary>
         /// <value>The height.</value>
         /// <value>The height.</value>
-        public double Height { get; set; }
+        public double Height
+        {
+            get
+            {
+                return _height;
+            }
+            set
+            {
+                _height = value;
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the width.
         /// Gets or sets the width.
         /// </summary>
         /// </summary>
         /// <value>The width.</value>
         /// <value>The width.</value>
-        public double Width { get; set; }
+        public double Width
+        {
+            get { return _width; }
+            set { _width = value; }
+        }
 
 
         public bool Equals(ImageSize size)
         public bool Equals(ImageSize size)
         {
         {
             return Width.Equals(size.Width) && Height.Equals(size.Height);
             return Width.Equals(size.Width) && Height.Equals(size.Height);
         }
         }
+
+        public override string ToString()
+        {
+            return string.Format("{0}-{1}", Width, Height);
+        }
+
+        public ImageSize(string value)
+        {
+            _width = 0;
+
+            _height = 0;
+
+            ParseValue(value);
+        }
+
+        private void ParseValue(string value)
+        {
+            if (!string.IsNullOrEmpty(value))
+            {
+                var parts = value.Split('-');
+
+                if (parts.Length == 2)
+                {
+                    double val;
+
+                    if (double.TryParse(parts[0], NumberStyles.Any, UsCulture, out val))
+                    {
+                        _width = val;
+                    }
+
+                    if (double.TryParse(parts[1], NumberStyles.Any, UsCulture, out val))
+                    {
+                        _height = val;
+                    }
+                }
+            }
+        }
     }
     }
 }
 }

+ 10 - 5
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -822,13 +822,18 @@ namespace MediaBrowser.Providers.Movies
 
 
                 // genres
                 // genres
                 // Movies get this from imdb
                 // Movies get this from imdb
-                if (movieData.genres != null && !movie.LockedFields.Contains(MetadataFields.Genres) && movie is BoxSet)
+                if (movieData.genres != null && !movie.LockedFields.Contains(MetadataFields.Genres))
                 {
                 {
-                    movie.Genres.Clear();
-
-                    foreach (var genre in movieData.genres.Select(g => g.name))
+                    // Only grab them if a boxset or there are no genres.
+                    // For movies and trailers we'll use imdb via omdb
+                    if (movie is BoxSet || movie.Genres.Count == 0)
                     {
                     {
-                        movie.AddGenre(genre);
+                        movie.Genres.Clear();
+
+                        foreach (var genre in movieData.genres.Select(g => g.name))
+                        {
+                            movie.AddGenre(genre);
+                        }
                     }
                     }
                 }
                 }
 
 

+ 5 - 2
MediaBrowser.Providers/Music/LastFmImageProvider.cs

@@ -70,9 +70,12 @@ namespace MediaBrowser.Providers.Music
         /// <returns>Task{System.Boolean}.</returns>
         /// <returns>Task{System.Boolean}.</returns>
         public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
         public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
         {
         {
-            var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualLastFmImageProvider.ProviderName).ConfigureAwait(false);
+            if (!item.HasImage(ImageType.Primary))
+            {
+                var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualLastFmImageProvider.ProviderName).ConfigureAwait(false);
 
 
-            await DownloadImages(item, images.ToList(), cancellationToken).ConfigureAwait(false);
+                await DownloadImages(item, images.ToList(), cancellationToken).ConfigureAwait(false);
+            }
 
 
             SetLastRefreshed(item, DateTime.UtcNow);
             SetLastRefreshed(item, DateTime.UtcNow);
 
 

+ 63 - 50
MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs

@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -24,7 +25,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
     /// <summary>
     /// <summary>
     /// Class ImageProcessor
     /// Class ImageProcessor
     /// </summary>
     /// </summary>
-    public class ImageProcessor : IImageProcessor
+    public class ImageProcessor : IImageProcessor, IDisposable
     {
     {
         /// <summary>
         /// <summary>
         /// The us culture
         /// The us culture
@@ -34,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <summary>
         /// <summary>
         /// The _cached imaged sizes
         /// The _cached imaged sizes
         /// </summary>
         /// </summary>
-        private readonly ConcurrentDictionary<string, ImageSize> _cachedImagedSizes = new ConcurrentDictionary<string, ImageSize>();
+        private readonly ConcurrentDictionary<Guid, ImageSize> _cachedImagedSizes;
 
 
         /// <summary>
         /// <summary>
         /// Gets the list of currently registered image processors
         /// Gets the list of currently registered image processors
@@ -49,21 +50,41 @@ namespace MediaBrowser.Server.Implementations.Drawing
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly IJsonSerializer _jsonSerializer;
+        private readonly IServerApplicationPaths _appPaths;
 
 
         private readonly string _imageSizeCachePath;
         private readonly string _imageSizeCachePath;
         private readonly string _croppedWhitespaceImageCachePath;
         private readonly string _croppedWhitespaceImageCachePath;
         private readonly string _enhancedImageCachePath;
         private readonly string _enhancedImageCachePath;
         private readonly string _resizedImageCachePath;
         private readonly string _resizedImageCachePath;
 
 
-        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem)
+        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
         {
         {
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _jsonSerializer = jsonSerializer;
+            _appPaths = appPaths;
 
 
             _imageSizeCachePath = Path.Combine(appPaths.ImageCachePath, "image-sizes");
             _imageSizeCachePath = Path.Combine(appPaths.ImageCachePath, "image-sizes");
             _croppedWhitespaceImageCachePath = Path.Combine(appPaths.ImageCachePath, "cropped-images");
             _croppedWhitespaceImageCachePath = Path.Combine(appPaths.ImageCachePath, "cropped-images");
             _enhancedImageCachePath = Path.Combine(appPaths.ImageCachePath, "enhanced-images");
             _enhancedImageCachePath = Path.Combine(appPaths.ImageCachePath, "enhanced-images");
             _resizedImageCachePath = Path.Combine(appPaths.ImageCachePath, "resized-images");
             _resizedImageCachePath = Path.Combine(appPaths.ImageCachePath, "resized-images");
+
+            _saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
+
+            Dictionary<Guid, ImageSize> sizeDictionary;
+
+            try
+            {
+                sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile);
+            }
+            catch (IOException)
+            {
+                // No biggie
+                sizeDictionary = new Dictionary<Guid, ImageSize>();
+            }
+
+            _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
         }
         }
 
 
         public void AddParts(IEnumerable<IImageEnhancer> enhancers)
         public void AddParts(IEnumerable<IImageEnhancer> enhancers)
@@ -84,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
             }
             }
 
 
             var originalImagePath = options.OriginalImagePath;
             var originalImagePath = options.OriginalImagePath;
-            
+
             if (options.HasDefaultOptions())
             if (options.HasDefaultOptions())
             {
             {
                 // Just spit out the original file if all the options are default
                 // Just spit out the original file if all the options are default
@@ -125,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
                     return;
                     return;
                 }
                 }
             }
             }
-            
+
             var quality = options.Quality ?? 90;
             var quality = options.Quality ?? 90;
 
 
             var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.BackgroundColor);
             var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.BackgroundColor);
@@ -485,11 +506,13 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
 
             ImageSize size;
             ImageSize size;
 
 
-            if (!_cachedImagedSizes.TryGetValue(name, out size))
+            var cacheHash = name.GetMD5();
+
+            if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
             {
             {
-                size = GetImageSizeInternal(name, path);
+                size = GetImageSizeInternal(path);
 
 
-                _cachedImagedSizes.AddOrUpdate(name, size, (keyName, oldValue) => size);
+                _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
             }
             }
 
 
             return size;
             return size;
@@ -498,62 +521,47 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <summary>
         /// <summary>
         /// Gets the image size internal.
         /// Gets the image size internal.
         /// </summary>
         /// </summary>
-        /// <param name="cacheKey">The cache key.</param>
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
         /// <returns>ImageSize.</returns>
         /// <returns>ImageSize.</returns>
-        private ImageSize GetImageSizeInternal(string cacheKey, string path)
+        private ImageSize GetImageSizeInternal(string path)
         {
         {
-            // Now check the file system cache
-            var fullCachePath = GetCachePath(_imageSizeCachePath, cacheKey, ".txt");
+            var size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
 
 
-            try
-            {
-                var result = File.ReadAllText(fullCachePath).Split('|');
+            StartSaveImageSizeTimer();
 
 
-                return new ImageSize
-                {
-                    Width = double.Parse(result[0], UsCulture),
-                    Height = double.Parse(result[1], UsCulture)
-                };
-            }
-            catch (IOException)
-            {
-                // Cache file doesn't exist or is currently being written to
-            }
+            return new ImageSize { Width = size.Width, Height = size.Height };
+        }
 
 
-            var syncLock = GetObjectLock(fullCachePath);
+        private readonly Timer _saveImageSizeTimer;
+        private const int SaveImageSizeTimeout = 5000;
+        private readonly object _saveImageSizeLock = new object();
+        private void StartSaveImageSizeTimer()
+        {
+            _saveImageSizeTimer.Change(SaveImageSizeTimeout, Timeout.Infinite);
+        }
 
 
-            lock (syncLock)
+        private void SaveImageSizeCallback(object state)
+        {
+            lock (_saveImageSizeLock)
             {
             {
                 try
                 try
                 {
                 {
-                    var result = File.ReadAllText(fullCachePath).Split('|');
-
-                    return new ImageSize
-                    {
-                        Width = double.Parse(result[0], UsCulture),
-                        Height = double.Parse(result[1], UsCulture)
-                    };
-                }
-                catch (FileNotFoundException)
-                {
-                    // Cache file doesn't exist no biggie
+                    var path = ImageSizeFile;
+                    Directory.CreateDirectory(Path.GetDirectoryName(path));
+                    _jsonSerializer.SerializeToFile(_cachedImagedSizes, path);
                 }
                 }
-                catch (DirectoryNotFoundException)
+                catch (Exception ex)
                 {
                 {
-                    // Cache file doesn't exist no biggie
+                    _logger.ErrorException("Error saving image size file", ex);
                 }
                 }
+            }
+        }
 
 
-                var size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
-
-                var parentPath = Path.GetDirectoryName(fullCachePath);
-
-                Directory.CreateDirectory(parentPath);
-
-                // Update the file system cache
-                File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture));
-
-                return new ImageSize { Width = size.Width, Height = size.Height };
+        private string ImageSizeFile
+        {
+            get
+            {
+                return Path.Combine(_appPaths.DataPath, "imagesizes.json");
             }
             }
         }
         }
 
 
@@ -882,5 +890,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
 
             }).ToList();
             }).ToList();
         }
         }
+
+        public void Dispose()
+        {
+            _saveImageSizeTimer.Dispose();
+        }
     }
     }
 }
 }

+ 10 - 6
MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs

@@ -363,6 +363,7 @@ namespace MediaBrowser.Server.Implementations.IO
             {
             {
                 if (string.Equals(i, e.FullPath, StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(i, e.FullPath, StringComparison.OrdinalIgnoreCase))
                 {
                 {
+                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
                     return true;
                     return true;
                 }
                 }
 
 
@@ -370,6 +371,7 @@ namespace MediaBrowser.Server.Implementations.IO
                 var parent = Path.GetDirectoryName(i);
                 var parent = Path.GetDirectoryName(i);
                 if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
                 {
                 {
+                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
                     return true;
                     return true;
                 }
                 }
 
 
@@ -379,10 +381,18 @@ namespace MediaBrowser.Server.Implementations.IO
                     parent = Path.GetDirectoryName(i);
                     parent = Path.GetDirectoryName(i);
                     if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
                     if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
                     {
                     {
+                        Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
                         return true;
                         return true;
                     }
                     }
                 }
                 }
 
 
+                if (i.StartsWith(e.FullPath, StringComparison.OrdinalIgnoreCase) || 
+                    e.FullPath.StartsWith(i, StringComparison.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
+                    return true;
+                }
+
                 return false;
                 return false;
 
 
             }))
             }))
@@ -390,12 +400,6 @@ namespace MediaBrowser.Server.Implementations.IO
                 return;
                 return;
             }
             }
 
 
-            if (tempIgnorePaths.Contains(e.FullPath, StringComparer.OrdinalIgnoreCase))
-            {
-                Logger.Debug("Watcher requested to ignore change to " + e.FullPath);
-                return;
-            }
-
             Logger.Info("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
             Logger.Info("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
 
 
             //Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path
             //Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path

+ 2 - 2
MediaBrowser.Server.Implementations/Providers/ImageSaver.cs

@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
@@ -8,6 +7,7 @@ using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using System;
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;

+ 1 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -288,7 +288,7 @@ namespace MediaBrowser.ServerApplication
             LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager);
             LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance(LocalizationManager);
             RegisterSingleInstance(LocalizationManager);
 
 
-            ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager);
+            ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer);
             RegisterSingleInstance(ImageProcessor);
             RegisterSingleInstance(ImageProcessor);
 
 
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);