diff options
| -rw-r--r-- | MediaBrowser.Api/Images/ImageService.cs | 405 | ||||
| -rw-r--r-- | MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Dto/DtoBuilder.cs | 16 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 43 | ||||
| -rw-r--r-- | MediaBrowser.Controller/IO/FileSystem.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Providers/IProviderManager.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Model/DTO/BaseItemDto.cs | 16 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dto/ImageInfo.cs | 52 | ||||
| -rw-r--r-- | MediaBrowser.Model/MediaBrowser.Model.csproj | 1 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Providers/ProviderManager.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/ApiClient.js | 63 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/packages.config | 2 |
12 files changed, 599 insertions, 25 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 0fa75af4d..3de5f5dc3 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -1,14 +1,20 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using ServiceStack.ServiceHost; using ServiceStack.Text.Controller; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; @@ -19,6 +25,18 @@ namespace MediaBrowser.Api.Images /// <summary> /// Class GetItemImage /// </summary> + [Route("/Items/{Id}/Images", "GET")] + [Api(Description = "Gets information about an item's images")] + public class GetItemImageInfos : IReturn<List<ImageInfo>> + { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + [Route("/Items/{Id}/Images/{Type}", "GET")] [Route("/Items/{Id}/Images/{Type}/{Index}", "GET")] [Api(Description = "Gets an item image")] @@ -33,6 +51,58 @@ namespace MediaBrowser.Api.Images } /// <summary> + /// Class UpdateItemImageIndex + /// </summary> + [Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST")] + [Api(Description = "Updates the index for an item image")] + public class UpdateItemImageIndex : IReturnVoid + { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid Id { get; set; } + + /// <summary> + /// Gets or sets the type of the image. + /// </summary> + /// <value>The type of the image.</value> + [ApiMember(Name = "Type", Description = "Image Type", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public ImageType Type { get; set; } + + /// <summary> + /// Gets or sets the index. + /// </summary> + /// <value>The index.</value> + [ApiMember(Name = "Index", Description = "Image Index", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] + public int Index { get; set; } + + /// <summary> + /// Gets or sets the new index. + /// </summary> + /// <value>The new index.</value> + [ApiMember(Name = "NewIndex", Description = "The new image index", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public int NewIndex { get; set; } + } + + /// <summary> + /// Class DeleteItemImage + /// </summary> + [Route("/Items/{Id}/Images/{Type}", "DELETE")] + [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")] + [Api(Description = "Deletes an item image")] + public class DeleteItemImage : DeleteImageRequest, IReturnVoid + { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid Id { get; set; } + } + + /// <summary> /// Class GetPersonImage /// </summary> [Route("/Persons/{Name}/Images/{Type}", "GET")] @@ -48,6 +118,9 @@ namespace MediaBrowser.Api.Images public string Name { get; set; } } + /// <summary> + /// Class GetArtistImage + /// </summary> [Route("/Artists/{Name}/Images/{Type}", "GET")] [Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")] [Api(Description = "Gets an artist image")] @@ -141,6 +214,9 @@ namespace MediaBrowser.Api.Images public Guid Id { get; set; } } + /// <summary> + /// Class PostUserImage + /// </summary> [Route("/Users/{Id}/Images/{Type}", "POST")] [Route("/Users/{Id}/Images/{Type}/{Index}", "POST")] [Api(Description = "Posts a user image")] @@ -160,6 +236,9 @@ namespace MediaBrowser.Api.Images public Stream RequestStream { get; set; } } + /// <summary> + /// Class PostItemImage + /// </summary> [Route("/Items/{Id}/Images/{Type}", "POST")] [Route("/Items/{Id}/Images/{Type}/{Index}", "POST")] [Api(Description = "Posts an item image")] @@ -178,7 +257,7 @@ namespace MediaBrowser.Api.Images /// <value>The request stream.</value> public Stream RequestStream { get; set; } } - + /// <summary> /// Class ImageService /// </summary> @@ -194,15 +273,23 @@ namespace MediaBrowser.Api.Images /// </summary> private readonly ILibraryManager _libraryManager; + private readonly IApplicationPaths _appPaths; + + private readonly IProviderManager _providerManager; + /// <summary> /// Initializes a new instance of the <see cref="ImageService" /> class. /// </summary> /// <param name="userManager">The user manager.</param> /// <param name="libraryManager">The library manager.</param> - public ImageService(IUserManager userManager, ILibraryManager libraryManager) + /// <param name="appPaths">The app paths.</param> + /// <param name="providerManager">The provider manager.</param> + public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager) { _userManager = userManager; _libraryManager = libraryManager; + _appPaths = appPaths; + _providerManager = providerManager; } /// <summary> @@ -210,6 +297,135 @@ namespace MediaBrowser.Api.Images /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> + public object Get(GetItemImageInfos request) + { + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager); + + var result = GetItemImageInfos(item).Result; + + return ToOptimizedResult(result); + } + + /// <summary> + /// Gets the item image infos. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>Task{List{ImageInfo}}.</returns> + public async Task<List<ImageInfo>> GetItemImageInfos(BaseItem item) + { + var list = new List<ImageInfo>(); + + foreach (var image in item.Images) + { + var path = image.Value; + + var fileInfo = new FileInfo(path); + + var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, path); + + var size = await Kernel.Instance.ImageManager.GetImageSize(path, dateModified).ConfigureAwait(false); + + list.Add(new ImageInfo + { + Path = path, + ImageType = image.Key, + ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, image.Key, path), + Size = fileInfo.Length, + Width = Convert.ToInt32(size.Width), + Height = Convert.ToInt32(size.Height) + }); + } + + var index = 0; + + foreach (var image in item.BackdropImagePaths) + { + var fileInfo = new FileInfo(image); + + var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); + + var size = await Kernel.Instance.ImageManager.GetImageSize(image, dateModified).ConfigureAwait(false); + + list.Add(new ImageInfo + { + Path = image, + ImageIndex = index, + ImageType = ImageType.Backdrop, + ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Backdrop, image), + Size = fileInfo.Length, + Width = Convert.ToInt32(size.Width), + Height = Convert.ToInt32(size.Height) + }); + + index++; + } + + index = 0; + + foreach (var image in item.ScreenshotImagePaths) + { + var fileInfo = new FileInfo(image); + + var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); + + var size = await Kernel.Instance.ImageManager.GetImageSize(image, dateModified).ConfigureAwait(false); + + list.Add(new ImageInfo + { + Path = image, + ImageIndex = index, + ImageType = ImageType.Screenshot, + ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Screenshot, image), + Size = fileInfo.Length, + Width = Convert.ToInt32(size.Width), + Height = Convert.ToInt32(size.Height) + }); + + index++; + } + + var video = item as Video; + + if (video != null) + { + index = 0; + + foreach (var chapter in video.Chapters) + { + if (!string.IsNullOrEmpty(chapter.ImagePath)) + { + var image = chapter.ImagePath; + + var fileInfo = new FileInfo(image); + + var dateModified = Kernel.Instance.ImageManager.GetImageDateModified(item, image); + + var size = await Kernel.Instance.ImageManager.GetImageSize(image, dateModified).ConfigureAwait(false); + + list.Add(new ImageInfo + { + Path = image, + ImageIndex = index, + ImageType = ImageType.Chapter, + ImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Chapter, image), + Size = fileInfo.Length, + Width = Convert.ToInt32(size.Width), + Height = Convert.ToInt32(size.Height) + }); + } + + index++; + } + } + + return list; + } + + /// <summary> + /// Gets the specified request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>System.Object.</returns> public object Get(GetItemImage request) { var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager); @@ -276,7 +492,7 @@ namespace MediaBrowser.Api.Images return GetImage(request, item); } - + /// <summary> /// Gets the specified request. /// </summary> @@ -333,18 +549,97 @@ namespace MediaBrowser.Api.Images { var item = _userManager.Users.First(i => i.Id == request.Id); - var task = item.DeleteImage(request.Type); + var task = item.DeleteImage(request.Type, request.Index); Task.WaitAll(task); } - + + /// <summary> + /// Deletes the specified request. + /// </summary> + /// <param name="request">The request.</param> + public void Delete(DeleteItemImage request) + { + var item = _libraryManager.GetItemById(request.Id); + + var task = item.DeleteImage(request.Type, request.Index); + + Task.WaitAll(task); + } + + /// <summary> + /// Posts the specified request. + /// </summary> + /// <param name="request">The request.</param> + public void Post(UpdateItemImageIndex request) + { + var item = _libraryManager.GetItemById(request.Id); + + var task = UpdateItemIndex(item, request.Type, request.Index, request.NewIndex); + + Task.WaitAll(task); + } + + /// <summary> + /// Updates the index of the item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="type">The type.</param> + /// <param name="currentIndex">Index of the current.</param> + /// <param name="newIndex">The new index.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentException">The change index operation is only applicable to backdrops and screenshots</exception> + private Task UpdateItemIndex(BaseItem item, ImageType type, int currentIndex, int newIndex) + { + string file1; + string file2; + + if (type == ImageType.Screenshot) + { + file1 = item.ScreenshotImagePaths[currentIndex]; + file2 = item.ScreenshotImagePaths[newIndex]; + } + else if (type == ImageType.Backdrop) + { + file1 = item.BackdropImagePaths[currentIndex]; + file2 = item.BackdropImagePaths[newIndex]; + } + else + { + throw new ArgumentException("The change index operation is only applicable to backdrops and screenshots"); + } + + SwapFiles(file1, file2); + + // Directory watchers should repeat this, but do a quick refresh first + return item.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false); + } + + /// <summary> + /// Swaps the files. + /// </summary> + /// <param name="file1">The file1.</param> + /// <param name="file2">The file2.</param> + private void SwapFiles(string file1, string file2) + { + var temp1 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp"); + var temp2 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp"); + + File.Copy(file1, temp1); + File.Copy(file2, temp2); + + File.Copy(temp1, file2, true); + File.Copy(temp2, file1, true); + } + /// <summary> /// Gets the image. /// </summary> /// <param name="request">The request.</param> /// <param name="item">The item.</param> /// <returns>System.Object.</returns> - /// <exception cref="ResourceNotFoundException"></exception> + /// <exception cref="ResourceNotFoundException"> + /// </exception> private object GetImage(ImageRequest request, BaseItem item) { var kernel = Kernel.Instance; @@ -430,7 +725,13 @@ namespace MediaBrowser.Api.Images filename = "clearart"; break; case ImageType.Primary: - filename = "folder"; + filename = entity is Episode ? Path.GetFileNameWithoutExtension(entity.Path) : "folder"; + break; + case ImageType.Backdrop: + filename = GetBackdropFilenameToSave(entity); + break; + case ImageType.Screenshot: + filename = GetScreenshotFilenameToSave(entity); break; default: filename = imageType.ToString().ToLower(); @@ -440,9 +741,30 @@ namespace MediaBrowser.Api.Images var extension = mimeType.Split(';').First().Split('/').Last(); - var oldImagePath = entity.GetImage(imageType); + string oldImagePath; + switch (imageType) + { + case ImageType.Backdrop: + case ImageType.Screenshot: + oldImagePath = null; + break; + default: + oldImagePath = entity.GetImage(imageType); + break; + } + + // Don't save locally if there's no parent (special feature, trailer, etc) + var saveLocally = !(entity is Audio) && entity.Parent != null; + + if (imageType != ImageType.Primary) + { + if (entity is Episode) + { + saveLocally = false; + } + } - var imagePath = Path.Combine(entity.MetaLocation, filename + "." + extension); + var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally); // Save to file system using (var fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) @@ -450,8 +772,19 @@ namespace MediaBrowser.Api.Images await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } - // Set the image - entity.SetImage(imageType, imagePath); + if (imageType == ImageType.Screenshot) + { + entity.ScreenshotImagePaths.Add(imagePath); + } + else if (imageType == ImageType.Backdrop) + { + entity.BackdropImagePaths.Add(imagePath); + } + else + { + // Set the image + entity.SetImage(imageType, imagePath); + } // If the new and old paths are different, delete the old one if (!string.IsNullOrEmpty(oldImagePath) && !oldImagePath.Equals(imagePath, StringComparison.OrdinalIgnoreCase)) @@ -463,5 +796,53 @@ namespace MediaBrowser.Api.Images await entity.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); } } + + /// <summary> + /// Gets the backdrop filename to save. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + private string GetBackdropFilenameToSave(BaseItem item) + { + var paths = item.BackdropImagePaths.ToList(); + + if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop", StringComparison.OrdinalIgnoreCase))) + { + return "screenshot"; + } + + var index = 1; + + while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop" + index, StringComparison.OrdinalIgnoreCase))) + { + index++; + } + + return "backdrop" + index; + } + + /// <summary> + /// Gets the screenshot filename to save. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + private string GetScreenshotFilenameToSave(BaseItem item) + { + var paths = item.ScreenshotImagePaths.ToList(); + + if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot", StringComparison.OrdinalIgnoreCase))) + { + return "screenshot"; + } + + var index = 1; + + while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot" + index, StringComparison.OrdinalIgnoreCase))) + { + index++; + } + + return "screenshot" + index; + } } } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 4396fac66..9bcce87c8 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -241,7 +241,7 @@ namespace MediaBrowser.Api.Playback.Progressive } } - return new ImageService(UserManager, LibraryManager) + return new ImageService(UserManager, LibraryManager, ApplicationPaths, null) { Logger = Logger, RequestContext = RequestContext, diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs index 39b139f02..803e198bf 100644 --- a/MediaBrowser.Controller/Dto/DtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs @@ -287,6 +287,7 @@ namespace MediaBrowser.Controller.Dto dto.AspectRatio = item.AspectRatio; dto.BackdropImageTags = GetBackdropImageTags(item); + dto.ScreenshotImageTags = GetScreenshotImageTags(item); if (fields.Contains(ItemFields.Genres)) { @@ -981,5 +982,20 @@ namespace MediaBrowser.Controller.Dto return item.BackdropImagePaths.Select(p => Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Backdrop, p)).ToList(); } + + /// <summary> + /// Gets the screenshot image tags. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>List{Guid}.</returns> + private List<Guid> GetScreenshotImageTags(BaseItem item) + { + if (item.ScreenshotImagePaths == null) + { + return new List<Guid>(); + } + + return item.ScreenshotImagePaths.Select(p => Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Screenshot, p)).ToList(); + } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 48bfd8075..a4cbd1b07 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1475,22 +1475,49 @@ namespace MediaBrowser.Controller.Entities /// Deletes the image. /// </summary> /// <param name="type">The type.</param> + /// <param name="index">The index.</param> /// <returns>Task.</returns> - public async Task DeleteImage(ImageType type) + public Task DeleteImage(ImageType type, int? index) { - if (!HasImage(type)) + if (type == ImageType.Backdrop) { - return; + if (!index.HasValue) + { + throw new ArgumentException("Please specify a backdrop image index to delete."); + } + + var file = BackdropImagePaths[index.Value]; + + BackdropImagePaths.Remove(file); + + // Delete the source file + File.Delete(file); } + else if (type == ImageType.Screenshot) + { + if (!index.HasValue) + { + throw new ArgumentException("Please specify a screenshot image index to delete."); + } + + var file = ScreenshotImagePaths[index.Value]; - // Delete the source file - File.Delete(GetImage(type)); + ScreenshotImagePaths.Remove(file); + + // Delete the source file + File.Delete(file); + } + else + { + // Delete the source file + File.Delete(GetImage(type)); - // Remove it from the item - SetImage(type, null); + // Remove it from the item + SetImage(type, null); + } // Refresh metadata - await RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + return RefreshMetadata(CancellationToken.None); } } } diff --git a/MediaBrowser.Controller/IO/FileSystem.cs b/MediaBrowser.Controller/IO/FileSystem.cs index cbe561fdf..e5f80533a 100644 --- a/MediaBrowser.Controller/IO/FileSystem.cs +++ b/MediaBrowser.Controller/IO/FileSystem.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.IO try { - return info.LastAccessTimeUtc; + return info.LastWriteTimeUtc; } catch (Exception ex) { diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index fa10c8585..da46c0bce 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -47,5 +47,14 @@ namespace MediaBrowser.Controller.Providers /// </summary> /// <param name="providers">The providers.</param> void AddMetadataProviders(IEnumerable<BaseMetadataProvider> providers); + + /// <summary> + /// Gets the save path. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="targetFileName">Name of the target file.</param> + /// <param name="saveLocally">if set to <c>true</c> [save locally].</param> + /// <returns>System.String.</returns> + string GetSavePath(BaseItem item, string targetFileName, bool saveLocally); } }
\ No newline at end of file diff --git a/MediaBrowser.Model/DTO/BaseItemDto.cs b/MediaBrowser.Model/DTO/BaseItemDto.cs index f33892c47..2e54f3311 100644 --- a/MediaBrowser.Model/DTO/BaseItemDto.cs +++ b/MediaBrowser.Model/DTO/BaseItemDto.cs @@ -339,6 +339,12 @@ namespace MediaBrowser.Model.Dto public List<Guid> BackdropImageTags { get; set; } /// <summary> + /// Gets or sets the screenshot image tags. + /// </summary> + /// <value>The screenshot image tags.</value> + public List<Guid> ScreenshotImageTags { get; set; } + + /// <summary> /// Gets or sets the parent logo image tag. /// </summary> /// <value>The parent logo image tag.</value> @@ -441,6 +447,16 @@ namespace MediaBrowser.Model.Dto } /// <summary> + /// Gets the screenshot count. + /// </summary> + /// <value>The screenshot count.</value> + [IgnoreDataMember] + public int ScreenshotCount + { + get { return ScreenshotImageTags == null ? 0 : ScreenshotImageTags.Count; } + } + + /// <summary> /// Gets a value indicating whether this instance has banner. /// </summary> /// <value><c>true</c> if this instance has banner; otherwise, <c>false</c>.</value> diff --git a/MediaBrowser.Model/Dto/ImageInfo.cs b/MediaBrowser.Model/Dto/ImageInfo.cs new file mode 100644 index 000000000..0850ee0a4 --- /dev/null +++ b/MediaBrowser.Model/Dto/ImageInfo.cs @@ -0,0 +1,52 @@ +using MediaBrowser.Model.Entities; +using System; + +namespace MediaBrowser.Model.Dto +{ + /// <summary> + /// Class ImageInfo + /// </summary> + public class ImageInfo + { + /// <summary> + /// Gets or sets the type of the image. + /// </summary> + /// <value>The type of the image.</value> + public ImageType ImageType { get; set; } + + /// <summary> + /// Gets or sets the index of the image. + /// </summary> + /// <value>The index of the image.</value> + public int? ImageIndex { get; set; } + + /// <summary> + /// The image tag + /// </summary> + public Guid ImageTag; + + /// <summary> + /// Gets or sets the path. + /// </summary> + /// <value>The path.</value> + public string Path { get; set; } + + /// <summary> + /// Gets or sets the height. + /// </summary> + /// <value>The height.</value> + public int Height { get; set; } + + /// <summary> + /// Gets or sets the width. + /// </summary> + /// <value>The width.</value> + public int Width { get; set; } + + /// <summary> + /// Gets or sets the size. + /// </summary> + /// <value>The size.</value> + public long Size { get; set; } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 512ddd7de..707e6ea4d 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -45,6 +45,7 @@ <Compile Include="Dto\BaseItemPerson.cs" /> <Compile Include="Dto\ChapterInfoDto.cs" /> <Compile Include="Dto\IItemDto.cs" /> + <Compile Include="Dto\ImageInfo.cs" /> <Compile Include="Dto\ItemByNameCounts.cs" /> <Compile Include="Dto\StudioDto.cs" /> <Compile Include="Entities\IByReferenceItem.cs" /> diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index fe93cd377..569fb8e02 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -397,6 +397,19 @@ namespace MediaBrowser.Server.Implementations.Providers return localPath; } + /// <summary> + /// Gets the save path. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="targetFileName">Name of the target file.</param> + /// <param name="saveLocally">if set to <c>true</c> [save locally].</param> + /// <returns>System.String.</returns> + public string GetSavePath(BaseItem item, string targetFileName, bool saveLocally) + { + return (saveLocally && item.MetaLocation != null) ? + Path.Combine(item.MetaLocation, targetFileName) : + _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetFileName); + } /// <summary> /// Saves to library filesystem. diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 2e11a72fc..ae97e86f1 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -758,7 +758,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { * @param {String} userId * @param {String} imageType The type of image to delete, based on the server-side ImageType enum. */ - self.deleteUserImage = function (userId, imageType) { + self.deleteUserImage = function (userId, imageType, imageIndex) { if (!userId) { throw new Error("null userId"); @@ -770,12 +770,71 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { var url = self.getUrl("Users/" + userId + "/Images/" + imageType); + if (imageIndex != null) { + url += "/" + imageIndex; + } + return self.ajax({ type: "DELETE", url: url }); }; + self.deleteItemImage = function (itemId, imageType, imageIndex) { + + if (!itemId) { + throw new Error("null itemId"); + } + + if (!imageType) { + throw new Error("null imageType"); + } + + var url = self.getUrl("Items/" + itemId + "/Images/" + imageType); + + if (imageIndex != null) { + url += "/" + imageIndex; + } + + return self.ajax({ + type: "DELETE", + url: url + }); + }; + + self.updateItemImageIndex = function (itemId, imageType, imageIndex, newIndex) { + + if (!itemId) { + throw new Error("null itemId"); + } + + if (!imageType) { + throw new Error("null imageType"); + } + + var url = self.getUrl("Items/" + itemId + "/Images/" + imageType + "/" + imageIndex + "/Index", { newIndex: newIndex }); + + return self.ajax({ + type: "POST", + url: url + }); + }; + + self.getItemImageInfos = function (itemId) { + + if (!itemId) { + throw new Error("null itemId"); + } + + var url = self.getUrl("Items/" + itemId + "/Images"); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + /** * Uploads a user image * @param {String} userId @@ -839,7 +898,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { return deferred.promise(); }; - self.uploadImage = function (itemId, imageType, file) { + self.uploadItemImage = function (itemId, imageType, file) { if (!itemId) { throw new Error("null itemId"); diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 23ebca293..34667ce4c 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="MediaBrowser.ApiClient.Javascript" version="3.0.94" targetFramework="net45" /> + <package id="MediaBrowser.ApiClient.Javascript" version="3.0.99" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.43" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.43" targetFramework="net45" /> </packages>
\ No newline at end of file |
