diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs index ebb583506..e68292176 100644 --- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs +++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -13,7 +13,6 @@ using ServiceStack.ServiceHost; using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace MediaBrowser.Api.DefaultTheme { @@ -68,24 +67,26 @@ namespace MediaBrowser.Api.DefaultTheme private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; + private readonly IImageProcessor _imageProcessor; - public DefaultThemeService(IUserManager userManager, IDtoService dtoService, ILogger logger, ILibraryManager libraryManager, ILocalizationManager localization) + public DefaultThemeService(IUserManager userManager, IDtoService dtoService, ILogger logger, ILibraryManager libraryManager, ILocalizationManager localization, IImageProcessor imageProcessor) { _userManager = userManager; _dtoService = dtoService; _logger = logger; _libraryManager = libraryManager; _localization = localization; + _imageProcessor = imageProcessor; } public object Get(GetHomeView request) { - var result = GetHomeView(request).Result; + var result = GetHomeView(request); return ToOptimizedResult(result); } - private async Task GetHomeView(GetHomeView request) + private HomeView GetHomeView(GetHomeView request) { var user = _userManager.GetUserById(request.UserId); @@ -113,12 +114,12 @@ namespace MediaBrowser.Api.DefaultTheme public object Get(GetGamesView request) { - var result = GetGamesView(request).Result; + var result = GetGamesView(request); return ToOptimizedResult(result); } - private async Task GetGamesView(GetGamesView request) + private GamesView GetGamesView(GetGamesView request) { var user = _userManager.GetUserById(request.UserId); @@ -145,19 +146,19 @@ namespace MediaBrowser.Api.DefaultTheme public object Get(GetMovieView request) { - var result = GetMovieView(request).Result; + var result = GetMovieView(request); return ToOptimizedResult(result); } public object Get(GetTvView request) { - var result = GetTvView(request).Result; + var result = GetTvView(request); return ToOptimizedResult(result); } - private async Task GetTvView(GetTvView request) + private TvView GetTvView(GetTvView request) { var user = _userManager.GetUserById(request.UserId); @@ -210,7 +211,7 @@ namespace MediaBrowser.Api.DefaultTheme return view; } - private async Task GetMovieView(GetMovieView request) + private MoviesView GetMovieView(GetMovieView request) { var user = _userManager.GetUserById(request.UserId); @@ -348,9 +349,9 @@ namespace MediaBrowser.Api.DefaultTheme { try { - var date = Kernel.Instance.ImageManager.GetImageDateModified(item, path); + var date = item.GetImageDateModified(path); - var size = Kernel.Instance.ImageManager.GetImageSize(path, date); + var size = _imageProcessor.GetImageSize(path, date); return size.Width; } @@ -400,13 +401,11 @@ namespace MediaBrowser.Api.DefaultTheme ImageType = imageType }; - var imageManager = Kernel.Instance.ImageManager; - try { - var imagePath = imageManager.GetImagePath(item, imageType, 0); + var imagePath = item.GetImagePath(imageType, 0); - stub.ImageTag = imageManager.GetImageCacheTag(item, imageType, imagePath); + stub.ImageTag = _imageProcessor.GetImageCacheTag(item, imageType, imagePath); } catch (Exception ex) { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index fb5cb291e..b8c6fc8f0 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -338,11 +339,12 @@ namespace MediaBrowser.Api.Images private readonly IItemRepository _itemRepo; private readonly IDtoService _dtoService; + private readonly IImageProcessor _imageProcessor; /// /// Initializes a new instance of the class. /// - public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService) + public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor) { _userManager = userManager; _libraryManager = libraryManager; @@ -350,6 +352,7 @@ namespace MediaBrowser.Api.Images _providerManager = providerManager; _itemRepo = itemRepo; _dtoService = dtoService; + _imageProcessor = imageProcessor; } /// @@ -403,15 +406,13 @@ namespace MediaBrowser.Api.Images var fileInfo = new FileInfo(path); - var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, path); - - var size = Kernel.Instance.ImageManager.GetImageSize(path, dateModified); + var size = _imageProcessor.GetImageSize(path); list.Add(new ImageInfo { Path = path, ImageType = image.Key, - ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, image.Key, path), + ImageTag = _imageProcessor.GetImageCacheTag(item, image.Key, path), Size = fileInfo.Length, Width = Convert.ToInt32(size.Width), Height = Convert.ToInt32(size.Height) @@ -424,16 +425,14 @@ namespace MediaBrowser.Api.Images { var fileInfo = new FileInfo(image); - var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); - - var size = Kernel.Instance.ImageManager.GetImageSize(image, dateModified); + var size = _imageProcessor.GetImageSize(image); list.Add(new ImageInfo { Path = image, ImageIndex = index, ImageType = ImageType.Backdrop, - ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Backdrop, image), + ImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Backdrop, image), Size = fileInfo.Length, Width = Convert.ToInt32(size.Width), Height = Convert.ToInt32(size.Height) @@ -448,16 +447,14 @@ namespace MediaBrowser.Api.Images { var fileInfo = new FileInfo(image); - var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); - - var size = Kernel.Instance.ImageManager.GetImageSize(image, dateModified); + var size = _imageProcessor.GetImageSize(image); list.Add(new ImageInfo { Path = image, ImageIndex = index, ImageType = ImageType.Screenshot, - ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Screenshot, image), + ImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Screenshot, image), Size = fileInfo.Length, Width = Convert.ToInt32(size.Width), Height = Convert.ToInt32(size.Height) @@ -480,16 +477,14 @@ namespace MediaBrowser.Api.Images var fileInfo = new FileInfo(image); - var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); - - var size = Kernel.Instance.ImageManager.GetImageSize(image, dateModified); + var size = _imageProcessor.GetImageSize(image); list.Add(new ImageInfo { Path = image, ImageIndex = index, ImageType = ImageType.Chapter, - ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Chapter, image), + ImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Chapter, image), Size = fileInfo.Length, Width = Convert.ToInt32(size.Width), Height = Convert.ToInt32(size.Height) @@ -721,11 +716,7 @@ namespace MediaBrowser.Api.Images /// private object GetImage(ImageRequest request, BaseItem item) { - var kernel = Kernel.Instance; - - var index = request.Index ?? 0; - - var imagePath = GetImagePath(kernel, request, item); + var imagePath = GetImagePath(request, item); if (string.IsNullOrEmpty(imagePath)) { @@ -733,9 +724,9 @@ namespace MediaBrowser.Api.Images } // See if we can avoid a file system lookup by looking for the file in ResolveArgs - var originalFileImageDateModified = kernel.ImageManager.GetImageDateModified(item, imagePath); + var originalFileImageDateModified = item.GetImageDateModified(imagePath); - var supportedImageEnhancers = request.EnableImageEnhancers ? kernel.ImageManager.ImageEnhancers.Where(i => + var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i => { try { @@ -759,7 +750,7 @@ namespace MediaBrowser.Api.Images var contentType = MimeTypes.GetMimeType(imagePath); - var cacheGuid = kernel.ImageManager.GetImageCacheTag(imagePath, originalFileImageDateModified, supportedImageEnhancers, item, request.Type); + var cacheGuid = _imageProcessor.GetImageCacheTag(item, request.Type, imagePath, originalFileImageDateModified, supportedImageEnhancers); TimeSpan? cacheDuration = null; @@ -778,7 +769,8 @@ namespace MediaBrowser.Api.Images Request = currentRequest, OriginalImageDateModified = originalFileImageDateModified, Enhancers = supportedImageEnhancers, - OriginalImagePath = imagePath + OriginalImagePath = imagePath, + ImageProcessor = _imageProcessor }, contentType); } @@ -786,15 +778,14 @@ namespace MediaBrowser.Api.Images /// /// Gets the image path. /// - /// The kernel. /// The request. /// The item. /// System.String. - private string GetImagePath(Kernel kernel, ImageRequest request, BaseItem item) + private string GetImagePath(ImageRequest request, BaseItem item) { var index = request.Index ?? 0; - return kernel.ImageManager.GetImagePath(item, request.Type, index); + return item.GetImagePath(request.Type, index); } /// diff --git a/MediaBrowser.Api/Images/ImageWriter.cs b/MediaBrowser.Api/Images/ImageWriter.cs index a734e28e8..da2c9c043 100644 --- a/MediaBrowser.Api/Images/ImageWriter.cs +++ b/MediaBrowser.Api/Images/ImageWriter.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -35,6 +35,8 @@ namespace MediaBrowser.Api.Images public string OriginalImagePath; + public IImageProcessor ImageProcessor { get; set; } + /// /// The _options /// @@ -73,7 +75,7 @@ namespace MediaBrowser.Api.Images cropwhitespace = Request.CropWhitespace.Value; } - return Kernel.Instance.ImageManager.ProcessImage(Item, Request.Type, Request.Index ?? 0, OriginalImagePath, cropwhitespace, + return ImageProcessor.ProcessImage(Item, Request.Type, Request.Index ?? 0, OriginalImagePath, cropwhitespace, OriginalImageDateModified, responseStream, Request.Width, Request.Height, Request.MaxWidth, Request.MaxHeight, Request.Quality, Enhancers); } diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index d935fea79..915ec0c10 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.MediaInfo; using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; @@ -41,16 +42,8 @@ namespace MediaBrowser.Api.Playback.Progressive /// public class AudioService : BaseProgressiveStreamingService { - /// - /// Initializes a new instance of the class. - /// - /// The app paths. - /// The user manager. - /// The library manager. - /// The iso manager. - /// The media encoder. - public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService) - : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService) + public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor) + : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor) { } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 806e55024..0bc147a46 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.MediaInfo; using MediaBrowser.Common.Net; using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -24,11 +25,13 @@ namespace MediaBrowser.Api.Playback.Progressive public abstract class BaseProgressiveStreamingService : BaseStreamingService { protected readonly IItemRepository ItemRepository; + protected readonly IImageProcessor ImageProcessor; - protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService) : + protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor) : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService) { ItemRepository = itemRepository; + ImageProcessor = imageProcessor; } /// @@ -303,7 +306,7 @@ namespace MediaBrowser.Api.Playback.Progressive } } - return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService) + return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor) { Logger = Logger, RequestContext = RequestContext, diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index eb53bc2ce..c1dd7fa01 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.MediaInfo; using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -53,16 +54,8 @@ namespace MediaBrowser.Api.Playback.Progressive /// public class VideoService : BaseProgressiveStreamingService { - /// - /// Initializes a new instance of the class. - /// - /// The app paths. - /// The user manager. - /// The library manager. - /// The iso manager. - /// The media encoder. - public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService) - : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService) + public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor) + : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor) { } diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 2b3f11761..78c299fbb 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -66,6 +67,7 @@ namespace MediaBrowser.Api private readonly ILibrarySearchEngine _searchEngine; private readonly ILibraryManager _libraryManager; private readonly IDtoService _dtoService; + private readonly IImageProcessor _imageProcessor; /// /// Initializes a new instance of the class. @@ -73,12 +75,13 @@ namespace MediaBrowser.Api /// The user manager. /// The search engine. /// The library manager. - public SearchService(IUserManager userManager, ILibrarySearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService) + public SearchService(IUserManager userManager, ILibrarySearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService, IImageProcessor imageProcessor) { _userManager = userManager; _searchEngine = searchEngine; _libraryManager = libraryManager; _dtoService = dtoService; + _imageProcessor = imageProcessor; } /// @@ -161,7 +164,7 @@ namespace MediaBrowser.Api if (item.HasImage(ImageType.Primary)) { - result.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Primary, item.GetImage(ImageType.Primary)); + result.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary, item.GetImage(ImageType.Primary)); } var episode = item as Episode; diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs new file mode 100644 index 000000000..55c279b0c --- /dev/null +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -0,0 +1,94 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Drawing +{ + /// + /// Interface IImageProcessor + /// + public interface IImageProcessor + { + /// + /// Gets the image enhancers. + /// + /// The image enhancers. + IEnumerable ImageEnhancers { get; } + + /// + /// Gets the size of the image. + /// + /// The path. + /// ImageSize. + ImageSize GetImageSize(string path); + + /// + /// Gets the size of the image. + /// + /// The path. + /// The image date modified. + /// ImageSize. + ImageSize GetImageSize(string path, DateTime imageDateModified); + + /// + /// Adds the parts. + /// + /// The enhancers. + void AddParts(IEnumerable enhancers); + + /// + /// Gets the supported enhancers. + /// + /// The item. + /// Type of the image. + /// IEnumerable{IImageEnhancer}. + IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType); + + /// + /// Gets the image cache tag. + /// + /// The item. + /// Type of the image. + /// The image path. + /// Guid. + Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath); + + /// + /// Gets the image cache tag. + /// + /// The item. + /// Type of the image. + /// The original image path. + /// The date modified. + /// The image enhancers. + /// Guid. + Guid GetImageCacheTag(BaseItem item, ImageType imageType, string originalImagePath, DateTime dateModified, + IEnumerable imageEnhancers); + + /// + /// Processes the image. + /// + /// The entity. + /// Type of the image. + /// Index of the image. + /// The original image path. + /// if set to true [crop whitespace]. + /// The date modified. + /// To stream. + /// The width. + /// The height. + /// Width of the max. + /// Height of the max. + /// The quality. + /// The enhancers. + /// Task. + Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, string originalImagePath, bool cropWhitespace, + DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, + int? quality, List enhancers); + } +} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f81485867..db3e546d1 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; @@ -936,7 +937,7 @@ namespace MediaBrowser.Controller.Entities var itemsChanged = !LocalTrailerIds.SequenceEqual(newItemIds); - var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); + var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -952,7 +953,7 @@ namespace MediaBrowser.Controller.Entities var themeVideosChanged = !ThemeVideoIds.SequenceEqual(newThemeVideoIds); - var tasks = newThemeVideos.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); + var tasks = newThemeVideos.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -971,7 +972,7 @@ namespace MediaBrowser.Controller.Entities var themeSongsChanged = !ThemeSongIds.SequenceEqual(newThemeSongIds); - var tasks = newThemeSongs.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); + var tasks = newThemeSongs.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -1562,5 +1563,64 @@ namespace MediaBrowser.Controller.Entities ScreenshotImagePaths.Remove(path); } } + + /// + /// Gets the image path. + /// + /// Type of the image. + /// Index of the image. + /// System.String. + /// + /// + /// item + public string GetImagePath(ImageType imageType, int imageIndex) + { + if (imageType == ImageType.Backdrop) + { + return BackdropImagePaths[imageIndex]; + } + + if (imageType == ImageType.Screenshot) + { + return ScreenshotImagePaths[imageIndex]; + } + + if (imageType == ImageType.Chapter) + { + return ItemRepository.GetChapter(Id, imageIndex).ImagePath; + } + + return GetImage(imageType); + } + + /// + /// Gets the image date modified. + /// + /// The image path. + /// DateTime. + /// item + public DateTime GetImageDateModified(string imagePath) + { + if (string.IsNullOrEmpty(imagePath)) + { + throw new ArgumentNullException("imagePath"); + } + + var metaFileEntry = ResolveArgs.GetMetaFileByPath(imagePath); + + // If we didn't the metafile entry, check the Season + if (metaFileEntry == null) + { + var episode = this as Episode; + + if (episode != null && episode.Season != null) + { + episode.Season.ResolveArgs.GetMetaFileByPath(imagePath); + } + } + + // See if we can avoid a file system lookup by looking for the file in ResolveArgs + return metaFileEntry == null ? File.GetLastWriteTimeUtc(imagePath) : metaFileEntry.LastWriteTimeUtc; + } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 60e169936..152767860 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Entities.Movies var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds); - var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); + var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 5bf485229..37a1648c1 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.MediaInfo; +using MediaBrowser.Controller.MediaInfo; namespace MediaBrowser.Controller { @@ -14,12 +13,6 @@ namespace MediaBrowser.Controller /// The instance. public static Kernel Instance { get; private set; } - /// - /// Gets the image manager. - /// - /// The image manager. - public ImageManager ImageManager { get; set; } - /// /// Gets the FFMPEG controller. /// diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0e97a9f2a..960f597ac 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -71,6 +71,7 @@ Properties\SharedVersion.cs + @@ -95,8 +96,6 @@ - - diff --git a/MediaBrowser.Controller/Drawing/ImageHeader.cs b/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs similarity index 99% rename from MediaBrowser.Controller/Drawing/ImageHeader.cs rename to MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs index 95a753f00..4da836cc6 100644 --- a/MediaBrowser.Controller/Drawing/ImageHeader.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs @@ -5,7 +5,7 @@ using System.Drawing; using System.IO; using System.Linq; -namespace MediaBrowser.Controller.Drawing +namespace MediaBrowser.Server.Implementations.Drawing { /// /// Taken from http://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file/111349 diff --git a/MediaBrowser.Controller/Drawing/ImageManager.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs similarity index 73% rename from MediaBrowser.Controller/Drawing/ImageManager.cs rename to MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index 05f45a457..d16c2a4de 100644 --- a/MediaBrowser.Controller/Drawing/ImageManager.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -1,108 +1,79 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Globalization; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Drawing; +using System; +using System.Collections.Concurrent; +using System.IO; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; -namespace MediaBrowser.Controller.Drawing +namespace MediaBrowser.Server.Implementations.Drawing { /// - /// Class ImageManager + /// Class ImageProcessor /// - public class ImageManager + public class ImageProcessor : IImageProcessor { + /// + /// The us culture + /// + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// The _cached imaged sizes + /// + private readonly ConcurrentDictionary _cachedImagedSizes = new ConcurrentDictionary(); + /// /// Gets the list of currently registered image processors /// Image processors are specialized metadata providers that run after the normal ones /// /// The image enhancers. - public IEnumerable ImageEnhancers { get; set; } - - /// - /// Gets the image size cache. - /// - /// The image size cache. - private FileSystemRepository ImageSizeCache { get; set; } - - /// - /// Gets or sets the resized image cache. - /// - /// The resized image cache. - private FileSystemRepository ResizedImageCache { get; set; } - /// - /// Gets the cropped image cache. - /// - /// The cropped image cache. - private FileSystemRepository CroppedImageCache { get; set; } - - /// - /// Gets the cropped image cache. - /// - /// The cropped image cache. - private FileSystemRepository EnhancedImageCache { get; set; } - - /// - /// The cached imaged sizes - /// - private readonly ConcurrentDictionary _cachedImagedSizes = new ConcurrentDictionary(); + public IEnumerable ImageEnhancers { get; private set; } /// /// The _logger /// private readonly ILogger _logger; - - private readonly IItemRepository _itemRepo; - /// - /// Initializes a new instance of the class. + /// The _app paths /// - /// The logger. - /// The app paths. - /// The item repo. - public ImageManager(ILogger logger, IServerApplicationPaths appPaths, IItemRepository itemRepo) + 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) { _logger = logger; - _itemRepo = itemRepo; + _appPaths = appPaths; - ImageSizeCache = new FileSystemRepository(Path.Combine(appPaths.ImageCachePath, "image-sizes")); - ResizedImageCache = new FileSystemRepository(Path.Combine(appPaths.ImageCachePath, "resized-images")); - CroppedImageCache = new FileSystemRepository(Path.Combine(appPaths.ImageCachePath, "cropped-images")); - EnhancedImageCache = new FileSystemRepository(Path.Combine(appPaths.ImageCachePath, "enhanced-images")); + _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"); + } + + public void AddParts(IEnumerable enhancers) + { + ImageEnhancers = enhancers.ToArray(); } - /// - /// Processes an image by resizing to target dimensions - /// - /// The entity that owns the image - /// The image type - /// The image index (currently only used with backdrops) - /// The original image path. - /// if set to true [crop whitespace]. - /// The last date modified of the original image file - /// The stream to save the new image to - /// Use if a fixed width is required. Aspect ratio will be preserved. - /// Use if a fixed height is required. Aspect ratio will be preserved. - /// Use if a max width is required. Aspect ratio will be preserved. - /// Use if a max height is required. Aspect ratio will be preserved. - /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice. - /// The enhancers. - /// Task. - /// entity public async Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, string originalImagePath, bool cropWhitespace, DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality, List enhancers) { if (entity == null) @@ -117,7 +88,7 @@ namespace MediaBrowser.Controller.Drawing if (cropWhitespace) { - originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); + originalImagePath = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); } // No enhancement - don't cache @@ -246,254 +217,18 @@ namespace MediaBrowser.Controller.Drawing } } - /// - /// Caches the resized image. - /// - /// The cache file path. - /// The bytes. - private async Task CacheResizedImage(string cacheFilePath, byte[] bytes) - { - var parentPath = Path.GetDirectoryName(cacheFilePath); - - if (!Directory.Exists(parentPath)) - { - Directory.CreateDirectory(parentPath); - } - - // 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); - } - } - - /// - /// Gets the cache file path based on a set of parameters - /// - /// The path to the original image file - /// The size to output the image in - /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice. - /// The last modified date of the image - /// System.String. - private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified) - { - var filename = originalPath; - - filename += "width=" + outputSize.Width; - - filename += "height=" + outputSize.Height; - - filename += "quality=" + quality; - - filename += "datemodified=" + dateModified.Ticks; - - return ResizedImageCache.GetResourcePath(filename, Path.GetExtension(originalPath)); - } - - - /// - /// Gets image dimensions - /// - /// The image path. - /// The date modified. - /// Task{ImageSize}. - /// imagePath - public ImageSize GetImageSize(string imagePath, DateTime dateModified) - { - if (string.IsNullOrEmpty(imagePath)) - { - throw new ArgumentNullException("imagePath"); - } - - var name = imagePath + "datemodified=" + dateModified.Ticks; - - ImageSize size; - - if (!_cachedImagedSizes.TryGetValue(name, out size)) - { - size = GetImageSize(name, imagePath); - - _cachedImagedSizes.AddOrUpdate(name, size, (keyName, oldValue) => size); - } - - return size; - } - - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Gets the size of the image. - /// - /// Name of the key. - /// The image path. - /// ImageSize. - private ImageSize GetImageSize(string keyName, string imagePath) - { - // Now check the file system cache - var fullCachePath = ImageSizeCache.GetResourcePath(keyName, ".txt"); - - try - { - var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray(); - - return new ImageSize { Width = result[0], Height = result[1] }; - } - catch (IOException) - { - // Cache file doesn't exist or is currently being written to - } - - var syncLock = GetObjectLock(fullCachePath); - - lock (syncLock) - { - try - { - var result = File.ReadAllText(fullCachePath) - .Split('|') - .Select(i => double.Parse(i, UsCulture)) - .ToArray(); - - return new ImageSize { Width = result[0], Height = result[1] }; - } - catch (FileNotFoundException) - { - // Cache file doesn't exist no biggie - } - catch (DirectoryNotFoundException) - { - // Cache file doesn't exist no biggie - } - - var size = ImageHeader.GetDimensions(imagePath, _logger); - - var parentPath = Path.GetDirectoryName(fullCachePath); - - if (!Directory.Exists(parentPath)) - { - 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 }; - } - } - - /// - /// Gets the image path. - /// - /// The item. - /// Type of the image. - /// Index of the image. - /// System.String. - /// item - /// - public string GetImagePath(BaseItem item, ImageType imageType, int imageIndex) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (imageType == ImageType.Backdrop) - { - if (item.BackdropImagePaths == null) - { - throw new InvalidOperationException(string.Format("Item {0} does not have any Backdrops.", item.Name)); - } - - return item.BackdropImagePaths[imageIndex]; - } - - if (imageType == ImageType.Screenshot) - { - if (item.ScreenshotImagePaths == null) - { - throw new InvalidOperationException(string.Format("Item {0} does not have any Screenshots.", item.Name)); - } - - return item.ScreenshotImagePaths[imageIndex]; - } - - if (imageType == ImageType.Chapter) - { - return _itemRepo.GetChapter(item.Id, imageIndex).ImagePath; - } - - return item.GetImage(imageType); - } - - /// - /// Gets the image date modified. - /// - /// The item. - /// Type of the image. - /// Index of the image. - /// DateTime. - /// item - public DateTime GetImageDateModified(BaseItem item, ImageType imageType, int imageIndex) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - var imagePath = GetImagePath(item, imageType, imageIndex); - - return GetImageDateModified(item, imagePath); - } - - /// - /// Gets the image date modified. - /// - /// The item. - /// The image path. - /// DateTime. - /// item - public DateTime GetImageDateModified(BaseItem item, string imagePath) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (string.IsNullOrEmpty(imagePath)) - { - throw new ArgumentNullException("imagePath"); - } - - var metaFileEntry = item.ResolveArgs.GetMetaFileByPath(imagePath); - - // If we didn't the metafile entry, check the Season - if (metaFileEntry == null) - { - var episode = item as Episode; - - if (episode != null && episode.Season != null) - { - episode.Season.ResolveArgs.GetMetaFileByPath(imagePath); - } - } - - // See if we can avoid a file system lookup by looking for the file in ResolveArgs - return metaFileEntry == null ? File.GetLastWriteTimeUtc(imagePath) : metaFileEntry.LastWriteTimeUtc; - } - /// /// Crops whitespace from an image, caches the result, and returns the cached path /// /// The original image path. /// The date modified. /// System.String. - private async Task GetCroppedImage(string originalImagePath, DateTime dateModified) + private async Task GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified) { var name = originalImagePath; name += "datemodified=" + dateModified.Ticks; - var croppedImagePath = CroppedImageCache.GetResourcePath(name, Path.GetExtension(originalImagePath)); + var croppedImagePath = GetCachePath(_croppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath)); var semaphore = GetLock(croppedImagePath); @@ -552,6 +287,210 @@ namespace MediaBrowser.Controller.Drawing return croppedImagePath; } + /// + /// Caches the resized image. + /// + /// The cache file path. + /// The bytes. + private async Task CacheResizedImage(string cacheFilePath, byte[] bytes) + { + var parentPath = Path.GetDirectoryName(cacheFilePath); + + if (!Directory.Exists(parentPath)) + { + Directory.CreateDirectory(parentPath); + } + + // 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); + } + } + + /// + /// Gets the cache file path based on a set of parameters + /// + /// The path to the original image file + /// The size to output the image in + /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice. + /// The last modified date of the image + /// System.String. + private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified) + { + var filename = originalPath; + + filename += "width=" + outputSize.Width; + + filename += "height=" + outputSize.Height; + + filename += "quality=" + quality; + + filename += "datemodified=" + dateModified.Ticks; + + return GetCachePath(_resizedImageCachePath, filename, Path.GetExtension(originalPath)); + } + + /// + /// Gets the size of the image. + /// + /// The path. + /// ImageSize. + public ImageSize GetImageSize(string path) + { + return GetImageSize(path, File.GetLastWriteTimeUtc(path)); + } + + /// + /// Gets the size of the image. + /// + /// The path. + /// The image date modified. + /// ImageSize. + /// path + public ImageSize GetImageSize(string path, DateTime imageDateModified) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + + var name = path + "datemodified=" + imageDateModified.Ticks; + + ImageSize size; + + if (!_cachedImagedSizes.TryGetValue(name, out size)) + { + size = GetImageSizeInternal(name, path); + + _cachedImagedSizes.AddOrUpdate(name, size, (keyName, oldValue) => size); + } + + return size; + } + + /// + /// Gets the image size internal. + /// + /// The cache key. + /// The path. + /// ImageSize. + private ImageSize GetImageSizeInternal(string cacheKey, string path) + { + // Now check the file system cache + var fullCachePath = GetCachePath(_imageSizeCachePath, cacheKey, ".txt"); + + try + { + var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray(); + + return new ImageSize { Width = result[0], Height = result[1] }; + } + catch (IOException) + { + // Cache file doesn't exist or is currently being written to + } + + var syncLock = GetObjectLock(fullCachePath); + + lock (syncLock) + { + try + { + var result = File.ReadAllText(fullCachePath) + .Split('|') + .Select(i => double.Parse(i, UsCulture)) + .ToArray(); + + return new ImageSize { Width = result[0], Height = result[1] }; + } + catch (FileNotFoundException) + { + // Cache file doesn't exist no biggie + } + catch (DirectoryNotFoundException) + { + // Cache file doesn't exist no biggie + } + + var size = ImageHeader.GetDimensions(path, _logger); + + var parentPath = Path.GetDirectoryName(fullCachePath); + + if (!Directory.Exists(parentPath)) + { + 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 }; + } + } + + /// + /// Gets the image cache tag. + /// + /// The item. + /// Type of the image. + /// The image path. + /// Guid. + /// item + public Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + if (string.IsNullOrEmpty(imagePath)) + { + throw new ArgumentNullException("imagePath"); + } + + var dateModified = item.GetImageDateModified(imagePath); + + var supportedEnhancers = GetSupportedEnhancers(item, imageType).ToList(); + + return GetImageCacheTag(item, imageType, imagePath, dateModified, supportedEnhancers); + } + + /// + /// Gets the image cache tag. + /// + /// The item. + /// Type of the image. + /// The original image path. + /// The date modified of the original image file. + /// The image enhancers. + /// Guid. + /// item + public Guid GetImageCacheTag(BaseItem item, ImageType imageType, string originalImagePath, DateTime dateModified, IEnumerable imageEnhancers) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + if (imageEnhancers == null) + { + throw new ArgumentNullException("imageEnhancers"); + } + + if (string.IsNullOrEmpty(originalImagePath)) + { + throw new ArgumentNullException("originalImagePath"); + } + + // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes + var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList(); + cacheKeys.Add(originalImagePath + dateModified.Ticks); + + return string.Join("|", cacheKeys.ToArray()).GetMD5(); + } + /// /// Gets the enhanced image. /// @@ -610,10 +549,10 @@ namespace MediaBrowser.Controller.Drawing throw new ArgumentNullException("item"); } - var cacheGuid = GetImageCacheTag(originalImagePath, dateModified, supportedEnhancers, item, imageType); + var cacheGuid = GetImageCacheTag(item, imageType, originalImagePath, dateModified, supportedEnhancers); // All enhanced images are saved as png to allow transparency - var enhancedImagePath = EnhancedImageCache.GetResourcePath(cacheGuid + ".png"); + var enhancedImagePath = GetCachePath(_enhancedImageCachePath, cacheGuid + ".png"); var semaphore = GetLock(enhancedImagePath); @@ -665,80 +604,6 @@ namespace MediaBrowser.Controller.Drawing return enhancedImagePath; } - /// - /// Gets the image cache tag. - /// - /// The item. - /// Type of the image. - /// The image path. - /// Guid. - /// item - public Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (string.IsNullOrEmpty(imagePath)) - { - throw new ArgumentNullException("imagePath"); - } - - var dateModified = GetImageDateModified(item, imagePath); - - var supportedEnhancers = ImageEnhancers.Where(i => - { - try - { - return i.Supports(item, imageType); - } - catch (Exception ex) - { - _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name); - - return false; - } - - }).ToList(); - - return GetImageCacheTag(imagePath, dateModified, supportedEnhancers, item, imageType); - } - - /// - /// Gets the image cache tag. - /// - /// The original image path. - /// The date modified of the original image file. - /// The image enhancers. - /// The item. - /// Type of the image. - /// Guid. - /// item - public Guid GetImageCacheTag(string originalImagePath, DateTime dateModified, IEnumerable imageEnhancers, BaseItem item, ImageType imageType) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (imageEnhancers == null) - { - throw new ArgumentNullException("imageEnhancers"); - } - - if (string.IsNullOrEmpty(originalImagePath)) - { - throw new ArgumentNullException("originalImagePath"); - } - - // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes - var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList(); - cacheKeys.Add(originalImagePath + dateModified.Ticks); - - return string.Join("|", cacheKeys.ToArray()).GetMD5(); - } - /// /// Executes the image enhancers. /// @@ -772,6 +637,21 @@ namespace MediaBrowser.Controller.Drawing return result; } + /// + /// The _semaphoreLocks + /// + private readonly ConcurrentDictionary _locks = new ConcurrentDictionary(); + + /// + /// Gets the lock. + /// + /// The filename. + /// System.Object. + private object GetObjectLock(string filename) + { + return _locks.GetOrAdd(filename, key => new object()); + } + /// /// The _semaphoreLocks /// @@ -788,18 +668,85 @@ namespace MediaBrowser.Controller.Drawing } /// - /// The _semaphoreLocks + /// Gets the cache path. /// - private readonly ConcurrentDictionary _locks = new ConcurrentDictionary(); + /// The path. + /// Name of the unique. + /// The file extension. + /// System.String. + /// + /// path + /// or + /// uniqueName + /// or + /// fileExtension + /// + public string GetCachePath(string path, string uniqueName, string fileExtension) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + if (string.IsNullOrEmpty(uniqueName)) + { + throw new ArgumentNullException("uniqueName"); + } + + if (string.IsNullOrEmpty(fileExtension)) + { + throw new ArgumentNullException("fileExtension"); + } + + var filename = uniqueName.GetMD5() + fileExtension; + + return GetCachePath(path, filename); + } /// - /// Gets the lock. + /// Gets the cache path. /// + /// The path. /// The filename. - /// System.Object. - private object GetObjectLock(string filename) + /// System.String. + /// + /// path + /// or + /// filename + /// + public string GetCachePath(string path, string filename) { - return _locks.GetOrAdd(filename, key => new object()); + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + if (string.IsNullOrEmpty(filename)) + { + throw new ArgumentNullException("filename"); + } + + var prefix = filename.Substring(0, 1); + + path = Path.Combine(path, prefix); + + return Path.Combine(path, filename); + } + + public IEnumerable GetSupportedEnhancers(BaseItem item, ImageType imageType) + { + return ImageEnhancers.Where(i => + { + try + { + return i.Supports(item as BaseItem, imageType); + } + catch (Exception ex) + { + _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name); + + return false; + } + + }).ToList(); } } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 24b6f0fce..99878e2ec 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1,5 +1,5 @@ using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -30,13 +30,16 @@ namespace MediaBrowser.Server.Implementations.Dto private readonly IUserDataRepository _userDataRepository; private readonly IItemRepository _itemRepo; - public DtoService(ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IUserDataRepository userDataRepository, IItemRepository itemRepo) + private readonly IImageProcessor _imageProcessor; + + public DtoService(ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor) { _logger = logger; _libraryManager = libraryManager; _userManager = userManager; _userDataRepository = userDataRepository; _itemRepo = itemRepo; + _imageProcessor = imageProcessor; } /// @@ -209,7 +212,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (!string.IsNullOrEmpty(image)) { - dto.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(user, ImageType.Primary, image); + dto.PrimaryImageTag = _imageProcessor.GetImageCacheTag(user, ImageType.Primary, image); try { @@ -288,7 +291,7 @@ namespace MediaBrowser.Server.Implementations.Dto { try { - info.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Primary, imagePath); + info.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary, imagePath); } catch (IOException) { @@ -409,7 +412,7 @@ namespace MediaBrowser.Server.Implementations.Dto { try { - return Kernel.Instance.ImageManager.GetImageCacheTag(item, type, path); + return _imageProcessor.GetImageCacheTag(item, type, path); } catch (IOException ex) { @@ -1154,7 +1157,7 @@ namespace MediaBrowser.Server.Implementations.Dto try { - size = Kernel.Instance.ImageManager.GetImageSize(path, dateModified); + size = _imageProcessor.GetImageSize(path, dateModified); } catch (FileNotFoundException) { @@ -1169,21 +1172,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height; - var supportedEnhancers = Kernel.Instance.ImageManager.ImageEnhancers.Where(i => - { - try - { - return i.Supports(item, ImageType.Primary); - } - catch (Exception ex) - { - _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name); - - return false; - } - - }).ToList(); - + var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList(); foreach (var enhancer in supportedEnhancers) { @@ -1199,6 +1188,5 @@ namespace MediaBrowser.Server.Implementations.Dto dto.PrimaryImageAspectRatio = size.Width / size.Height; } - } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 22de1e898..ff9ff4735 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -91,6 +91,7 @@ False ..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.Linq.dll + ..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll @@ -112,6 +113,7 @@ + @@ -128,6 +130,7 @@ + diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index d7e228b18..8f738c5dc 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -34,6 +34,7 @@ using MediaBrowser.Providers; using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Implementations.BdInfo; using MediaBrowser.Server.Implementations.Configuration; +using MediaBrowser.Server.Implementations.Drawing; using MediaBrowser.Server.Implementations.Dto; using MediaBrowser.Server.Implementations.HttpServer; using MediaBrowser.Server.Implementations.IO; @@ -160,6 +161,7 @@ namespace MediaBrowser.ServerApplication /// The HTTP server. private IHttpServer HttpServer { get; set; } private IDtoService DtoService { get; set; } + private IImageProcessor ImageProcessor { get; set; } /// /// Gets or sets the media encoder. @@ -295,7 +297,10 @@ namespace MediaBrowser.ServerApplication LocalizationManager = new LocalizationManager(ServerConfigurationManager); RegisterSingleInstance(LocalizationManager); - DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataRepository, ItemRepository); + ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths); + RegisterSingleInstance(ImageProcessor); + + DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataRepository, ItemRepository, ImageProcessor); RegisterSingleInstance(DtoService); var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false)); @@ -314,11 +319,8 @@ namespace MediaBrowser.ServerApplication /// private void SetKernelProperties() { - ServerKernel.ImageManager = new ImageManager(LogManager.GetLogger("ImageManager"), - ApplicationPaths, ItemRepository); Parallel.Invoke( () => ServerKernel.FFMpegManager = new FFMpegManager(ApplicationPaths, MediaEncoder, Logger, ItemRepository), - () => ServerKernel.ImageManager.ImageEnhancers = GetExports().OrderBy(e => e.Priority).ToArray(), () => LocalizedStrings.StringFiles = GetExports(), SetStaticProperties ); @@ -461,6 +463,8 @@ namespace MediaBrowser.ServerApplication ProviderManager.AddParts(GetExports().ToArray()); IsoManager.AddParts(GetExports().ToArray()); + + ImageProcessor.AddParts(GetExports().ToArray()); } ///