diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs index 8f66029fee..e95b5e3752 100644 --- a/MediaBrowser.Model/Drawing/DrawingUtils.cs +++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs @@ -1,4 +1,5 @@ - +using System.Globalization; + namespace MediaBrowser.Model.Drawing { /// @@ -131,20 +132,77 @@ namespace MediaBrowser.Model.Drawing /// public struct ImageSize { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + private double _height; + private double _width; + /// /// Gets or sets the height. /// /// The height. - public double Height { get; set; } + public double Height + { + get + { + return _height; + } + set + { + _height = value; + } + } + /// /// Gets or sets the width. /// /// The width. - public double Width { get; set; } + public double Width + { + get { return _width; } + set { _width = value; } + } public bool Equals(ImageSize size) { 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; + } + } + } + } } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 9d71fef0ad..cc6e07d622 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -822,13 +822,18 @@ namespace MediaBrowser.Providers.Movies // genres // 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); + } } } diff --git a/MediaBrowser.Providers/Music/LastFmImageProvider.cs b/MediaBrowser.Providers/Music/LastFmImageProvider.cs index 075f68b6a8..cd40052235 100644 --- a/MediaBrowser.Providers/Music/LastFmImageProvider.cs +++ b/MediaBrowser.Providers/Music/LastFmImageProvider.cs @@ -70,9 +70,12 @@ namespace MediaBrowser.Providers.Music /// Task{System.Boolean}. public override async Task 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); diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index 4379c8fad2..78dcf6fd0d 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -24,7 +25,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// /// Class ImageProcessor /// - public class ImageProcessor : IImageProcessor + public class ImageProcessor : IImageProcessor, IDisposable { /// /// The us culture @@ -34,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// /// The _cached imaged sizes /// - private readonly ConcurrentDictionary _cachedImagedSizes = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _cachedImagedSizes; /// /// Gets the list of currently registered image processors @@ -49,21 +50,41 @@ namespace MediaBrowser.Server.Implementations.Drawing private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _jsonSerializer; + private readonly IServerApplicationPaths _appPaths; private readonly string _imageSizeCachePath; private readonly string _croppedWhitespaceImageCachePath; private readonly string _enhancedImageCachePath; private readonly string _resizedImageCachePath; - public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem) + public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer) { _logger = logger; _fileSystem = fileSystem; + _jsonSerializer = jsonSerializer; + _appPaths = appPaths; _imageSizeCachePath = Path.Combine(appPaths.ImageCachePath, "image-sizes"); _croppedWhitespaceImageCachePath = Path.Combine(appPaths.ImageCachePath, "cropped-images"); _enhancedImageCachePath = Path.Combine(appPaths.ImageCachePath, "enhanced-images"); _resizedImageCachePath = Path.Combine(appPaths.ImageCachePath, "resized-images"); + + _saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite); + + Dictionary sizeDictionary; + + try + { + sizeDictionary = jsonSerializer.DeserializeFromFile>(ImageSizeFile); + } + catch (IOException) + { + // No biggie + sizeDictionary = new Dictionary(); + } + + _cachedImagedSizes = new ConcurrentDictionary(sizeDictionary); } public void AddParts(IEnumerable enhancers) @@ -84,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Drawing } var originalImagePath = options.OriginalImagePath; - + if (options.HasDefaultOptions()) { // Just spit out the original file if all the options are default @@ -125,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.Drawing return; } } - + var quality = options.Quality ?? 90; 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; - if (!_cachedImagedSizes.TryGetValue(name, out size)) - { - size = GetImageSizeInternal(name, path); + var cacheHash = name.GetMD5(); - _cachedImagedSizes.AddOrUpdate(name, size, (keyName, oldValue) => size); + if (!_cachedImagedSizes.TryGetValue(cacheHash, out size)) + { + size = GetImageSizeInternal(path); + + _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size); } return size; @@ -498,62 +521,47 @@ namespace MediaBrowser.Server.Implementations.Drawing /// /// Gets the image size internal. /// - /// The cache key. /// The path. /// ImageSize. - 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 { - var result = File.ReadAllText(fullCachePath).Split('|'); - - return new ImageSize - { - Width = double.Parse(result[0], UsCulture), - Height = double.Parse(result[1], UsCulture) - }; + var path = ImageSizeFile; + Directory.CreateDirectory(Path.GetDirectoryName(path)); + _jsonSerializer.SerializeToFile(_cachedImagedSizes, path); } - catch (FileNotFoundException) + catch (Exception ex) { - // Cache file doesn't exist no biggie - } - catch (DirectoryNotFoundException) - { - // 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(); } + + public void Dispose() + { + _saveImageSizeTimer.Dispose(); + } } } diff --git a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs index 9fc622c213..a8c923bb0a 100644 --- a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs @@ -363,6 +363,7 @@ namespace MediaBrowser.Server.Implementations.IO { if (string.Equals(i, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); return true; } @@ -370,6 +371,7 @@ namespace MediaBrowser.Server.Implementations.IO var parent = Path.GetDirectoryName(i); if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); return true; } @@ -379,10 +381,18 @@ namespace MediaBrowser.Server.Implementations.IO parent = Path.GetDirectoryName(i); if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Watcher ignoring change to {0}", e.FullPath); 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; })) @@ -390,12 +400,6 @@ namespace MediaBrowser.Server.Implementations.IO 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); //Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs index f464985991..dfbf0736b5 100644 --- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs +++ b/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.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -8,6 +7,7 @@ using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index c5c5bc7e53..03819ff912 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.ServerApplication LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LocalizationManager); - ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager); + ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); RegisterSingleInstance(ImageProcessor); DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);