create images list object

pull/702/head
Luke Pulverenti 11 years ago
parent 5e2a2a02ef
commit 76658f0797

@ -115,7 +115,7 @@ namespace MediaBrowser.Api.DefaultTheme
var itemsWithImages = allFavoriteItems.Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)) var itemsWithImages = allFavoriteItems.Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
.ToList(); .ToList();
var itemsWithBackdrops = allFavoriteItems.Where(i => i.BackdropImagePaths.Count > 0) var itemsWithBackdrops = allFavoriteItems.Where(i => i.GetImages(ImageType.Backdrop).Any())
.ToList(); .ToList();
var view = new FavoritesView(); var view = new FavoritesView();
@ -227,7 +227,7 @@ namespace MediaBrowser.Api.DefaultTheme
var gamesWithImages = items.OfType<Game>().Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath)).ToList(); var gamesWithImages = items.OfType<Game>().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<Game>().ToList(); var gamesWithBackdrops = itemsWithBackdrops.OfType<Game>().ToList();
@ -282,7 +282,7 @@ namespace MediaBrowser.Api.DefaultTheme
.OfType<Series>() .OfType<Series>()
.ToList(); .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(); var view = new TvView();
@ -298,7 +298,7 @@ namespace MediaBrowser.Api.DefaultTheme
.ToList(); .ToList();
view.ShowsItems = series view.ShowsItems = series
.Where(i => i.BackdropImagePaths.Count > 0) .Where(i => i.GetImages(ImageType.Backdrop).Any())
.Randomize("all") .Randomize("all")
.Select(i => GetItemStub(i, ImageType.Backdrop)) .Select(i => GetItemStub(i, ImageType.Backdrop))
.Where(i => i != null) .Where(i => i != null)
@ -425,7 +425,7 @@ namespace MediaBrowser.Api.DefaultTheme
view.FamilyMoviePercentage /= movies.Count; view.FamilyMoviePercentage /= movies.Count;
var moviesWithBackdrops = movies var moviesWithBackdrops = movies
.Where(i => i.BackdropImagePaths.Count > 0) .Where(i => i.GetImages(ImageType.Backdrop).Any())
.ToList(); .ToList();
var fields = new List<ItemFields>(); var fields = new List<ItemFields>();
@ -456,7 +456,7 @@ namespace MediaBrowser.Api.DefaultTheme
view.BoxSetItems = items view.BoxSetItems = items
.OfType<BoxSet>() .OfType<BoxSet>()
.Where(i => i.BackdropImagePaths.Count > 0) .Where(i => i.GetImages(ImageType.Backdrop).Any())
.Randomize() .Randomize()
.Select(i => GetItemStub(i, ImageType.Backdrop)) .Select(i => GetItemStub(i, ImageType.Backdrop))
.Where(i => i != null) .Where(i => i != null)
@ -491,7 +491,7 @@ namespace MediaBrowser.Api.DefaultTheme
.ToList(); .ToList();
view.HDItems = hdMovies view.HDItems = hdMovies
.Where(i => i.BackdropImagePaths.Count > 0) .Where(i => i.GetImages(ImageType.Backdrop).Any())
.Randomize("hd") .Randomize("hd")
.Select(i => GetItemStub(i, ImageType.Backdrop)) .Select(i => GetItemStub(i, ImageType.Backdrop))
.Where(i => i != null) .Where(i => i != null)
@ -499,7 +499,7 @@ namespace MediaBrowser.Api.DefaultTheme
.ToList(); .ToList();
view.FamilyMovies = familyMovies view.FamilyMovies = familyMovies
.Where(i => i.BackdropImagePaths.Count > 0) .Where(i => i.GetImages(ImageType.Backdrop).Any())
.Randomize("family") .Randomize("family")
.Select(i => GetItemStub(i, ImageType.Backdrop)) .Select(i => GetItemStub(i, ImageType.Backdrop))
.Where(i => i != null) .Where(i => i != null)
@ -575,7 +575,7 @@ namespace MediaBrowser.Api.DefaultTheme
private IEnumerable<BaseItem> FilterItemsForBackdropDisplay(IEnumerable<BaseItem> items) private IEnumerable<BaseItem> FilterItemsForBackdropDisplay(IEnumerable<BaseItem> items)
{ {
var tuples = items var tuples = items
.Select(i => new Tuple<BaseItem, double>(i, GetResolution(i, i.BackdropImagePaths[0]))) .Select(i => new Tuple<BaseItem, double>(i, GetResolution(i, ImageType.Backdrop, 0)))
.Where(i => i.Item2 > 0) .Where(i => i.Item2 > 0)
.ToList(); .ToList();
@ -591,13 +591,13 @@ namespace MediaBrowser.Api.DefaultTheme
return tuples.Select(i => i.Item1); return tuples.Select(i => i.Item1);
} }
private double GetResolution(BaseItem item, string path) private double GetResolution(BaseItem item, ImageType type, int index)
{ {
try 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; return size.Width;
} }
@ -618,9 +618,12 @@ namespace MediaBrowser.Api.DefaultTheme
try 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) catch (Exception ex)
{ {

@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -334,12 +335,12 @@ namespace MediaBrowser.Api.Images
private readonly IItemRepository _itemRepo; private readonly IItemRepository _itemRepo;
private readonly IDtoService _dtoService; private readonly IDtoService _dtoService;
private readonly IImageProcessor _imageProcessor; private readonly IImageProcessor _imageProcessor;
private readonly IFileSystem _fileSystem;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageService" /> class. /// Initializes a new instance of the <see cref="ImageService" /> class.
/// </summary> /// </summary>
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; _userManager = userManager;
_libraryManager = libraryManager; _libraryManager = libraryManager;
@ -348,6 +349,7 @@ namespace MediaBrowser.Api.Images
_itemRepo = itemRepo; _itemRepo = itemRepo;
_dtoService = dtoService; _dtoService = dtoService;
_imageProcessor = imageProcessor; _imageProcessor = imageProcessor;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -395,9 +397,9 @@ namespace MediaBrowser.Api.Images
{ {
var list = new List<ImageInfo>(); var list = new List<ImageInfo>();
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) if (info != null)
{ {
@ -405,28 +407,16 @@ namespace MediaBrowser.Api.Images
} }
} }
var index = 0; foreach (var imageType in item.ImageInfos.Select(i => i.Type).Distinct().Where(item.AllowsMultipleImages))
foreach (var image in item.BackdropImagePaths)
{
var info = GetImageInfo(image, item, index, ImageType.Backdrop);
if (info != null)
{ {
list.Add(info); var index = 0;
}
index++;
}
index = 0; // Prevent implicitly captured closure
var currentImageType = imageType;
var hasScreenshots = item as IHasScreenshots; foreach (var image in item.ImageInfos.Where(i => i.Type == currentImageType))
if (hasScreenshots != null)
{
foreach (var image in hasScreenshots.ScreenshotImagePaths)
{ {
var info = GetImageInfo(image, item, index, ImageType.Screenshot); var info = GetImageInfo(item, image, index);
if (info != null) if (info != null)
{ {
@ -441,7 +431,7 @@ namespace MediaBrowser.Api.Images
if (video != null) if (video != null)
{ {
index = 0; var index = 0;
foreach (var chapter in _itemRepo.GetChapters(video.Id)) foreach (var chapter in _itemRepo.GetChapters(video.Id))
{ {
@ -449,7 +439,13 @@ namespace MediaBrowser.Api.Images
{ {
var image = chapter.ImagePath; 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) if (info != null)
{ {
@ -464,20 +460,20 @@ namespace MediaBrowser.Api.Images
return list; return list;
} }
private ImageInfo GetImageInfo(string path, IHasImages item, int? imageIndex, ImageType type) private ImageInfo GetImageInfo(IHasImages item, ItemImageInfo info, int? imageIndex)
{ {
try 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 return new ImageInfo
{ {
Path = path, Path = info.Path,
ImageIndex = imageIndex, ImageIndex = imageIndex,
ImageType = type, ImageType = info.Type,
ImageTag = _imageProcessor.GetImageCacheTag(item, type, path), ImageTag = _imageProcessor.GetImageCacheTag(item, info),
Size = fileInfo.Length, Size = fileInfo.Length,
Width = Convert.ToInt32(size.Width), Width = Convert.ToInt32(size.Width),
Height = Convert.ToInt32(size.Height) Height = Convert.ToInt32(size.Height)
@ -485,7 +481,7 @@ namespace MediaBrowser.Api.Images
} }
catch (Exception ex) 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; return null;
} }
@ -584,7 +580,7 @@ namespace MediaBrowser.Api.Images
{ {
var item = _userManager.Users.First(i => i.Id == request.Id); 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); Task.WaitAll(task);
} }
@ -597,7 +593,7 @@ namespace MediaBrowser.Api.Images
{ {
var item = _libraryManager.GetItemById(request.Id); 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); Task.WaitAll(task);
} }
@ -613,7 +609,7 @@ namespace MediaBrowser.Api.Images
var item = GetItemByName(request.Name, type, _libraryManager); 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); Task.WaitAll(task);
} }
@ -671,15 +667,15 @@ namespace MediaBrowser.Api.Images
/// </exception> /// </exception>
public object GetImage(ImageRequest request, IHasImages item) 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)); 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 // 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 => var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i =>
{ {
@ -696,16 +692,9 @@ namespace MediaBrowser.Api.Images
}).ToList() : new List<IImageEnhancer>(); }).ToList() : new List<IImageEnhancer>();
// If the file does not exist GetLastWriteTimeUtc will return jan 1, 1601 as opposed to throwing an exception var contentType = GetMimeType(request.Format, imageInfo.Path);
// 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 cacheGuid = _imageProcessor.GetImageCacheTag(item, request.Type, imagePath, originalFileImageDateModified, supportedImageEnhancers); var cacheGuid = _imageProcessor.GetImageCacheTag(item, request.Type, imageInfo.Path, originalFileImageDateModified, supportedImageEnhancers);
TimeSpan? cacheDuration = null; TimeSpan? cacheDuration = null;
@ -724,7 +713,7 @@ namespace MediaBrowser.Api.Images
Request = currentRequest, Request = currentRequest,
OriginalImageDateModified = originalFileImageDateModified, OriginalImageDateModified = originalFileImageDateModified,
Enhancers = supportedImageEnhancers, Enhancers = supportedImageEnhancers,
OriginalImagePath = imagePath, OriginalImagePath = imageInfo.Path,
ImageProcessor = _imageProcessor ImageProcessor = _imageProcessor
}, contentType); }, contentType);
@ -758,11 +747,11 @@ namespace MediaBrowser.Api.Images
/// <param name="request">The request.</param> /// <param name="request">The request.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private string GetImagePath(ImageRequest request, IHasImages item) private ItemImageInfo GetImageInfo(ImageRequest request, IHasImages item)
{ {
var index = request.Index ?? 0; var index = request.Index ?? 0;
return item.GetImagePath(request.Type, index); return item.GetImageInfo(request.Type, index);
} }
/// <summary> /// <summary>

@ -165,9 +165,11 @@ namespace MediaBrowser.Api
ProductionYear = item.ProductionYear 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); SetThumbImageInfo(result, item);
@ -241,10 +243,15 @@ namespace MediaBrowser.Api
if (itemWithImage != null) if (itemWithImage != null)
{ {
hint.ThumbImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb, itemWithImage.GetImagePath(ImageType.Thumb)); var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb);
if (tag.HasValue)
{
hint.ThumbImageTag = tag.Value;
hint.ThumbImageItemId = itemWithImage.Id.ToString("N"); hint.ThumbImageItemId = itemWithImage.Id.ToString("N");
} }
} }
}
private void SetBackdropImageInfo(SearchHint hint, BaseItem item) private void SetBackdropImageInfo(SearchHint hint, BaseItem item)
{ {
@ -257,10 +264,15 @@ namespace MediaBrowser.Api
if (itemWithImage != null) if (itemWithImage != null)
{ {
hint.BackdropImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop, itemWithImage.GetImagePath(ImageType.Backdrop, 0)); var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop);
if (tag.HasValue)
{
hint.BackdropImageTag = tag.Value;
hint.BackdropImageItemId = itemWithImage.Id.ToString("N"); hint.BackdropImageItemId = itemWithImage.Id.ToString("N");
} }
} }
}
private T GetParentWithImage<T>(BaseItem item, ImageType type) private T GetParentWithImage<T>(BaseItem item, ImageType type)
where T : BaseItem where T : BaseItem

@ -1181,21 +1181,6 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns><c>true</c> if the specified item has image; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified item has image; otherwise, <c>false</c>.</returns>
internal static bool HasImage(BaseItem item, ImageType imageType) 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); return item.HasImage(imageType);
} }

@ -53,10 +53,9 @@ namespace MediaBrowser.Controller.Drawing
/// Gets the image cache tag. /// Gets the image cache tag.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param> /// <param name="image">The image.</param>
/// <param name="imagePath">The image path.</param>
/// <returns>Guid.</returns> /// <returns>Guid.</returns>
Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath); Guid GetImageCacheTag(IHasImages item, ItemImageInfo image);
/// <summary> /// <summary>
/// Gets the image cache tag. /// Gets the image cache tag.
@ -87,4 +86,24 @@ namespace MediaBrowser.Controller.Drawing
/// <returns>Task{System.String}.</returns> /// <returns>Task{System.String}.</returns>
Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex); Task<string> 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);
}
}
} }

@ -28,10 +28,9 @@ namespace MediaBrowser.Controller.Entities
Genres = new List<string>(); Genres = new List<string>();
Studios = new List<string>(); Studios = new List<string>();
People = new List<PersonInfo>(); People = new List<PersonInfo>();
BackdropImagePaths = new List<string>();
Images = new Dictionary<ImageType, string>();
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
LockedFields = new List<MetadataFields>(); LockedFields = new List<MetadataFields>();
ImageInfos = new List<ItemImageInfo>();
} }
/// <summary> /// <summary>
@ -48,6 +47,12 @@ namespace MediaBrowser.Controller.Entities
public const string ThemeVideosFolderName = "backdrops"; public const string ThemeVideosFolderName = "backdrops";
public const string XbmcTrailerFileSuffix = "-trailer"; public const string XbmcTrailerFileSuffix = "-trailer";
public List<ItemImageInfo> ImageInfos { get; set; }
/// <summary>
/// Gets a value indicating whether this instance is in mixed folder.
/// </summary>
/// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
public bool IsInMixedFolder { get; set; } public bool IsInMixedFolder { get; set; }
private string _name; private string _name;
@ -160,15 +165,8 @@ namespace MediaBrowser.Controller.Entities
public string PrimaryImagePath public string PrimaryImagePath
{ {
get { return this.GetImagePath(ImageType.Primary); } get { return this.GetImagePath(ImageType.Primary); }
set { this.SetImagePath(ImageType.Primary, value); }
} }
/// <summary>
/// Gets or sets the images.
/// </summary>
/// <value>The images.</value>
public Dictionary<ImageType, string> Images { get; set; }
/// <summary> /// <summary>
/// Gets or sets the date created. /// Gets or sets the date created.
/// </summary> /// </summary>
@ -349,12 +347,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The display type of the media.</value> /// <value>The display type of the media.</value>
public string DisplayMediaType { get; set; } public string DisplayMediaType { get; set; }
/// <summary>
/// Gets or sets the backdrop image paths.
/// </summary>
/// <value>The backdrop image paths.</value>
public List<string> BackdropImagePaths { get; set; }
/// <summary> /// <summary>
/// Gets or sets the official rating. /// Gets or sets the official rating.
/// </summary> /// </summary>
@ -1162,43 +1154,31 @@ namespace MediaBrowser.Controller.Entities
/// <exception cref="System.ArgumentException">Backdrops should be accessed using Item.Backdrops</exception> /// <exception cref="System.ArgumentException">Backdrops should be accessed using Item.Backdrops</exception>
public bool HasImage(ImageType type, int imageIndex) public bool HasImage(ImageType type, int imageIndex)
{ {
if (type == ImageType.Backdrop) return GetImageInfo(type, imageIndex) != null;
{
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));
} }
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"); throw new ArgumentException("Cannot set chapter images using SetImagePath");
}
if (type == ImageType.Screenshot)
{
throw new ArgumentException("Screenshots should be accessed using Item.Screenshots");
} }
var typeKey = type; var image = GetImageInfo(type, index);
// If it's null remove the key from the dictionary if (image == null)
if (string.IsNullOrEmpty(path))
{ {
if (Images.ContainsKey(typeKey)) ImageInfos.Add(new ItemImageInfo
{ {
Images.Remove(typeKey); Path = file.FullName,
} Type = type,
DateModified = FileSystem.GetLastWriteTimeUtc(file)
});
} }
else else
{ {
Images[typeKey] = path; image.Path = file.FullName;
image.DateModified = FileSystem.GetLastWriteTimeUtc(file);
} }
} }
@ -1208,66 +1188,23 @@ namespace MediaBrowser.Controller.Entities
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public Task DeleteImage(ImageType type, int? index) public Task DeleteImage(ImageType type, int index)
{
if (type == ImageType.Backdrop)
{ {
if (!index.HasValue) var info = GetImageInfo(type, index);
{
throw new ArgumentException("Please specify a backdrop image index to delete.");
}
var file = BackdropImagePaths[index.Value];
BackdropImagePaths.Remove(file); if (info == null)
// Delete the source file
DeleteImagePath(file);
}
else if (type == ImageType.Screenshot)
{
if (!index.HasValue)
{ {
throw new ArgumentException("Please specify a screenshot image index to delete."); // Nothing to do
return Task.FromResult(true);
} }
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 // Remove it from the item
this.SetImagePath(type, null); ImageInfos.Remove(info);
}
// 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);
}
/// <summary> // Delete the source file
/// Deletes the image path. var currentFile = new FileInfo(info.Path);
/// </summary>
/// <param name="path">The path.</param>
private void DeleteImagePath(string path)
{
var currentFile = new FileInfo(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.Exists)
{ {
if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
@ -1277,6 +1214,8 @@ namespace MediaBrowser.Controller.Entities
currentFile.Delete(); currentFile.Delete();
} }
return LibraryManager.UpdateItem(this, ItemUpdateType.ImageUpdate, CancellationToken.None);
} }
/// <summary> /// <summary>
@ -1284,132 +1223,110 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public bool ValidateImages() public bool ValidateImages()
{ {
var changed = false; var deletedImages = ImageInfos
.Where(image => !File.Exists(image.Path))
// 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)
.ToList(); .ToList();
// Now remove them from the dictionary if (deletedImages.Count > 0)
foreach (var key in deletedKeys)
{ {
Images.Remove(key); ImageInfos = ImageInfos.Except(deletedImages).ToList();
changed = true;
} }
if (ValidateBackdrops()) return deletedImages.Count > 0;
{
changed = true;
}
if (ValidateScreenshots())
{
changed = true;
}
return changed;
} }
/// <summary> /// <summary>
/// Validates that backdrops within the item are still on the file system /// Gets the image path.
/// </summary> /// </summary>
private bool ValidateBackdrops() /// <param name="imageType">Type of the image.</param>
{ /// <param name="imageIndex">Index of the image.</param>
var changed = false; /// <returns>System.String.</returns>
/// <exception cref="System.InvalidOperationException">
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below /// </exception>
var deletedImages = BackdropImagePaths /// <exception cref="System.ArgumentNullException">item</exception>
.Where(path => !File.Exists(path)) public string GetImagePath(ImageType imageType, int imageIndex)
.ToList();
// Now remove them from the dictionary
foreach (var path in deletedImages)
{ {
BackdropImagePaths.Remove(path); var info = GetImageInfo(imageType, imageIndex);
changed = true; return info == null ? null : info.Path;
}
return changed;
} }
/// <summary> /// <summary>
/// Validates the screenshots. /// Gets the image information.
/// </summary> /// </summary>
private bool ValidateScreenshots() /// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>ItemImageInfo.</returns>
public ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex)
{ {
var changed = false; if (imageType == ImageType.Chapter)
{
var hasScreenshots = this as IHasScreenshots; var chapter = ItemRepository.GetChapter(Id, imageIndex);
if (hasScreenshots == null) if (chapter == null)
{ {
return changed; return null;
} }
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below var path = chapter.ImagePath;
var deletedImages = hasScreenshots.ScreenshotImagePaths
.Where(path => !File.Exists(path))
.ToList();
// Now remove them from the dictionary if (string.IsNullOrWhiteSpace(path))
foreach (var path in deletedImages)
{ {
hasScreenshots.ScreenshotImagePaths.Remove(path); return null;
changed = true;
}
return changed;
} }
/// <summary> return new ItemImageInfo
/// Gets the image path.
/// </summary>
/// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>System.String.</returns>
/// <exception cref="System.InvalidOperationException">
/// </exception>
/// <exception cref="System.ArgumentNullException">item</exception>
public string GetImagePath(ImageType imageType, int imageIndex)
{ {
if (imageType == ImageType.Backdrop) Path = path,
{ DateModified = FileSystem.GetLastWriteTimeUtc(path),
return BackdropImagePaths.Count > imageIndex ? BackdropImagePaths[imageIndex] : null; Type = imageType
};
} }
if (imageType == ImageType.Screenshot) return GetImages(imageType)
{ .ElementAtOrDefault(imageIndex);
var hasScreenshots = (IHasScreenshots)this;
return hasScreenshots.ScreenshotImagePaths.Count > imageIndex ? hasScreenshots.ScreenshotImagePaths[imageIndex] : null;
} }
public IEnumerable<ItemImageInfo> GetImages(ImageType imageType)
{
if (imageType == ImageType.Chapter) if (imageType == ImageType.Chapter)
{ {
return ItemRepository.GetChapter(Id, imageIndex).ImagePath; throw new ArgumentException("No image info for chapter images");
} }
string val; return ImageInfos.Where(i => i.Type == imageType);
Images.TryGetValue(imageType, out val);
return val;
} }
/// <summary> /// <summary>
/// Gets the image date modified. /// Adds the images.
/// </summary> /// </summary>
/// <param name="imagePath">The image path.</param> /// <param name="imageType">Type of the image.</param>
/// <returns>DateTime.</returns> /// <param name="images">The images.</param>
/// <exception cref="System.ArgumentNullException">item</exception> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
public DateTime GetImageDateModified(string imagePath) /// <exception cref="System.ArgumentException">Cannot call AddImages with chapter images</exception>
public bool AddImages(ImageType imageType, IEnumerable<FileInfo> 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 var existingImagePaths = GetImages(imageType)
return FileSystem.GetLastWriteTimeUtc(imagePath); .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;
} }
/// <summary> /// <summary>
@ -1421,25 +1338,39 @@ namespace MediaBrowser.Controller.Entities
return new[] { Path }; 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) 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"); throw new ArgumentException("The change index operation is only applicable to backdrops and screenshots");
} }
var file1 = GetImagePath(type, index1); var info1 = GetImageInfo(type, index1);
var file2 = GetImagePath(type, index2); var info2 = GetImageInfo(type, index2);
FileSystem.SwapFiles(file1, file2); if (info1 == null || info2 == null)
// Directory watchers should repeat this, but do a quick refresh first
return RefreshMetadata(new MetadataRefreshOptions
{ {
ForceSave = true, // Nothing to do
MetadataRefreshMode = MetadataRefreshMode.None 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) public virtual bool IsPlayed(User user)

@ -30,17 +30,10 @@ namespace MediaBrowser.Controller.Entities
ThemeSongIds = new List<Guid>(); ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>(); ThemeVideoIds = new List<Guid>();
Tags = new List<string>(); Tags = new List<string>();
ScreenshotImagePaths = new List<string>();
} }
public List<Guid> LocalTrailerIds { get; set; } public List<Guid> LocalTrailerIds { get; set; }
/// <summary>
/// Gets or sets the screenshot image paths.
/// </summary>
/// <value>The screenshot image paths.</value>
public List<string> ScreenshotImagePaths { get; set; }
/// <summary> /// <summary>
/// Gets or sets the tags. /// Gets or sets the tags.
/// </summary> /// </summary>

@ -1,4 +1,5 @@
using MediaBrowser.Model.Entities; using System.IO;
using MediaBrowser.Model.Entities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -31,6 +32,13 @@ namespace MediaBrowser.Controller.Entities
/// <value>The type of the location.</value> /// <value>The type of the location.</value>
LocationType LocationType { get; } LocationType LocationType { get; }
/// <summary>
/// Gets the images.
/// </summary>
/// <param name="imageType">Type of the image.</param>
/// <returns>IEnumerable{ItemImageInfo}.</returns>
IEnumerable<ItemImageInfo> GetImages(ImageType imageType);
/// <summary> /// <summary>
/// Gets the image path. /// Gets the image path.
/// </summary> /// </summary>
@ -40,19 +48,20 @@ namespace MediaBrowser.Controller.Entities
string GetImagePath(ImageType imageType, int imageIndex); string GetImagePath(ImageType imageType, int imageIndex);
/// <summary> /// <summary>
/// Gets the image date modified. /// Gets the image information.
/// </summary> /// </summary>
/// <param name="imagePath">The image path.</param> /// <param name="imageType">Type of the image.</param>
/// <returns>DateTime.</returns> /// <param name="imageIndex">Index of the image.</param>
DateTime GetImageDateModified(string imagePath); /// <returns>ItemImageInfo.</returns>
ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex);
/// <summary> /// <summary>
/// Sets the image. /// Sets the image.
/// </summary> /// </summary>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <param name="path">The path.</param> /// <param name="file">The file.</param>
void SetImagePath(ImageType type, int index, string path); void SetImagePath(ImageType type, int index, FileInfo file);
/// <summary> /// <summary>
/// Determines whether the specified type has image. /// Determines whether the specified type has image.
@ -62,6 +71,13 @@ namespace MediaBrowser.Controller.Entities
/// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
bool HasImage(ImageType type, int imageIndex); bool HasImage(ImageType type, int imageIndex);
/// <summary>
/// Allowses the multiple images.
/// </summary>
/// <param name="type">The type.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool AllowsMultipleImages(ImageType type);
/// <summary> /// <summary>
/// Swaps the images. /// Swaps the images.
/// </summary> /// </summary>
@ -94,12 +110,6 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
bool ValidateImages(); bool ValidateImages();
/// <summary>
/// Gets or sets the backdrop image paths.
/// </summary>
/// <value>The backdrop image paths.</value>
List<string> BackdropImagePaths { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is owned item. /// Gets a value indicating whether this instance is owned item.
/// </summary> /// </summary>
@ -111,6 +121,14 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
/// <value>The containing folder path.</value> /// <value>The containing folder path.</value>
string ContainingFolderPath { get; } string ContainingFolderPath { get; }
/// <summary>
/// Adds the images.
/// </summary>
/// <param name="imageType">Type of the image.</param>
/// <param name="images">The images.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool AddImages(ImageType imageType, IEnumerable<FileInfo> images);
} }
public static class HasImagesExtensions public static class HasImagesExtensions
@ -136,10 +154,10 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param> /// <param name="imageType">Type of the image.</param>
/// <param name="path">The path.</param> /// <param name="file">The file.</param>
public static void SetImagePath(this IHasImages item, ImageType imageType, string path) public static void SetImagePath(this IHasImages item, ImageType imageType, FileInfo file)
{ {
item.SetImagePath(imageType, 0, path); item.SetImagePath(imageType, 0, file);
} }
} }
} }

@ -1,5 +1,4 @@
using System.Collections.Generic; 
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
/// <summary> /// <summary>
@ -7,10 +6,5 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
public interface IHasScreenshots public interface IHasScreenshots
{ {
/// <summary>
/// Gets or sets the screenshot image paths.
/// </summary>
/// <value>The screenshot image paths.</value>
List<string> ScreenshotImagePaths { get; set; }
} }
} }

@ -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; }
}
}

@ -104,6 +104,7 @@
<Compile Include="Entities\ILibraryItem.cs" /> <Compile Include="Entities\ILibraryItem.cs" />
<Compile Include="Entities\ImageSourceInfo.cs" /> <Compile Include="Entities\ImageSourceInfo.cs" />
<Compile Include="Entities\IMetadataContainer.cs" /> <Compile Include="Entities\IMetadataContainer.cs" />
<Compile Include="Entities\ItemImageInfo.cs" />
<Compile Include="Entities\LinkedChild.cs" /> <Compile Include="Entities\LinkedChild.cs" />
<Compile Include="Entities\MusicVideo.cs" /> <Compile Include="Entities\MusicVideo.cs" />
<Compile Include="Entities\IHasAwards.cs" /> <Compile Include="Entities\IHasAwards.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; imageIndex = item.GetImages(type).Count();
}
else if (type == ImageType.Screenshot && imageIndex == null)
{
var hasScreenshots = (IHasScreenshots)item;
imageIndex = hasScreenshots.ScreenshotImagePaths.Count;
} }
var index = imageIndex ?? 0; var index = imageIndex ?? 0;
@ -275,43 +270,7 @@ namespace MediaBrowser.Providers.Manager
/// imageIndex</exception> /// imageIndex</exception>
private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path) private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path)
{ {
switch (type) item.SetImagePath(type, imageIndex ?? 0, new FileInfo(path));
{
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;
}
} }
/// <summary> /// <summary>
@ -347,19 +306,10 @@ namespace MediaBrowser.Providers.Manager
filename = item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : "folder"; filename = item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : "folder";
break; break;
case ImageType.Backdrop: case ImageType.Backdrop:
if (!imageIndex.HasValue) filename = GetBackdropSaveFilename(item.GetImages(type), "backdrop", "backdrop", imageIndex);
{
throw new ArgumentNullException("imageIndex");
}
filename = GetBackdropSaveFilename(item.BackdropImagePaths, "backdrop", "backdrop", imageIndex.Value);
break; break;
case ImageType.Screenshot: case ImageType.Screenshot:
if (!imageIndex.HasValue) filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex);
{
throw new ArgumentNullException("imageIndex");
}
var hasScreenshots = (IHasScreenshots)item;
filename = GetBackdropSaveFilename(hasScreenshots.ScreenshotImagePaths, "screenshot", "screenshot", imageIndex.Value);
break; break;
default: default:
filename = type.ToString().ToLower(); filename = type.ToString().ToLower();
@ -404,16 +354,16 @@ namespace MediaBrowser.Providers.Manager
return path; return path;
} }
private string GetBackdropSaveFilename(IEnumerable<string> images, string zeroIndexFilename, string numberedIndexPrefix, int index) private string GetBackdropSaveFilename(IEnumerable<ItemImageInfo> images, string zeroIndexFilename, string numberedIndexPrefix, int? index)
{ {
if (index == 0) if (index.HasValue && index.Value == 0)
{ {
return zeroIndexFilename; 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)) while (filenames.Contains(numberedIndexPrefix + current.ToString(UsCulture), StringComparer.OrdinalIgnoreCase))
{ {
current++; current++;
@ -484,7 +434,7 @@ namespace MediaBrowser.Providers.Manager
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) }; 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[] return new[]
{ {

@ -178,22 +178,15 @@ namespace MediaBrowser.Providers.Manager
return false; return false;
} }
if (images.Contains(ImageType.Backdrop) && item.BackdropImagePaths.Count < backdropLimit) if (images.Contains(ImageType.Backdrop) && item.GetImages(ImageType.Backdrop).Count() < backdropLimit)
{ {
return false; 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; return true;
} }
@ -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; var hasScreenshots = item as IHasScreenshots;
if (hasScreenshots != null) 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) catch (OperationCanceledException)
@ -280,50 +273,42 @@ namespace MediaBrowser.Providers.Manager
if (image != null) if (image != null)
{ {
var oldPath = item.GetImagePath(type); var currentImage = item.GetImageInfo(type, 0);
item.SetImagePath(type, image.Path); if (currentImage == null || !string.Equals(currentImage.Path, image.Path, StringComparison.OrdinalIgnoreCase))
if (!string.Equals(oldPath, image.Path, StringComparison.OrdinalIgnoreCase))
{ {
item.SetImagePath(type, new FileInfo(image.Path));
changed = true; 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(); var backdrops = images.Where(i => i.Type == ImageType.Backdrop).ToList();
if (backdrops.Count > 0) if (backdrops.Count > 0)
{ {
var oldCount = item.BackdropImagePaths.Count; var foundImages = images.Where(i => i.Type == ImageType.Backdrop)
.Select(i => new FileInfo(i.Path))
item.BackdropImagePaths = item.BackdropImagePaths
.Concat(backdrops.Select(i => i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
if (oldCount != item.BackdropImagePaths.Count) if (foundImages.Count > 0)
{
if (item.AddImages(ImageType.Backdrop, foundImages))
{ {
changed = true; changed = true;
} }
} }
}
var hasScreenshots = item as IHasScreenshots; var hasScreenshots = item as IHasScreenshots;
if (hasScreenshots != null) 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))
if (screenshots.Count > 0)
{
var oldCount = hasScreenshots.ScreenshotImagePaths.Count;
hasScreenshots.ScreenshotImagePaths = hasScreenshots.ScreenshotImagePaths
.Concat(screenshots.Select(i => i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
if (oldCount != hasScreenshots.ScreenshotImagePaths.Count) if (foundImages.Count > 0)
{
if (item.AddImages(ImageType.Screenshot, foundImages))
{ {
changed = true; changed = true;
} }
@ -360,46 +345,11 @@ namespace MediaBrowser.Providers.Manager
} }
} }
private async Task DownloadBackdrops(IHasImages item, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, CancellationToken cancellationToken) private async Task DownloadBackdrops(IHasImages item, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> 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<RemoteImageInfo> images, CancellationToken cancellationToken)
{
const ImageType imageType = ImageType.Screenshot;
foreach (var image in images.Where(i => i.Type == imageType)) foreach (var image in images.Where(i => i.Type == imageType))
{ {
if (item.ScreenshotImagePaths.Count >= limit) if (item.GetImages(imageType).Count() >= limit)
{ {
break; break;
} }

@ -389,35 +389,33 @@ namespace MediaBrowser.Providers.Manager
public IEnumerable<MetadataPluginSummary> GetAllMetadataPlugins() public IEnumerable<MetadataPluginSummary> GetAllMetadataPlugins()
{ {
var list = new List<MetadataPluginSummary>(); var list = new List<MetadataPluginSummary>
{
list.Add(GetPluginSummary<Game>()); GetPluginSummary<Game>(),
list.Add(GetPluginSummary<GameSystem>()); GetPluginSummary<GameSystem>(),
list.Add(GetPluginSummary<Movie>()); GetPluginSummary<Movie>(),
list.Add(GetPluginSummary<Trailer>()); GetPluginSummary<Trailer>(),
list.Add(GetPluginSummary<BoxSet>()); GetPluginSummary<BoxSet>(),
list.Add(GetPluginSummary<Book>()); GetPluginSummary<Book>(),
list.Add(GetPluginSummary<Series>()); GetPluginSummary<Series>(),
list.Add(GetPluginSummary<Season>()); GetPluginSummary<Season>(),
list.Add(GetPluginSummary<Episode>()); GetPluginSummary<Episode>(),
list.Add(GetPluginSummary<Person>()); GetPluginSummary<Person>(),
list.Add(GetPluginSummary<MusicAlbum>()); GetPluginSummary<MusicAlbum>(),
list.Add(GetPluginSummary<MusicArtist>()); GetPluginSummary<MusicArtist>(),
list.Add(GetPluginSummary<Audio>()); GetPluginSummary<Audio>(),
GetPluginSummary<Genre>(),
list.Add(GetPluginSummary<Genre>()); GetPluginSummary<Studio>(),
list.Add(GetPluginSummary<Studio>()); GetPluginSummary<GameGenre>(),
list.Add(GetPluginSummary<GameGenre>()); GetPluginSummary<MusicGenre>(),
list.Add(GetPluginSummary<MusicGenre>()); GetPluginSummary<AdultVideo>(),
GetPluginSummary<MusicVideo>(),
list.Add(GetPluginSummary<AdultVideo>()); GetPluginSummary<Video>(),
list.Add(GetPluginSummary<MusicVideo>()); GetPluginSummary<LiveTvChannel>(),
list.Add(GetPluginSummary<Video>()); GetPluginSummary<LiveTvProgram>(),
GetPluginSummary<LiveTvVideoRecording>(),
list.Add(GetPluginSummary<LiveTvChannel>()); GetPluginSummary<LiveTvAudioRecording>()
list.Add(GetPluginSummary<LiveTvProgram>()); };
list.Add(GetPluginSummary<LiveTvVideoRecording>());
list.Add(GetPluginSummary<LiveTvAudioRecording>());
return list; return list;
} }

@ -66,17 +66,17 @@ namespace MediaBrowser.Providers.TV
if (!string.IsNullOrWhiteSpace(filename)) if (!string.IsNullOrWhiteSpace(filename))
{ {
// Strip off everything but the filename. Some metadata tools like MetaBrowser v1.0 will have an 'episodes' prefix //// Strip off everything but the filename. Some metadata tools like MetaBrowser v1.0 will have an 'episodes' prefix
// even though it's actually using the metadata folder. //// even though it's actually using the metadata folder.
filename = Path.GetFileName(filename); //filename = Path.GetFileName(filename);
var seasonFolder = Path.GetDirectoryName(item.Path); //var seasonFolder = Path.GetDirectoryName(item.Path);
filename = Path.Combine(seasonFolder, "metadata", filename); //filename = Path.Combine(seasonFolder, "metadata", filename);
if (File.Exists(filename)) //if (File.Exists(filename))
{ //{
item.SetImagePath(ImageType.Primary, 0, filename); // item.SetImagePath(ImageType.Primary, 0, filename);
} //}
} }
break; break;
} }

@ -619,27 +619,24 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// Gets the image cache tag. /// Gets the image cache tag.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param> /// <param name="image">The image.</param>
/// <param name="imagePath">The image path.</param>
/// <returns>Guid.</returns> /// <returns>Guid.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
public Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath) public Guid GetImageCacheTag(IHasImages item, ItemImageInfo image)
{ {
if (item == null) if (item == null)
{ {
throw new ArgumentNullException("item"); 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, image.Type);
var supportedEnhancers = GetSupportedEnhancers(item, imageType);
return GetImageCacheTag(item, imageType, imagePath, dateModified, supportedEnhancers.ToList()); return GetImageCacheTag(item, image.Type, image.Path, image.DateModified, supportedEnhancers.ToList());
} }
/// <summary> /// <summary>
@ -693,9 +690,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
{ {
var enhancers = GetSupportedEnhancers(item, imageType).ToList(); 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); var result = await GetEnhancedImage(imagePath, dateModified, item, imageType, imageIndex, enhancers);

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
@ -34,8 +35,9 @@ namespace MediaBrowser.Server.Implementations.Dto
private readonly IImageProcessor _imageProcessor; private readonly IImageProcessor _imageProcessor;
private readonly IServerConfigurationManager _config; 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; _logger = logger;
_libraryManager = libraryManager; _libraryManager = libraryManager;
@ -44,6 +46,7 @@ namespace MediaBrowser.Server.Implementations.Dto
_itemRepo = itemRepo; _itemRepo = itemRepo;
_imageProcessor = imageProcessor; _imageProcessor = imageProcessor;
_config = config; _config = config;
_fileSystem = fileSystem;
} }
/// <summary> /// <summary>
@ -207,11 +210,11 @@ namespace MediaBrowser.Server.Implementations.Dto
Configuration = user.Configuration 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 try
{ {
@ -288,12 +291,7 @@ namespace MediaBrowser.Server.Implementations.Dto
RunTimeTicks = item.RunTimeTicks RunTimeTicks = item.RunTimeTicks
}; };
var imagePath = item.PrimaryImagePath; info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary);
if (!string.IsNullOrEmpty(imagePath))
{
info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary, imagePath);
}
return info; return info;
} }
@ -380,11 +378,7 @@ namespace MediaBrowser.Server.Implementations.Dto
/// <returns>List{System.String}.</returns> /// <returns>List{System.String}.</returns>
private List<Guid> GetBackdropImageTags(BaseItem item) private List<Guid> GetBackdropImageTags(BaseItem item)
{ {
return item.BackdropImagePaths return GetCacheTags(item, ImageType.Backdrop).ToList();
.Select(p => GetImageCacheTag(item, ImageType.Backdrop, p))
.Where(i => i.HasValue)
.Select(i => i.Value)
.ToList();
} }
/// <summary> /// <summary>
@ -399,23 +393,40 @@ namespace MediaBrowser.Server.Implementations.Dto
{ {
return new List<Guid>(); return new List<Guid>();
} }
return GetCacheTags(item, ImageType.Screenshot).ToList();
}
return hasScreenshots.ScreenshotImagePaths private IEnumerable<Guid> GetCacheTags(BaseItem item, ImageType type)
.Select(p => GetImageCacheTag(item, ImageType.Screenshot, p)) {
return item.GetImages(type)
.Select(p => GetImageCacheTag(item, p))
.Where(i => i.HasValue) .Where(i => i.HasValue)
.Select(i => i.Value) .Select(i => i.Value)
.ToList(); .ToList();
} }
private Guid? GetImageCacheTag(BaseItem item, ImageType type, string path) private Guid? GetImageCacheTag(BaseItem item, ImageType type)
{ {
try try
{ {
return _imageProcessor.GetImageCacheTag(item, type, path); return _imageProcessor.GetImageCacheTag(item, type);
} }
catch (IOException ex) catch (IOException ex)
{ {
_logger.ErrorException("Error getting {0} image info for {1}", ex, type, path); _logger.ErrorException("Error getting {0} image info", ex, type);
return null;
}
}
private Guid? GetImageCacheTag(BaseItem item, ItemImageInfo image)
{
try
{
return _imageProcessor.GetImageCacheTag(item, image);
}
catch (IOException ex)
{
_logger.ErrorException("Error getting {0} image info for {1}", ex, image.Type, image.Path);
return null; return null;
} }
} }
@ -468,12 +479,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (dictionary.TryGetValue(person.Name, out entity)) if (dictionary.TryGetValue(person.Name, out entity))
{ {
var primaryImagePath = entity.PrimaryImagePath; baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
if (!string.IsNullOrEmpty(primaryImagePath))
{
baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
}
} }
dto.People[i] = baseItemPerson; dto.People[i] = baseItemPerson;
@ -520,12 +526,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (dictionary.TryGetValue(studio, out entity)) if (dictionary.TryGetValue(studio, out entity))
{ {
var primaryImagePath = entity.PrimaryImagePath; studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
if (!string.IsNullOrEmpty(primaryImagePath))
{
studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
}
} }
dto.Studios[i] = studioDto; dto.Studios[i] = studioDto;
@ -544,7 +545,7 @@ namespace MediaBrowser.Server.Implementations.Dto
while (parent != null) while (parent != null)
{ {
if (parent.BackdropImagePaths != null && parent.BackdropImagePaths.Count > 0) if (parent.GetImages(ImageType.Backdrop).Any())
{ {
return parent; return parent;
} }
@ -595,7 +596,12 @@ namespace MediaBrowser.Server.Implementations.Dto
if (!string.IsNullOrEmpty(chapterInfo.ImagePath)) 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; return dto;
@ -750,15 +756,15 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.ImageTags = new Dictionary<ImageType, Guid>(); dto.ImageTags = new Dictionary<ImageType, Guid>();
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, image);
var tag = GetImageCacheTag(item, type, image.Value);
if (tag.HasValue) if (tag.HasValue)
{ {
dto.ImageTags[type] = tag.Value; dto.ImageTags[image.Type] = tag.Value;
} }
} }
@ -862,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{ {
dto.ParentLogoItemId = GetDtoId(parentWithLogo); 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.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.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); dto.AlbumId = GetDtoId(albumParent);
var imagePath = albumParent.PrimaryImagePath; dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary);
if (!string.IsNullOrEmpty(imagePath))
{
dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary, imagePath);
}
} }
} }
@ -1085,17 +1086,9 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AirTime = series.AirTime; dto.AirTime = series.AirTime;
dto.SeriesStudio = series.Studios.FirstOrDefault(); dto.SeriesStudio = series.Studios.FirstOrDefault();
if (series.HasImage(ImageType.Thumb)) dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb);
{
dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb, series.GetImagePath(ImageType.Thumb));
}
var imagePath = series.PrimaryImagePath;
if (!string.IsNullOrEmpty(imagePath)) dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
{
dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary, imagePath);
}
} }
// Add SeasonInfo // Add SeasonInfo
@ -1110,12 +1103,7 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AirTime = series.AirTime; dto.AirTime = series.AirTime;
dto.SeriesStudio = series.Studios.FirstOrDefault(); dto.SeriesStudio = series.Studios.FirstOrDefault();
var imagePath = series.PrimaryImagePath; dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary);
if (!string.IsNullOrEmpty(imagePath))
{
dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary, imagePath);
}
} }
var game = item as Game; var game = item as Game;
@ -1303,15 +1291,17 @@ namespace MediaBrowser.Server.Implementations.Dto
/// <returns>Task.</returns> /// <returns>Task.</returns>
public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item) 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; return;
} }
var path = imageInfo.Path;
// See if we can avoid a file system lookup by looking for the file in ResolveArgs // 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; ImageSize size;

@ -401,16 +401,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private Guid? GetImageTag(IHasImages info) private Guid? GetImageTag(IHasImages info)
{ {
var path = info.PrimaryImagePath;
if (string.IsNullOrEmpty(path))
{
return null;
}
try try
{ {
return _imageProcessor.GetImageCacheTag(info, ImageType.Primary, path); return _imageProcessor.GetImageCacheTag(info, ImageType.Primary);
} }
catch (Exception ex) catch (Exception ex)
{ {

@ -309,7 +309,7 @@ namespace MediaBrowser.ServerApplication
ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer);
RegisterSingleInstance(ImageProcessor); 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); RegisterSingleInstance(DtoService);
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);

@ -258,8 +258,8 @@ namespace MediaBrowser.ServerApplication
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Thumb), "Thumb")); previews.Add(new PreviewItem(item.GetImagePath(ImageType.Thumb), "Thumb"));
} }
previews.AddRange( previews.AddRange(
item.BackdropImagePaths.Select( item.GetImages(ImageType.Backdrop).Select(
image => new PreviewItem(image, "Backdrop"))); image => new PreviewItem(image.Path, "Backdrop")));
}); });
lstPreviews.ItemsSource = previews; lstPreviews.ItemsSource = previews;
lstPreviews.Items.Refresh(); lstPreviews.Items.Refresh();

Loading…
Cancel
Save