support image stubbing

pull/702/head
Luke Pulverenti 9 years ago
parent 3741eb2426
commit d577e1c7b0

@ -18,6 +18,7 @@ using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using Emby.Drawing.Common;
using MediaBrowser.Controller.Library;
namespace Emby.Drawing
{
@ -53,18 +54,20 @@ namespace Emby.Drawing
private readonly IServerApplicationPaths _appPaths;
private readonly IImageEncoder _imageEncoder;
private readonly SemaphoreSlim _imageProcessingSemaphore;
private readonly Func<ILibraryManager> _libraryManager;
public ImageProcessor(ILogger logger,
IServerApplicationPaths appPaths,
IFileSystem fileSystem,
IJsonSerializer jsonSerializer,
IImageEncoder imageEncoder,
int maxConcurrentImageProcesses)
int maxConcurrentImageProcesses, Func<ILibraryManager> libraryManager)
{
_logger = logger;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
_imageEncoder = imageEncoder;
_libraryManager = libraryManager;
_appPaths = appPaths;
ImageEnhancers = new List<IImageEnhancer>();
@ -158,7 +161,14 @@ namespace Emby.Drawing
throw new ArgumentNullException("options");
}
var originalImagePath = options.Image.Path;
var originalImage = options.Image;
if (!originalImage.IsLocalFile)
{
originalImage = await _libraryManager().ConvertImageToLocal(options.Item, originalImage, options.ImageIndex).ConfigureAwait(false);
}
var originalImagePath = originalImage.Path;
if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace)
{
@ -166,7 +176,7 @@ namespace Emby.Drawing
return originalImagePath;
}
var dateModified = options.Image.DateModified;
var dateModified = originalImage.DateModified;
if (options.CropWhiteSpace)
{
@ -181,7 +191,7 @@ namespace Emby.Drawing
var tuple = await GetEnhancedImage(new ItemImageInfo
{
DateModified = dateModified,
Type = options.Image.Type,
Type = originalImage.Type,
Path = originalImagePath
}, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false);
@ -360,16 +370,6 @@ namespace Emby.Drawing
return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
}
/// <summary>
/// Gets the size of the image.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>ImageSize.</returns>
public ImageSize GetImageSize(string path)
{
return GetImageSize(path, _fileSystem.GetLastWriteTimeUtc(path), false);
}
public ImageSize GetImageSize(ItemImageInfo info)
{
return GetImageSize(info.Path, info.DateModified, false);

@ -319,10 +319,13 @@ namespace MediaBrowser.Api.Images
try
{
var size = _imageProcessor.GetImageSize(info);
if (info.IsLocalFile)
{
var size = _imageProcessor.GetImageSize(info);
width = Convert.ToInt32(size.Width);
height = Convert.ToInt32(size.Height);
width = Convert.ToInt32(size.Width);
height = Convert.ToInt32(size.Height);
}
}
catch
{

@ -124,7 +124,7 @@ namespace MediaBrowser.Api.Social
Task.WaitAll(task);
}
public object Get(GetShareImage request)
public async Task<object> Get(GetShareImage request)
{
var share = _sharingManager.GetShareInfo(request.Id);
@ -143,7 +143,21 @@ namespace MediaBrowser.Api.Social
if (image != null)
{
return ToStaticFileResult(image.Path);
if (image.IsLocalFile)
{
return ToStaticFileResult(image.Path);
}
try
{
// Don't fail the request over this
var updatedImage = await _libraryManager.ConvertImageToLocal(item, image, 0).ConfigureAwait(false);
return ToStaticFileResult(updatedImage.Path);
}
catch
{
}
}
// Grab a dlna icon if nothing else is available

@ -25,13 +25,6 @@ namespace MediaBrowser.Controller.Drawing
/// <value>The image enhancers.</value>
IEnumerable<IImageEnhancer> ImageEnhancers { get; }
/// <summary>
/// Gets the size of the image.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>ImageSize.</returns>
ImageSize GetImageSize(string path);
/// <summary>
/// Gets the size of the image.
/// </summary>

@ -1432,6 +1432,23 @@ namespace MediaBrowser.Controller.Entities
return GetImageInfo(type, imageIndex) != null;
}
public void SetImage(ItemImageInfo image, int index)
{
if (image.Type == ImageType.Chapter)
{
throw new ArgumentException("Cannot set chapter images using SetImagePath");
}
var existingImage = GetImageInfo(image.Type, index);
if (existingImage != null)
{
ImageInfos.Remove(existingImage);
}
ImageInfos.Add(image);
}
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
{
if (type == ImageType.Chapter)
@ -1473,18 +1490,21 @@ namespace MediaBrowser.Controller.Entities
// Remove it from the item
RemoveImage(info);
// Delete the source file
var currentFile = new FileInfo(info.Path);
// Deletion will fail if the file is hidden so remove the attribute first
if (currentFile.Exists)
if (info.IsLocalFile)
{
if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
// Delete the source file
var currentFile = new FileInfo(info.Path);
// Deletion will fail if the file is hidden so remove the attribute first
if (currentFile.Exists)
{
currentFile.Attributes &= ~FileAttributes.Hidden;
}
if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
{
currentFile.Attributes &= ~FileAttributes.Hidden;
}
FileSystem.DeleteFile(currentFile.FullName);
FileSystem.DeleteFile(currentFile.FullName);
}
}
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
@ -1505,11 +1525,16 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public bool ValidateImages(IDirectoryService directoryService)
{
var allDirectories = ImageInfos.Select(i => System.IO.Path.GetDirectoryName(i.Path)).Distinct(StringComparer.OrdinalIgnoreCase).ToList();
var allFiles = allDirectories.SelectMany(directoryService.GetFiles).Select(i => i.FullName).ToList();
var allFiles = ImageInfos
.Where(i => i.IsLocalFile)
.Select(i => System.IO.Path.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
.SelectMany(directoryService.GetFiles)
.Select(i => i.FullName)
.ToList();
var deletedImages = ImageInfos
.Where(image => !allFiles.Contains(image.Path, StringComparer.OrdinalIgnoreCase))
.Where(image => image.IsLocalFile && !allFiles.Contains(image.Path, StringComparer.OrdinalIgnoreCase))
.ToList();
if (deletedImages.Count > 0)
@ -1619,7 +1644,10 @@ namespace MediaBrowser.Controller.Entities
}
else
{
existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
if (existing.IsLocalFile)
{
existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
}
}
}
@ -1628,7 +1656,7 @@ namespace MediaBrowser.Controller.Entities
var newImagePaths = images.Select(i => i.FullName).ToList();
var deleted = existingImages
.Where(i => !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path))
.Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path))
.ToList();
ImageInfos = ImageInfos.Except(deleted).ToList();
@ -1679,6 +1707,12 @@ namespace MediaBrowser.Controller.Entities
return Task.FromResult(true);
}
if (!info1.IsLocalFile || !info2.IsLocalFile)
{
// TODO: Not supported yet
return Task.FromResult(true);
}
var path1 = info1.Path;
var path2 = info2.Path;

@ -2,9 +2,11 @@
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Entities
{
@ -191,6 +193,21 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="image">The image.</param>
void RemoveImage(ItemImageInfo image);
/// <summary>
/// Updates to repository.
/// </summary>
/// <param name="updateReason">The update reason.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
/// <summary>
/// Sets the image.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="index">The index.</param>
void SetImage(ItemImageInfo image, int index);
}
public static class HasImagesExtensions

@ -36,14 +36,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The date last refreshed.</value>
DateTime DateLastRefreshed { get; set; }
/// <summary>
/// Updates to repository.
/// </summary>
/// <param name="updateReason">The update reason.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made
/// </summary>

@ -29,6 +29,13 @@ namespace MediaBrowser.Controller.Entities
{
get
{
if (Path != null)
{
if (Path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
return true;
}
}

@ -534,5 +534,14 @@ namespace MediaBrowser.Controller.Library
/// <param name="to">To.</param>
/// <returns>System.String.</returns>
string SubstitutePath(string path, string from, string to);
/// <summary>
/// Converts the image to local.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="image">The image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task.</returns>
Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
}
}

@ -1,12 +1,14 @@
using System;
using System.IO;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Controller.Providers
{
public class DynamicImageResponse
{
public string Path { get; set; }
public MediaProtocol Protocol { get; set; }
public Stream Stream { get; set; }
public ImageFormat Format { get; set; }
public bool HasImage { get; set; }

@ -136,7 +136,7 @@ namespace MediaBrowser.Providers.Manager
source = memoryStream;
var currentPath = GetCurrentImagePath(item, type, index);
var currentImage = GetCurrentImage(item, type, index);
using (source)
{
@ -160,8 +160,10 @@ namespace MediaBrowser.Providers.Manager
SetImagePath(item, type, imageIndex, paths[0]);
// Delete the current path
if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
if (currentImage != null && currentImage.IsLocalFile && !paths.Contains(currentImage.Path, StringComparer.OrdinalIgnoreCase))
{
var currentPath = currentImage.Path;
_libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
try
@ -301,9 +303,9 @@ namespace MediaBrowser.Providers.Manager
/// or
/// imageIndex
/// </exception>
private string GetCurrentImagePath(IHasImages item, ImageType type, int imageIndex)
private ItemImageInfo GetCurrentImage(IHasImages item, ImageType type, int imageIndex)
{
return item.GetImagePath(type, imageIndex);
return item.GetImageInfo(type, imageIndex);
}
/// <summary>

@ -17,6 +17,7 @@ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Providers.Manager
{
@ -138,11 +139,24 @@ namespace MediaBrowser.Providers.Manager
{
if (!string.IsNullOrEmpty(response.Path))
{
var mimeType = MimeTypes.GetMimeType(response.Path);
var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
if (response.Protocol == MediaProtocol.Http)
{
_logger.Debug("Setting image url into item {0}", item.Id);
item.SetImage(new ItemImageInfo
{
Path = response.Path,
Type = imageType
}, 0);
}
else
{
var mimeType = MimeTypes.GetMimeType(response.Path);
var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
}
}
else
{
@ -391,7 +405,7 @@ namespace MediaBrowser.Providers.Manager
else
{
var existing = item.GetImageInfo(type, 0);
if (existing != null && !_fileSystem.FileExists(existing.Path))
if (existing != null && !_fileSystem.FileExists(existing.Path))
{
item.RemoveImage(existing);
changed = true;

@ -22,13 +22,15 @@ namespace MediaBrowser.Providers.Music
var image = album.GetRecursiveChildren()
.OfType<Audio>()
.Select(i => i.GetImagePath(type))
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
.Select(i => i.GetImageInfo(type, 0))
.FirstOrDefault(i => i != null && i.IsLocalFile);
var imagePath = image == null ? null : image.Path;
return Task.FromResult(new DynamicImageResponse
{
Path = image,
HasImage = !string.IsNullOrEmpty(image)
Path = imagePath,
HasImage = !string.IsNullOrEmpty(imagePath)
});
}

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Server.Implementations.Channels
{
@ -35,24 +36,9 @@ namespace MediaBrowser.Server.Implementations.Channels
if (!string.IsNullOrEmpty(channelItem.ExternalImagePath))
{
var options = new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = channelItem.ExternalImagePath
};
var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
imageResponse.HasImage = true;
imageResponse.Stream = response.Content;
imageResponse.SetFormatFromMimeType(response.ContentType);
}
else
{
_logger.Error("Provider did not return an image content type.");
}
imageResponse.Path = channelItem.ExternalImagePath;
imageResponse.Protocol = MediaProtocol.Http;
imageResponse.HasImage = true;
}
return imageResponse;

@ -1743,7 +1743,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
if (imageInfo == null)
if (imageInfo == null || !imageInfo.IsLocalFile)
{
return;
}

@ -2354,5 +2354,17 @@ namespace MediaBrowser.Server.Implementations.Library
return ItemRepository.UpdatePeople(item.Id, people);
}
private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1,1);
public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
{
_logger.Debug("ConvertImageToLocal item {0}", item.Id);
await _providerManagerFactory().SaveImage(item, image.Path, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
return item.GetImageInfo(image.Type, imageIndex);
}
}
}

@ -1446,7 +1446,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
dto.ChannelName = channel.Name;
if (!string.IsNullOrEmpty(channel.PrimaryImagePath))
if (channel.HasImage(ImageType.Primary))
{
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
}
@ -1512,7 +1512,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
dto.ChannelName = channel.Name;
if (!string.IsNullOrEmpty(channel.PrimaryImagePath))
if (channel.HasImage(ImageType.Primary))
{
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
}

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@ -40,24 +41,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
if (liveTvItem.ExternalImagePath.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
var options = new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = liveTvItem.ExternalImagePath
};
var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
imageResponse.HasImage = true;
imageResponse.Stream = response.Content;
imageResponse.SetFormatFromMimeType(response.ContentType);
}
else
{
_logger.Error("Provider did not return an image content type.");
}
imageResponse.Path = liveTvItem.ExternalImagePath;
imageResponse.Protocol = MediaProtocol.Http;
imageResponse.HasImage = true;
}
else
{

@ -125,7 +125,22 @@ namespace MediaBrowser.Server.Implementations.Photos
protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
{
return items
.Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
.Select(i =>
{
var image = i.GetImageInfo(ImageType.Primary, 0);
if (image != null && image.IsLocalFile)
{
return image.Path;
}
image = i.GetImageInfo(ImageType.Thumb, 0);
if (image != null && image.IsLocalFile)
{
return image.Path;
}
return null;
})
.Where(i => !string.IsNullOrWhiteSpace(i));
}

@ -563,7 +563,7 @@ namespace MediaBrowser.Server.Startup.Common
int.TryParse(_startupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses);
}
return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder(), maxConcurrentImageProcesses);
return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder(), maxConcurrentImageProcesses, () => LibraryManager);
}
private IImageEncoder GetImageEncoder()

@ -884,11 +884,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
writer.WriteStartElement("art");
var poster = item.PrimaryImagePath;
var image = item.GetImageInfo(ImageType.Primary, 0);
if (!string.IsNullOrEmpty(poster))
if (image != null && image.IsLocalFile)
{
writer.WriteElementString("poster", GetPathToSave(item.PrimaryImagePath, libraryManager, config));
writer.WriteElementString("poster", GetPathToSave(image.Path, libraryManager, config));
}
foreach (var backdrop in item.GetImages(ImageType.Backdrop))
@ -985,10 +985,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
try
{
var personEntity = libraryManager.GetPerson(person.Name);
var image = personEntity.GetImageInfo(ImageType.Primary, 0);
if (!string.IsNullOrEmpty(personEntity.PrimaryImagePath))
if (image != null && image.IsLocalFile)
{
writer.WriteElementString("thumb", GetPathToSave(personEntity.PrimaryImagePath, libraryManager, config));
writer.WriteElementString("thumb", GetPathToSave(image.Path, libraryManager, config));
}
}
catch (Exception)

Loading…
Cancel
Save