From 76658f07977a5857c752dc1266b66f881b454f48 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Feb 2014 15:30:41 -0500 Subject: [PATCH] create images list object --- .../DefaultTheme/DefaultThemeService.cs | 31 +- MediaBrowser.Api/Images/ImageService.cs | 87 +++-- MediaBrowser.Api/SearchService.cs | 24 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 15 - .../Drawing/IImageProcessor.cs | 25 +- MediaBrowser.Controller/Entities/BaseItem.cs | 315 +++++++----------- MediaBrowser.Controller/Entities/Game.cs | 7 - .../Entities/IHasImages.cs | 50 ++- .../Entities/IHasScreenshots.cs | 8 +- .../Entities/ItemImageInfo.cs | 14 + .../MediaBrowser.Controller.csproj | 1 + .../Providers/ILocalImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 70 +--- .../Manager/ItemImageProvider.cs | 100 ++---- .../Manager/ProviderManager.cs | 56 ++-- MediaBrowser.Providers/TV/EpisodeXmlParser.cs | 18 +- .../Drawing/ImageProcessor.cs | 20 +- .../Dto/DtoService.cs | 128 ++++--- .../LiveTv/LiveTvDtoService.cs | 9 +- .../ApplicationHost.cs | 2 +- .../LibraryExplorer.xaml.cs | 4 +- 21 files changed, 412 insertions(+), 574 deletions(-) create mode 100644 MediaBrowser.Controller/Entities/ItemImageInfo.cs diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs index 6a91897f2f..afba8c3604 100644 --- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs +++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs @@ -115,7 +115,7 @@ namespace MediaBrowser.Api.DefaultTheme var itemsWithImages = allFavoriteItems.Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)) .ToList(); - var itemsWithBackdrops = allFavoriteItems.Where(i => i.BackdropImagePaths.Count > 0) + var itemsWithBackdrops = allFavoriteItems.Where(i => i.GetImages(ImageType.Backdrop).Any()) .ToList(); var view = new FavoritesView(); @@ -227,7 +227,7 @@ namespace MediaBrowser.Api.DefaultTheme var gamesWithImages = items.OfType().Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)).ToList(); - var itemsWithBackdrops = FilterItemsForBackdropDisplay(items.Where(i => i.BackdropImagePaths.Count > 0)).ToList(); + var itemsWithBackdrops = FilterItemsForBackdropDisplay(items.Where(i => i.GetImages(ImageType.Backdrop).Any())).ToList(); var gamesWithBackdrops = itemsWithBackdrops.OfType().ToList(); @@ -282,7 +282,7 @@ namespace MediaBrowser.Api.DefaultTheme .OfType() .ToList(); - var seriesWithBackdrops = series.Where(i => i.BackdropImagePaths.Count > 0).ToList(); + var seriesWithBackdrops = series.Where(i => i.GetImages(ImageType.Backdrop).Any()).ToList(); var view = new TvView(); @@ -298,7 +298,7 @@ namespace MediaBrowser.Api.DefaultTheme .ToList(); view.ShowsItems = series - .Where(i => i.BackdropImagePaths.Count > 0) + .Where(i => i.GetImages(ImageType.Backdrop).Any()) .Randomize("all") .Select(i => GetItemStub(i, ImageType.Backdrop)) .Where(i => i != null) @@ -425,7 +425,7 @@ namespace MediaBrowser.Api.DefaultTheme view.FamilyMoviePercentage /= movies.Count; var moviesWithBackdrops = movies - .Where(i => i.BackdropImagePaths.Count > 0) + .Where(i => i.GetImages(ImageType.Backdrop).Any()) .ToList(); var fields = new List(); @@ -456,7 +456,7 @@ namespace MediaBrowser.Api.DefaultTheme view.BoxSetItems = items .OfType() - .Where(i => i.BackdropImagePaths.Count > 0) + .Where(i => i.GetImages(ImageType.Backdrop).Any()) .Randomize() .Select(i => GetItemStub(i, ImageType.Backdrop)) .Where(i => i != null) @@ -491,7 +491,7 @@ namespace MediaBrowser.Api.DefaultTheme .ToList(); view.HDItems = hdMovies - .Where(i => i.BackdropImagePaths.Count > 0) + .Where(i => i.GetImages(ImageType.Backdrop).Any()) .Randomize("hd") .Select(i => GetItemStub(i, ImageType.Backdrop)) .Where(i => i != null) @@ -499,7 +499,7 @@ namespace MediaBrowser.Api.DefaultTheme .ToList(); view.FamilyMovies = familyMovies - .Where(i => i.BackdropImagePaths.Count > 0) + .Where(i => i.GetImages(ImageType.Backdrop).Any()) .Randomize("family") .Select(i => GetItemStub(i, ImageType.Backdrop)) .Where(i => i != null) @@ -575,7 +575,7 @@ namespace MediaBrowser.Api.DefaultTheme private IEnumerable FilterItemsForBackdropDisplay(IEnumerable items) { var tuples = items - .Select(i => new Tuple(i, GetResolution(i, i.BackdropImagePaths[0]))) + .Select(i => new Tuple(i, GetResolution(i, ImageType.Backdrop, 0))) .Where(i => i.Item2 > 0) .ToList(); @@ -591,13 +591,13 @@ namespace MediaBrowser.Api.DefaultTheme return tuples.Select(i => i.Item1); } - private double GetResolution(BaseItem item, string path) + private double GetResolution(BaseItem item, ImageType type, int index) { try { - var date = item.GetImageDateModified(path); + var info = item.GetImageInfo(type, index); - var size = _imageProcessor.GetImageSize(path, date); + var size = _imageProcessor.GetImageSize(info.Path, info.DateModified); return size.Width; } @@ -618,9 +618,12 @@ namespace MediaBrowser.Api.DefaultTheme try { - var imagePath = item.GetImagePath(imageType, 0); + var tag = _imageProcessor.GetImageCacheTag(item, imageType); - stub.ImageTag = _imageProcessor.GetImageCacheTag(item, imageType, imagePath); + if (tag.HasValue) + { + stub.ImageTag = tag.Value; + } } catch (Exception ex) { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 514e856550..8cc1eabd0b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -334,12 +335,12 @@ namespace MediaBrowser.Api.Images private readonly IItemRepository _itemRepo; private readonly IDtoService _dtoService; private readonly IImageProcessor _imageProcessor; - + private readonly IFileSystem _fileSystem; /// /// Initializes a new instance of the class. /// - public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor) + public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem) { _userManager = userManager; _libraryManager = libraryManager; @@ -348,6 +349,7 @@ namespace MediaBrowser.Api.Images _itemRepo = itemRepo; _dtoService = dtoService; _imageProcessor = imageProcessor; + _fileSystem = fileSystem; } /// @@ -395,9 +397,9 @@ namespace MediaBrowser.Api.Images { var list = new List(); - foreach (var image in item.Images) + foreach (var image in item.ImageInfos.Where(i => !item.AllowsMultipleImages(i.Type))) { - var info = GetImageInfo(image.Value, item, null, image.Key); + var info = GetImageInfo(item, image, null); if (info != null) { @@ -405,28 +407,16 @@ namespace MediaBrowser.Api.Images } } - var index = 0; - - foreach (var image in item.BackdropImagePaths) + foreach (var imageType in item.ImageInfos.Select(i => i.Type).Distinct().Where(item.AllowsMultipleImages)) { - var info = GetImageInfo(image, item, index, ImageType.Backdrop); - - if (info != null) - { - list.Add(info); - } + var index = 0; - index++; - } + // Prevent implicitly captured closure + var currentImageType = imageType; - index = 0; - - var hasScreenshots = item as IHasScreenshots; - if (hasScreenshots != null) - { - foreach (var image in hasScreenshots.ScreenshotImagePaths) + foreach (var image in item.ImageInfos.Where(i => i.Type == currentImageType)) { - var info = GetImageInfo(image, item, index, ImageType.Screenshot); + var info = GetImageInfo(item, image, index); if (info != null) { @@ -441,7 +431,7 @@ namespace MediaBrowser.Api.Images if (video != null) { - index = 0; + var index = 0; foreach (var chapter in _itemRepo.GetChapters(video.Id)) { @@ -449,7 +439,13 @@ namespace MediaBrowser.Api.Images { var image = chapter.ImagePath; - var info = GetImageInfo(image, item, index, ImageType.Chapter); + var info = GetImageInfo(item, new ItemImageInfo + { + Path = image, + Type = ImageType.Chapter, + DateModified = _fileSystem.GetLastWriteTimeUtc(image) + + }, index); if (info != null) { @@ -464,20 +460,20 @@ namespace MediaBrowser.Api.Images return list; } - private ImageInfo GetImageInfo(string path, IHasImages item, int? imageIndex, ImageType type) + private ImageInfo GetImageInfo(IHasImages item, ItemImageInfo info, int? imageIndex) { try { - var fileInfo = new FileInfo(path); + var fileInfo = new FileInfo(info.Path); - var size = _imageProcessor.GetImageSize(path); + var size = _imageProcessor.GetImageSize(info.Path); return new ImageInfo { - Path = path, + Path = info.Path, ImageIndex = imageIndex, - ImageType = type, - ImageTag = _imageProcessor.GetImageCacheTag(item, type, path), + ImageType = info.Type, + ImageTag = _imageProcessor.GetImageCacheTag(item, info), Size = fileInfo.Length, Width = Convert.ToInt32(size.Width), Height = Convert.ToInt32(size.Height) @@ -485,7 +481,7 @@ namespace MediaBrowser.Api.Images } catch (Exception ex) { - Logger.ErrorException("Error getting image information for {0}", ex, path); + Logger.ErrorException("Error getting image information for {0}", ex, info.Path); return null; } @@ -584,7 +580,7 @@ namespace MediaBrowser.Api.Images { var item = _userManager.Users.First(i => i.Id == request.Id); - var task = item.DeleteImage(request.Type, request.Index); + var task = item.DeleteImage(request.Type, request.Index ?? 0); Task.WaitAll(task); } @@ -597,7 +593,7 @@ namespace MediaBrowser.Api.Images { var item = _libraryManager.GetItemById(request.Id); - var task = item.DeleteImage(request.Type, request.Index); + var task = item.DeleteImage(request.Type, request.Index ?? 0); Task.WaitAll(task); } @@ -613,7 +609,7 @@ namespace MediaBrowser.Api.Images var item = GetItemByName(request.Name, type, _libraryManager); - var task = item.DeleteImage(request.Type, request.Index); + var task = item.DeleteImage(request.Type, request.Index ?? 0); Task.WaitAll(task); } @@ -671,15 +667,15 @@ namespace MediaBrowser.Api.Images /// public object GetImage(ImageRequest request, IHasImages item) { - var imagePath = GetImagePath(request, item); + var imageInfo = GetImageInfo(request, item); - if (string.IsNullOrEmpty(imagePath)) + if (imageInfo == null) { throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type)); } // See if we can avoid a file system lookup by looking for the file in ResolveArgs - var originalFileImageDateModified = item.GetImageDateModified(imagePath); + var originalFileImageDateModified = imageInfo.DateModified; var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i => { @@ -696,16 +692,9 @@ namespace MediaBrowser.Api.Images }).ToList() : new List(); - // If the file does not exist GetLastWriteTimeUtc will return jan 1, 1601 as opposed to throwing an exception - // http://msdn.microsoft.com/en-us/library/system.io.file.getlastwritetimeutc.aspx - if (originalFileImageDateModified.Year == 1601 && !File.Exists(imagePath)) - { - throw new ResourceNotFoundException(string.Format("File not found: {0}", imagePath)); - } - - var contentType = GetMimeType(request.Format, imagePath); + var contentType = GetMimeType(request.Format, imageInfo.Path); - var cacheGuid = _imageProcessor.GetImageCacheTag(item, request.Type, imagePath, originalFileImageDateModified, supportedImageEnhancers); + var cacheGuid = _imageProcessor.GetImageCacheTag(item, request.Type, imageInfo.Path, originalFileImageDateModified, supportedImageEnhancers); TimeSpan? cacheDuration = null; @@ -724,7 +713,7 @@ namespace MediaBrowser.Api.Images Request = currentRequest, OriginalImageDateModified = originalFileImageDateModified, Enhancers = supportedImageEnhancers, - OriginalImagePath = imagePath, + OriginalImagePath = imageInfo.Path, ImageProcessor = _imageProcessor }, contentType); @@ -758,11 +747,11 @@ namespace MediaBrowser.Api.Images /// The request. /// The item. /// System.String. - private string GetImagePath(ImageRequest request, IHasImages item) + private ItemImageInfo GetImageInfo(ImageRequest request, IHasImages item) { var index = request.Index ?? 0; - return item.GetImagePath(request.Type, index); + return item.GetImageInfo(request.Type, index); } /// diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 330d7c46f3..18bd8c6956 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -165,9 +165,11 @@ namespace MediaBrowser.Api ProductionYear = item.ProductionYear }; - if (item.HasImage(ImageType.Primary)) + var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); + + if (primaryImageTag.HasValue) { - result.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary, item.GetImagePath(ImageType.Primary)); + result.PrimaryImageTag = primaryImageTag.Value; } SetThumbImageInfo(result, item); @@ -241,8 +243,13 @@ namespace MediaBrowser.Api if (itemWithImage != null) { - hint.ThumbImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb, itemWithImage.GetImagePath(ImageType.Thumb)); - hint.ThumbImageItemId = itemWithImage.Id.ToString("N"); + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb); + + if (tag.HasValue) + { + hint.ThumbImageTag = tag.Value; + hint.ThumbImageItemId = itemWithImage.Id.ToString("N"); + } } } @@ -257,8 +264,13 @@ namespace MediaBrowser.Api if (itemWithImage != null) { - hint.BackdropImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop, itemWithImage.GetImagePath(ImageType.Backdrop, 0)); - hint.BackdropImageItemId = itemWithImage.Id.ToString("N"); + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop); + + if (tag.HasValue) + { + hint.BackdropImageTag = tag.Value; + hint.BackdropImageItemId = itemWithImage.Id.ToString("N"); + } } } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 101a379ea7..39cccf28a8 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -1181,21 +1181,6 @@ namespace MediaBrowser.Api.UserLibrary /// true if the specified item has image; otherwise, false. internal static bool HasImage(BaseItem item, ImageType imageType) { - if (imageType == ImageType.Backdrop) - { - return item.BackdropImagePaths.Count > 0; - } - - if (imageType == ImageType.Screenshot) - { - var hasScreenshots = item as IHasScreenshots; - if (hasScreenshots == null) - { - return false; - } - return hasScreenshots.ScreenshotImagePaths.Count > 0; - } - return item.HasImage(imageType); } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 2ecf3ec9ae..ad5e622fc8 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -53,10 +53,9 @@ namespace MediaBrowser.Controller.Drawing /// Gets the image cache tag. /// /// The item. - /// Type of the image. - /// The image path. + /// The image. /// Guid. - Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath); + Guid GetImageCacheTag(IHasImages item, ItemImageInfo image); /// /// Gets the image cache tag. @@ -87,4 +86,24 @@ namespace MediaBrowser.Controller.Drawing /// Task{System.String}. Task GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex); } + + public static class ImageProcessorExtensions + { + public static Guid? GetImageCacheTag(this IImageProcessor processor, IHasImages item, ImageType imageType) + { + return processor.GetImageCacheTag(item, imageType, 0); + } + + public static Guid? GetImageCacheTag(this IImageProcessor processor, IHasImages item, ImageType imageType, int imageIndex) + { + var imageInfo = item.GetImageInfo(imageType, imageIndex); + + if (imageInfo == null) + { + return null; + } + + return processor.GetImageCacheTag(item, imageInfo); + } + } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1962921e7c..35691a0800 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -28,10 +28,9 @@ namespace MediaBrowser.Controller.Entities Genres = new List(); Studios = new List(); People = new List(); - BackdropImagePaths = new List(); - Images = new Dictionary(); ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); LockedFields = new List(); + ImageInfos = new List(); } /// @@ -48,6 +47,12 @@ namespace MediaBrowser.Controller.Entities public const string ThemeVideosFolderName = "backdrops"; public const string XbmcTrailerFileSuffix = "-trailer"; + public List ImageInfos { get; set; } + + /// + /// Gets a value indicating whether this instance is in mixed folder. + /// + /// true if this instance is in mixed folder; otherwise, false. public bool IsInMixedFolder { get; set; } private string _name; @@ -160,15 +165,8 @@ namespace MediaBrowser.Controller.Entities public string PrimaryImagePath { get { return this.GetImagePath(ImageType.Primary); } - set { this.SetImagePath(ImageType.Primary, value); } } - /// - /// Gets or sets the images. - /// - /// The images. - public Dictionary Images { get; set; } - /// /// Gets or sets the date created. /// @@ -349,12 +347,6 @@ namespace MediaBrowser.Controller.Entities /// The display type of the media. public string DisplayMediaType { get; set; } - /// - /// Gets or sets the backdrop image paths. - /// - /// The backdrop image paths. - public List BackdropImagePaths { get; set; } - /// /// Gets or sets the official rating. /// @@ -1162,43 +1154,31 @@ namespace MediaBrowser.Controller.Entities /// Backdrops should be accessed using Item.Backdrops public bool HasImage(ImageType type, int imageIndex) { - if (type == ImageType.Backdrop) - { - return BackdropImagePaths.Count > imageIndex; - } - if (type == ImageType.Screenshot) - { - var hasScreenshots = this as IHasScreenshots; - return hasScreenshots != null && hasScreenshots.ScreenshotImagePaths.Count > imageIndex; - } - - return !string.IsNullOrEmpty(this.GetImagePath(type)); + return GetImageInfo(type, imageIndex) != null; } - public void SetImagePath(ImageType type, int index, string path) + public void SetImagePath(ImageType type, int index, FileInfo file) { - if (type == ImageType.Backdrop) + if (type == ImageType.Chapter) { - throw new ArgumentException("Backdrops should be accessed using Item.Backdrops"); - } - if (type == ImageType.Screenshot) - { - throw new ArgumentException("Screenshots should be accessed using Item.Screenshots"); + throw new ArgumentException("Cannot set chapter images using SetImagePath"); } - var typeKey = type; + var image = GetImageInfo(type, index); - // If it's null remove the key from the dictionary - if (string.IsNullOrEmpty(path)) + if (image == null) { - if (Images.ContainsKey(typeKey)) + ImageInfos.Add(new ItemImageInfo { - Images.Remove(typeKey); - } + Path = file.FullName, + Type = type, + DateModified = FileSystem.GetLastWriteTimeUtc(file) + }); } else { - Images[typeKey] = path; + image.Path = file.FullName; + image.DateModified = FileSystem.GetLastWriteTimeUtc(file); } } @@ -1208,66 +1188,23 @@ namespace MediaBrowser.Controller.Entities /// The type. /// The index. /// Task. - public Task DeleteImage(ImageType type, int? index) + public Task DeleteImage(ImageType type, int index) { - if (type == ImageType.Backdrop) - { - if (!index.HasValue) - { - throw new ArgumentException("Please specify a backdrop image index to delete."); - } - - var file = BackdropImagePaths[index.Value]; + var info = GetImageInfo(type, index); - BackdropImagePaths.Remove(file); - - // Delete the source file - DeleteImagePath(file); - } - else if (type == ImageType.Screenshot) + if (info == null) { - if (!index.HasValue) - { - throw new ArgumentException("Please specify a screenshot image index to delete."); - } - - var hasScreenshots = (IHasScreenshots)this; - var file = hasScreenshots.ScreenshotImagePaths[index.Value]; - - hasScreenshots.ScreenshotImagePaths.Remove(file); - - // Delete the source file - DeleteImagePath(file); - } - else - { - // Delete the source file - DeleteImagePath(this.GetImagePath(type)); - - // Remove it from the item - this.SetImagePath(type, null); + // Nothing to do + return Task.FromResult(true); } - // Refresh metadata - // Need to disable slow providers or the image might get re-downloaded - return RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = true, - ImageRefreshMode = ImageRefreshMode.ValidationOnly, - MetadataRefreshMode = MetadataRefreshMode.None - - }, CancellationToken.None); - } + // Remove it from the item + ImageInfos.Remove(info); - /// - /// Deletes the image path. - /// - /// The path. - private void DeleteImagePath(string path) - { - var currentFile = new FileInfo(path); + // Delete the source file + var currentFile = new FileInfo(info.Path); - // This will fail if the file is hidden + // Deletion will fail if the file is hidden so remove the attribute first if (currentFile.Exists) { if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) @@ -1277,6 +1214,8 @@ namespace MediaBrowser.Controller.Entities currentFile.Delete(); } + + return LibraryManager.UpdateItem(this, ItemUpdateType.ImageUpdate, CancellationToken.None); } /// @@ -1284,132 +1223,110 @@ namespace MediaBrowser.Controller.Entities /// public bool ValidateImages() { - var changed = false; - - // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below - var deletedKeys = Images - .Where(image => !File.Exists(image.Value)) - .Select(i => i.Key) + var deletedImages = ImageInfos + .Where(image => !File.Exists(image.Path)) .ToList(); - // Now remove them from the dictionary - foreach (var key in deletedKeys) + if (deletedImages.Count > 0) { - Images.Remove(key); - changed = true; + ImageInfos = ImageInfos.Except(deletedImages).ToList(); } - if (ValidateBackdrops()) - { - changed = true; - } - if (ValidateScreenshots()) - { - changed = true; - } - - return changed; + return deletedImages.Count > 0; } /// - /// Validates that backdrops within the item are still on the file system + /// Gets the image path. /// - private bool ValidateBackdrops() + /// Type of the image. + /// Index of the image. + /// System.String. + /// + /// + /// item + public string GetImagePath(ImageType imageType, int imageIndex) { - var changed = false; - - // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below - var deletedImages = BackdropImagePaths - .Where(path => !File.Exists(path)) - .ToList(); - - // Now remove them from the dictionary - foreach (var path in deletedImages) - { - BackdropImagePaths.Remove(path); + var info = GetImageInfo(imageType, imageIndex); - changed = true; - } - - return changed; + return info == null ? null : info.Path; } /// - /// Validates the screenshots. + /// Gets the image information. /// - private bool ValidateScreenshots() + /// Type of the image. + /// Index of the image. + /// ItemImageInfo. + public ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex) { - var changed = false; + if (imageType == ImageType.Chapter) + { + var chapter = ItemRepository.GetChapter(Id, imageIndex); - var hasScreenshots = this as IHasScreenshots; + if (chapter == null) + { + return null; + } - if (hasScreenshots == null) - { - return changed; - } + var path = chapter.ImagePath; - // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below - var deletedImages = hasScreenshots.ScreenshotImagePaths - .Where(path => !File.Exists(path)) - .ToList(); + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } - // Now remove them from the dictionary - foreach (var path in deletedImages) - { - hasScreenshots.ScreenshotImagePaths.Remove(path); - changed = true; + return new ItemImageInfo + { + Path = path, + DateModified = FileSystem.GetLastWriteTimeUtc(path), + Type = imageType + }; } - return changed; + return GetImages(imageType) + .ElementAtOrDefault(imageIndex); } - /// - /// Gets the image path. - /// - /// Type of the image. - /// Index of the image. - /// System.String. - /// - /// - /// item - public string GetImagePath(ImageType imageType, int imageIndex) + public IEnumerable GetImages(ImageType imageType) { - if (imageType == ImageType.Backdrop) - { - return BackdropImagePaths.Count > imageIndex ? BackdropImagePaths[imageIndex] : null; - } - - if (imageType == ImageType.Screenshot) - { - var hasScreenshots = (IHasScreenshots)this; - return hasScreenshots.ScreenshotImagePaths.Count > imageIndex ? hasScreenshots.ScreenshotImagePaths[imageIndex] : null; - } - if (imageType == ImageType.Chapter) { - return ItemRepository.GetChapter(Id, imageIndex).ImagePath; + throw new ArgumentException("No image info for chapter images"); } - string val; - Images.TryGetValue(imageType, out val); - return val; + return ImageInfos.Where(i => i.Type == imageType); } /// - /// Gets the image date modified. + /// Adds the images. /// - /// The image path. - /// DateTime. - /// item - public DateTime GetImageDateModified(string imagePath) + /// Type of the image. + /// The images. + /// true if XXXX, false otherwise. + /// Cannot call AddImages with chapter images + public bool AddImages(ImageType imageType, IEnumerable images) { - if (string.IsNullOrEmpty(imagePath)) + if (imageType == ImageType.Chapter) { - throw new ArgumentNullException("imagePath"); + throw new ArgumentException("Cannot call AddImages with chapter images"); } - // See if we can avoid a file system lookup by looking for the file in ResolveArgs - return FileSystem.GetLastWriteTimeUtc(imagePath); + var existingImagePaths = GetImages(imageType) + .Select(i => i.Path) + .ToList(); + + var newImages = images + .Where(i => !existingImagePaths.Contains(i.FullName, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + ImageInfos.AddRange(newImages.Select(i => new ItemImageInfo + { + Path = i.FullName, + Type = imageType, + DateModified = FileSystem.GetLastWriteTimeUtc(i) + })); + + return newImages.Count > 0; } /// @@ -1421,25 +1338,39 @@ namespace MediaBrowser.Controller.Entities return new[] { Path }; } + public bool AllowsMultipleImages(ImageType type) + { + return type == ImageType.Backdrop || type == ImageType.Screenshot || type == ImageType.Chapter; + } + public Task SwapImages(ImageType type, int index1, int index2) { - if (type != ImageType.Screenshot && type != ImageType.Backdrop) + if (!AllowsMultipleImages(type)) { throw new ArgumentException("The change index operation is only applicable to backdrops and screenshots"); } - var file1 = GetImagePath(type, index1); - var file2 = GetImagePath(type, index2); + var info1 = GetImageInfo(type, index1); + var info2 = GetImageInfo(type, index2); - FileSystem.SwapFiles(file1, file2); - - // Directory watchers should repeat this, but do a quick refresh first - return RefreshMetadata(new MetadataRefreshOptions + if (info1 == null || info2 == null) { - ForceSave = true, - MetadataRefreshMode = MetadataRefreshMode.None + // Nothing to do + return Task.FromResult(true); + } + + var path1 = info1.Path; + var path2 = info2.Path; + + FileSystem.SwapFiles(path1, path2); + + info1.Path = path2; + info2.Path = path1; + + info1.DateModified = FileSystem.GetLastWriteTimeUtc(info1.Path); + info2.DateModified = FileSystem.GetLastWriteTimeUtc(info2.Path); - }, CancellationToken.None); + return LibraryManager.UpdateItem(this, ItemUpdateType.ImageUpdate, CancellationToken.None); } public virtual bool IsPlayed(User user) diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index 1e11bdbb33..cc9d9a1a4f 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -30,17 +30,10 @@ namespace MediaBrowser.Controller.Entities ThemeSongIds = new List(); ThemeVideoIds = new List(); Tags = new List(); - ScreenshotImagePaths = new List(); } public List LocalTrailerIds { get; set; } - /// - /// Gets or sets the screenshot image paths. - /// - /// The screenshot image paths. - public List ScreenshotImagePaths { get; set; } - /// /// Gets or sets the tags. /// diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index dd6194bc78..d260950bd2 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using System.IO; +using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -31,6 +32,13 @@ namespace MediaBrowser.Controller.Entities /// The type of the location. LocationType LocationType { get; } + /// + /// Gets the images. + /// + /// Type of the image. + /// IEnumerable{ItemImageInfo}. + IEnumerable GetImages(ImageType imageType); + /// /// Gets the image path. /// @@ -40,19 +48,20 @@ namespace MediaBrowser.Controller.Entities string GetImagePath(ImageType imageType, int imageIndex); /// - /// Gets the image date modified. + /// Gets the image information. /// - /// The image path. - /// DateTime. - DateTime GetImageDateModified(string imagePath); + /// Type of the image. + /// Index of the image. + /// ItemImageInfo. + ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex); /// /// Sets the image. /// /// The type. /// The index. - /// The path. - void SetImagePath(ImageType type, int index, string path); + /// The file. + void SetImagePath(ImageType type, int index, FileInfo file); /// /// Determines whether the specified type has image. @@ -62,6 +71,13 @@ namespace MediaBrowser.Controller.Entities /// true if the specified type has image; otherwise, false. bool HasImage(ImageType type, int imageIndex); + /// + /// Allowses the multiple images. + /// + /// The type. + /// true if XXXX, false otherwise. + bool AllowsMultipleImages(ImageType type); + /// /// Swaps the images. /// @@ -94,12 +110,6 @@ namespace MediaBrowser.Controller.Entities /// bool ValidateImages(); - /// - /// Gets or sets the backdrop image paths. - /// - /// The backdrop image paths. - List BackdropImagePaths { get; set; } - /// /// Gets a value indicating whether this instance is owned item. /// @@ -111,6 +121,14 @@ namespace MediaBrowser.Controller.Entities /// /// The containing folder path. string ContainingFolderPath { get; } + + /// + /// Adds the images. + /// + /// Type of the image. + /// The images. + /// true if XXXX, false otherwise. + bool AddImages(ImageType imageType, IEnumerable images); } public static class HasImagesExtensions @@ -136,10 +154,10 @@ namespace MediaBrowser.Controller.Entities /// /// The item. /// Type of the image. - /// The path. - public static void SetImagePath(this IHasImages item, ImageType imageType, string path) + /// The file. + public static void SetImagePath(this IHasImages item, ImageType imageType, FileInfo file) { - item.SetImagePath(imageType, 0, path); + item.SetImagePath(imageType, 0, file); } } } diff --git a/MediaBrowser.Controller/Entities/IHasScreenshots.cs b/MediaBrowser.Controller/Entities/IHasScreenshots.cs index 341d6403f2..2fd402bc2b 100644 --- a/MediaBrowser.Controller/Entities/IHasScreenshots.cs +++ b/MediaBrowser.Controller/Entities/IHasScreenshots.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Entities { /// @@ -7,10 +6,5 @@ namespace MediaBrowser.Controller.Entities /// public interface IHasScreenshots { - /// - /// Gets or sets the screenshot image paths. - /// - /// The screenshot image paths. - List ScreenshotImagePaths { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs new file mode 100644 index 0000000000..80aec64824 --- /dev/null +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -0,0 +1,14 @@ +using MediaBrowser.Model.Entities; +using System; + +namespace MediaBrowser.Controller.Entities +{ + public class ItemImageInfo + { + public string Path { get; set; } + + public ImageType Type { get; set; } + + public DateTime DateModified { get; set; } + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index f5b43c2abb..00e84177cb 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -104,6 +104,7 @@ + diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index ed7cdc8b2b..69242d1e20 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Providers public void SetFormatFromMimeType(string mimeType) { - + } } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 2a4ef75970..1bccc6bb81 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -107,14 +107,9 @@ namespace MediaBrowser.Providers.Manager } } - if (type == ImageType.Backdrop && imageIndex == null) + if (!imageIndex.HasValue && item.AllowsMultipleImages(type)) { - imageIndex = item.BackdropImagePaths.Count; - } - else if (type == ImageType.Screenshot && imageIndex == null) - { - var hasScreenshots = (IHasScreenshots)item; - imageIndex = hasScreenshots.ScreenshotImagePaths.Count; + imageIndex = item.GetImages(type).Count(); } var index = imageIndex ?? 0; @@ -275,43 +270,7 @@ namespace MediaBrowser.Providers.Manager /// imageIndex private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path) { - switch (type) - { - case ImageType.Screenshot: - - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - - var hasScreenshots = (IHasScreenshots)item; - if (hasScreenshots.ScreenshotImagePaths.Count > imageIndex.Value) - { - hasScreenshots.ScreenshotImagePaths[imageIndex.Value] = path; - } - else if (!hasScreenshots.ScreenshotImagePaths.Contains(path, StringComparer.OrdinalIgnoreCase)) - { - hasScreenshots.ScreenshotImagePaths.Add(path); - } - break; - case ImageType.Backdrop: - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - if (item.BackdropImagePaths.Count > imageIndex.Value) - { - item.BackdropImagePaths[imageIndex.Value] = path; - } - else if (!item.BackdropImagePaths.Contains(path, StringComparer.OrdinalIgnoreCase)) - { - item.BackdropImagePaths.Add(path); - } - break; - default: - item.SetImagePath(type, path); - break; - } + item.SetImagePath(type, imageIndex ?? 0, new FileInfo(path)); } /// @@ -347,19 +306,10 @@ namespace MediaBrowser.Providers.Manager filename = item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : "folder"; break; case ImageType.Backdrop: - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - filename = GetBackdropSaveFilename(item.BackdropImagePaths, "backdrop", "backdrop", imageIndex.Value); + filename = GetBackdropSaveFilename(item.GetImages(type), "backdrop", "backdrop", imageIndex); break; case ImageType.Screenshot: - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - var hasScreenshots = (IHasScreenshots)item; - filename = GetBackdropSaveFilename(hasScreenshots.ScreenshotImagePaths, "screenshot", "screenshot", imageIndex.Value); + filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex); break; default: filename = type.ToString().ToLower(); @@ -404,16 +354,16 @@ namespace MediaBrowser.Providers.Manager return path; } - private string GetBackdropSaveFilename(IEnumerable images, string zeroIndexFilename, string numberedIndexPrefix, int index) + private string GetBackdropSaveFilename(IEnumerable images, string zeroIndexFilename, string numberedIndexPrefix, int? index) { - if (index == 0) + if (index.HasValue && index.Value == 0) { return zeroIndexFilename; } - var filenames = images.Select(Path.GetFileNameWithoutExtension).ToList(); + var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList(); - var current = index; + var current = 1; while (filenames.Contains(numberedIndexPrefix + current.ToString(UsCulture), StringComparer.OrdinalIgnoreCase)) { current++; @@ -484,7 +434,7 @@ namespace MediaBrowser.Providers.Manager return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) }; } - var extraFanartFilename = GetBackdropSaveFilename(item.BackdropImagePaths, "fanart", "fanart", outputIndex); + var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", outputIndex); return new[] { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index bc5579ab65..74c73821cc 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -178,23 +178,16 @@ namespace MediaBrowser.Providers.Manager return false; } - if (images.Contains(ImageType.Backdrop) && item.BackdropImagePaths.Count < backdropLimit) + if (images.Contains(ImageType.Backdrop) && item.GetImages(ImageType.Backdrop).Count() < backdropLimit) { return false; } - if (images.Contains(ImageType.Screenshot)) + if (images.Contains(ImageType.Screenshot) && item.GetImages(ImageType.Screenshot).Count() < backdropLimit) { - var hasScreenshots = item as IHasScreenshots; - if (hasScreenshots != null) - { - if (hasScreenshots.ScreenshotImagePaths.Count < screenshotLimit) - { - return false; - } - } - } - + return false; + } + return true; } @@ -220,7 +213,7 @@ namespace MediaBrowser.Providers.Manager } _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); - + var images = await provider.GetAllImages(item, cancellationToken).ConfigureAwait(false); var list = images.ToList(); @@ -232,12 +225,12 @@ namespace MediaBrowser.Providers.Manager } } - await DownloadBackdrops(item, backdropLimit, provider, result, list, cancellationToken).ConfigureAwait(false); + await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, cancellationToken).ConfigureAwait(false); var hasScreenshots = item as IHasScreenshots; if (hasScreenshots != null) { - await DownloadScreenshots(hasScreenshots, screenshotLimit, provider, result, list, cancellationToken).ConfigureAwait(false); + await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -280,50 +273,42 @@ namespace MediaBrowser.Providers.Manager if (image != null) { - var oldPath = item.GetImagePath(type); + var currentImage = item.GetImageInfo(type, 0); - item.SetImagePath(type, image.Path); - - if (!string.Equals(oldPath, image.Path, StringComparison.OrdinalIgnoreCase)) + if (currentImage == null || !string.Equals(currentImage.Path, image.Path, StringComparison.OrdinalIgnoreCase)) { + item.SetImagePath(type, new FileInfo(image.Path)); changed = true; } } } - // The change reporting will only be accurate at the count level - // Improve this if/when needed var backdrops = images.Where(i => i.Type == ImageType.Backdrop).ToList(); if (backdrops.Count > 0) { - var oldCount = item.BackdropImagePaths.Count; - - item.BackdropImagePaths = item.BackdropImagePaths - .Concat(backdrops.Select(i => i.Path)) - .Distinct(StringComparer.OrdinalIgnoreCase) + var foundImages = images.Where(i => i.Type == ImageType.Backdrop) + .Select(i => new FileInfo(i.Path)) .ToList(); - if (oldCount != item.BackdropImagePaths.Count) + if (foundImages.Count > 0) { - changed = true; + if (item.AddImages(ImageType.Backdrop, foundImages)) + { + changed = true; + } } } var hasScreenshots = item as IHasScreenshots; if (hasScreenshots != null) { - var screenshots = images.Where(i => i.Type == ImageType.Screenshot).ToList(); + var foundImages = images.Where(i => i.Type == ImageType.Screenshot) + .Select(i => new FileInfo(i.Path)) + .ToList(); - if (screenshots.Count > 0) + if (foundImages.Count > 0) { - var oldCount = hasScreenshots.ScreenshotImagePaths.Count; - - hasScreenshots.ScreenshotImagePaths = hasScreenshots.ScreenshotImagePaths - .Concat(screenshots.Select(i => i.Path)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - if (oldCount != hasScreenshots.ScreenshotImagePaths.Count) + if (item.AddImages(ImageType.Screenshot, foundImages)) { changed = true; } @@ -360,46 +345,11 @@ namespace MediaBrowser.Providers.Manager } } - private async Task DownloadBackdrops(IHasImages item, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable images, CancellationToken cancellationToken) + private async Task DownloadBackdrops(IHasImages item, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable images, CancellationToken cancellationToken) { - const ImageType imageType = ImageType.Backdrop; - - foreach (var image in images.Where(i => i.Type == imageType)) - { - if (item.BackdropImagePaths.Count >= limit) - { - break; - } - - var url = image.Url; - - try - { - var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); - - await _providerManager.SaveImage((BaseItem)item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; - break; - } - catch (HttpException ex) - { - // Sometimes providers send back bad url's. Just move onto the next image - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) - { - continue; - } - break; - } - } - } - - private async Task DownloadScreenshots(IHasScreenshots item, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable images, CancellationToken cancellationToken) - { - const ImageType imageType = ImageType.Screenshot; - foreach (var image in images.Where(i => i.Type == imageType)) { - if (item.ScreenshotImagePaths.Count >= limit) + if (item.GetImages(imageType).Count() >= limit) { break; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 030b3cbd90..aec08a2927 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -389,35 +389,33 @@ namespace MediaBrowser.Providers.Manager public IEnumerable GetAllMetadataPlugins() { - var list = new List(); - - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary()); - list.Add(GetPluginSummary /// The item. - /// Type of the image. - /// The image path. + /// The image. /// Guid. /// item - public Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath) + public Guid GetImageCacheTag(IHasImages item, ItemImageInfo image) { if (item == null) { throw new ArgumentNullException("item"); } - if (string.IsNullOrEmpty(imagePath)) + if (image == null) { - throw new ArgumentNullException("imagePath"); + throw new ArgumentNullException("image"); } - var dateModified = item.GetImageDateModified(imagePath); - - var supportedEnhancers = GetSupportedEnhancers(item, imageType); + var supportedEnhancers = GetSupportedEnhancers(item, image.Type); - return GetImageCacheTag(item, imageType, imagePath, dateModified, supportedEnhancers.ToList()); + return GetImageCacheTag(item, image.Type, image.Path, image.DateModified, supportedEnhancers.ToList()); } /// @@ -693,9 +690,10 @@ namespace MediaBrowser.Server.Implementations.Drawing { var enhancers = GetSupportedEnhancers(item, imageType).ToList(); - var imagePath = item.GetImagePath(imageType, imageIndex); + var imageInfo = item.GetImageInfo(imageType, imageIndex); + var imagePath = imageInfo.Path; - var dateModified = item.GetImageDateModified(imagePath); + var dateModified = imageInfo.DateModified; var result = await GetEnhancedImage(imagePath, dateModified, item, imageType, imageIndex, enhancers); diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 84033f9ad8..5fa96c34b7 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -34,8 +35,9 @@ namespace MediaBrowser.Server.Implementations.Dto private readonly IImageProcessor _imageProcessor; private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; - public DtoService(ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config) + public DtoService(ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem) { _logger = logger; _libraryManager = libraryManager; @@ -44,6 +46,7 @@ namespace MediaBrowser.Server.Implementations.Dto _itemRepo = itemRepo; _imageProcessor = imageProcessor; _config = config; + _fileSystem = fileSystem; } /// @@ -207,11 +210,11 @@ namespace MediaBrowser.Server.Implementations.Dto Configuration = user.Configuration }; - var image = user.PrimaryImagePath; + var image = user.GetImageInfo(ImageType.Primary, 0); - if (!string.IsNullOrEmpty(image)) + if (image != null) { - dto.PrimaryImageTag = GetImageCacheTag(user, ImageType.Primary, image); + dto.PrimaryImageTag = GetImageCacheTag(user, image); try { @@ -288,12 +291,7 @@ namespace MediaBrowser.Server.Implementations.Dto RunTimeTicks = item.RunTimeTicks }; - var imagePath = item.PrimaryImagePath; - - if (!string.IsNullOrEmpty(imagePath)) - { - info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary, imagePath); - } + info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary); return info; } @@ -380,11 +378,7 @@ namespace MediaBrowser.Server.Implementations.Dto /// List{System.String}. private List GetBackdropImageTags(BaseItem item) { - return item.BackdropImagePaths - .Select(p => GetImageCacheTag(item, ImageType.Backdrop, p)) - .Where(i => i.HasValue) - .Select(i => i.Value) - .ToList(); + return GetCacheTags(item, ImageType.Backdrop).ToList(); } /// @@ -399,23 +393,40 @@ namespace MediaBrowser.Server.Implementations.Dto { return new List(); } + return GetCacheTags(item, ImageType.Screenshot).ToList(); + } - return hasScreenshots.ScreenshotImagePaths - .Select(p => GetImageCacheTag(item, ImageType.Screenshot, p)) + private IEnumerable GetCacheTags(BaseItem item, ImageType type) + { + return item.GetImages(type) + .Select(p => GetImageCacheTag(item, p)) .Where(i => i.HasValue) .Select(i => i.Value) .ToList(); } - private Guid? GetImageCacheTag(BaseItem item, ImageType type, string path) + private Guid? GetImageCacheTag(BaseItem item, ImageType type) + { + try + { + return _imageProcessor.GetImageCacheTag(item, type); + } + catch (IOException ex) + { + _logger.ErrorException("Error getting {0} image info", ex, type); + return null; + } + } + + private Guid? GetImageCacheTag(BaseItem item, ItemImageInfo image) { try { - return _imageProcessor.GetImageCacheTag(item, type, path); + return _imageProcessor.GetImageCacheTag(item, image); } catch (IOException ex) { - _logger.ErrorException("Error getting {0} image info for {1}", ex, type, path); + _logger.ErrorException("Error getting {0} image info for {1}", ex, image.Type, image.Path); return null; } } @@ -468,12 +479,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (dictionary.TryGetValue(person.Name, out entity)) { - var primaryImagePath = entity.PrimaryImagePath; - - if (!string.IsNullOrEmpty(primaryImagePath)) - { - baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath); - } + baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary); } dto.People[i] = baseItemPerson; @@ -520,12 +526,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (dictionary.TryGetValue(studio, out entity)) { - var primaryImagePath = entity.PrimaryImagePath; - - if (!string.IsNullOrEmpty(primaryImagePath)) - { - studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath); - } + studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary); } dto.Studios[i] = studioDto; @@ -544,7 +545,7 @@ namespace MediaBrowser.Server.Implementations.Dto while (parent != null) { - if (parent.BackdropImagePaths != null && parent.BackdropImagePaths.Count > 0) + if (parent.GetImages(ImageType.Backdrop).Any()) { return parent; } @@ -595,7 +596,12 @@ namespace MediaBrowser.Server.Implementations.Dto if (!string.IsNullOrEmpty(chapterInfo.ImagePath)) { - dto.ImageTag = GetImageCacheTag(item, ImageType.Chapter, chapterInfo.ImagePath); + dto.ImageTag = GetImageCacheTag(item, new ItemImageInfo + { + Path = chapterInfo.ImagePath, + Type = ImageType.Chapter, + DateModified = _fileSystem.GetLastWriteTimeUtc(chapterInfo.ImagePath) + }); } return dto; @@ -698,7 +704,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (fields.Contains(ItemFields.Keywords)) { - var hasTags = item as IHasKeywords; + var hasTags = item as IHasKeywords; if (hasTags != null) { dto.Keywords = hasTags.Keywords; @@ -750,15 +756,15 @@ namespace MediaBrowser.Server.Implementations.Dto dto.ImageTags = new Dictionary(); - foreach (var image in item.Images) + // Prevent implicitly captured closure + var currentItem = item; + foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type))) { - var type = image.Key; - - var tag = GetImageCacheTag(item, type, image.Value); + var tag = GetImageCacheTag(item, image); if (tag.HasValue) { - dto.ImageTags[type] = tag.Value; + dto.ImageTags[image.Type] = tag.Value; } } @@ -804,7 +810,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.CollectionType = collectionFolder.CollectionType; } - + if (fields.Contains(ItemFields.RemoteTrailers)) { dto.RemoteTrailers = hasTrailers != null ? @@ -862,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentLogoItemId = GetDtoId(parentWithLogo); - dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo, parentWithLogo.GetImagePath(ImageType.Logo)); + dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo); } } @@ -875,7 +881,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentArtItemId = GetDtoId(parentWithImage); - dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImagePath(ImageType.Art)); + dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art); } } @@ -888,7 +894,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentThumbItemId = GetDtoId(parentWithImage); - dto.ParentThumbImageTag = GetImageCacheTag(parentWithImage, ImageType.Thumb, parentWithImage.GetImagePath(ImageType.Thumb)); + dto.ParentThumbImageTag = GetImageCacheTag(parentWithImage, ImageType.Thumb); } } @@ -959,12 +965,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.AlbumId = GetDtoId(albumParent); - var imagePath = albumParent.PrimaryImagePath; - - if (!string.IsNullOrEmpty(imagePath)) - { - dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary, imagePath); - } + dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary); } } @@ -1085,17 +1086,9 @@ namespace MediaBrowser.Server.Implementations.Dto dto.AirTime = series.AirTime; dto.SeriesStudio = series.Studios.FirstOrDefault(); - if (series.HasImage(ImageType.Thumb)) - { - dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb, series.GetImagePath(ImageType.Thumb)); - } - - var imagePath = series.PrimaryImagePath; + dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb); - if (!string.IsNullOrEmpty(imagePath)) - { - dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary, imagePath); - } + dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); } // Add SeasonInfo @@ -1110,12 +1103,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.AirTime = series.AirTime; dto.SeriesStudio = series.Studios.FirstOrDefault(); - var imagePath = series.PrimaryImagePath; - - if (!string.IsNullOrEmpty(imagePath)) - { - dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary, imagePath); - } + dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); } var game = item as Game; @@ -1303,15 +1291,17 @@ namespace MediaBrowser.Server.Implementations.Dto /// Task. public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item) { - var path = item.PrimaryImagePath; + var imageInfo = item.GetImageInfo(ImageType.Primary, 0); - if (string.IsNullOrEmpty(path)) + if (imageInfo == null) { return; } + var path = imageInfo.Path; + // See if we can avoid a file system lookup by looking for the file in ResolveArgs - var dateModified = item.GetImageDateModified(path); + var dateModified = imageInfo.DateModified; ImageSize size; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 4805adb1f0..22d683e1b6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -401,16 +401,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv private Guid? GetImageTag(IHasImages info) { - var path = info.PrimaryImagePath; - - if (string.IsNullOrEmpty(path)) - { - return null; - } - try { - return _imageProcessor.GetImageCacheTag(info, ImageType.Primary, path); + return _imageProcessor.GetImageCacheTag(info, ImageType.Primary); } catch (Exception ex) { diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index d7858222e1..cd2f5779a8 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -309,7 +309,7 @@ namespace MediaBrowser.ServerApplication ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); RegisterSingleInstance(ImageProcessor); - DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager); + DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(DtoService); var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index 51d6615183..66a99f2e5a 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -258,8 +258,8 @@ namespace MediaBrowser.ServerApplication previews.Add(new PreviewItem(item.GetImagePath(ImageType.Thumb), "Thumb")); } previews.AddRange( - item.BackdropImagePaths.Select( - image => new PreviewItem(image, "Backdrop"))); + item.GetImages(ImageType.Backdrop).Select( + image => new PreviewItem(image.Path, "Backdrop"))); }); lstPreviews.ItemsSource = previews; lstPreviews.Items.Refresh();