diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs index e6e4594c16..33ea492e05 100644 --- a/MediaBrowser.Api/ApiService.cs +++ b/MediaBrowser.Api/ApiService.cs @@ -1,6 +1,4 @@ -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using System; +using System; using System.Net; namespace MediaBrowser.Api @@ -10,24 +8,6 @@ namespace MediaBrowser.Api /// public static class ApiService { - /// - /// Gets a User by Id - /// - /// The id of the user - /// User. - /// id - public static User GetUserById(string id) - { - if (string.IsNullOrEmpty(id)) - { - throw new ArgumentNullException("id"); - } - - var guid = new Guid(id); - - return Kernel.Instance.GetUserById(guid); - } - /// /// Determines whether [is API URL match] [the specified URL]. /// diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 113bad083d..d3d76f4f27 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.Extensions; +using System.Threading; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -9,6 +11,7 @@ using System; using System.IO; using System.Linq; using System.Threading.Tasks; +using ServiceStack.Text.Controller; namespace MediaBrowser.Api.Images { @@ -101,7 +104,7 @@ namespace MediaBrowser.Api.Images /// [Route("/Users/{Id}/Images/{Type}", "DELETE")] [Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")] - public class DeleteUserImage : DeleteImageRequest + public class DeleteUserImage : DeleteImageRequest, IReturnVoid { /// /// Gets or sets the id. @@ -109,6 +112,23 @@ namespace MediaBrowser.Api.Images /// The id. public Guid Id { get; set; } } + + [Route("/Users/{Id}/Images/{Type}", "POST")] + [Route("/Users/{Id}/Images/{Type}/{Index}", "POST")] + public class PostUserImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid + { + /// + /// Gets or sets the id. + /// + /// The id. + public Guid Id { get; set; } + + /// + /// The raw Http Request Input Stream + /// + /// The request stream. + public Stream RequestStream { get; set; } + } /// /// Class ImageService @@ -197,6 +217,26 @@ namespace MediaBrowser.Api.Images return GetImage(request, item); } + /// + /// Posts the specified request. + /// + /// The request. + public void Post(PostUserImage request) + { + var kernel = (Kernel)Kernel; + + var pathInfo = PathInfo.Parse(Request.PathInfo); + var id = new Guid(pathInfo.GetArgumentValue(1)); + + request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(3), true); + + var item = kernel.Users.First(i => i.Id == id); + + var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); + + Task.WaitAll(task); + } + /// /// Deletes the specified request. /// @@ -280,5 +320,62 @@ namespace MediaBrowser.Api.Images return kernel.ImageManager.GetImagePath(item, request.Type, index); } + + /// + /// Posts the image. + /// + /// The entity. + /// The input stream. + /// Type of the image. + /// Type of the MIME. + /// Task. + private async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType) + { + using (var reader = new StreamReader(inputStream)) + { + var text = await reader.ReadToEndAsync().ConfigureAwait(false); + + var bytes = Convert.FromBase64String(text); + + string filename; + + switch (imageType) + { + case ImageType.Art: + filename = "clearart"; + break; + case ImageType.Primary: + filename = "folder"; + break; + default: + filename = imageType.ToString().ToLower(); + break; + } + + var extension = mimeType.Substring(mimeType.IndexOf('/') + 1); + + var oldImagePath = entity.GetImage(imageType); + + var imagePath = Path.Combine(entity.MetaLocation, filename + "." + extension); + + // Save to file system + using (var fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) + { + await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + } + + // 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)) + { + File.Delete(oldImagePath); + } + + // Directory watchers should repeat this, but do a quick refresh first + await entity.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); + } + } } } diff --git a/MediaBrowser.Api/Images/UploadImageHandler.cs b/MediaBrowser.Api/Images/UploadImageHandler.cs deleted file mode 100644 index 758e96d851..0000000000 --- a/MediaBrowser.Api/Images/UploadImageHandler.cs +++ /dev/null @@ -1,141 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net.Handlers; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Api.Images -{ - /// - /// Class UploadImageHandler - /// - class UploadImageHandler : BaseActionHandler - { - /// - /// The _source entity - /// - private BaseItem _sourceEntity; - - /// - /// Gets the source entity. - /// - /// Task{BaseItem}. - private async Task GetSourceEntity() - { - if (_sourceEntity == null) - { - if (!string.IsNullOrEmpty(QueryString["personname"])) - { - _sourceEntity = - await Kernel.LibraryManager.GetPerson(QueryString["personname"]).ConfigureAwait(false); - } - - else if (!string.IsNullOrEmpty(QueryString["genre"])) - { - _sourceEntity = - await Kernel.LibraryManager.GetGenre(QueryString["genre"]).ConfigureAwait(false); - } - - else if (!string.IsNullOrEmpty(QueryString["year"])) - { - _sourceEntity = - await - Kernel.LibraryManager.GetYear(int.Parse(QueryString["year"])).ConfigureAwait(false); - } - - else if (!string.IsNullOrEmpty(QueryString["studio"])) - { - _sourceEntity = - await Kernel.LibraryManager.GetStudio(QueryString["studio"]).ConfigureAwait(false); - } - - else if (!string.IsNullOrEmpty(QueryString["userid"])) - { - _sourceEntity = ApiService.GetUserById(QueryString["userid"]); - } - - else - { - _sourceEntity = DtoBuilder.GetItemByClientId(QueryString["id"]); - } - } - - return _sourceEntity; - } - - /// - /// Gets the type of the image. - /// - /// The type of the image. - private ImageType ImageType - { - get - { - var imageType = QueryString["type"]; - - return (ImageType)Enum.Parse(typeof(ImageType), imageType, true); - } - } - - /// - /// Performs the action. - /// - /// Task. - protected override async Task ExecuteAction() - { - var entity = await GetSourceEntity().ConfigureAwait(false); - - using (var reader = new StreamReader(HttpListenerContext.Request.InputStream)) - { - var text = await reader.ReadToEndAsync().ConfigureAwait(false); - - var bytes = Convert.FromBase64String(text); - - string filename; - - switch (ImageType) - { - case ImageType.Art: - filename = "clearart"; - break; - case ImageType.Primary: - filename = "folder"; - break; - default: - filename = ImageType.ToString().ToLower(); - break; - } - - // Use the client filename to determine the original extension - var clientFileName = QueryString["filename"]; - - var oldImagePath = entity.GetImage(ImageType); - - var imagePath = Path.Combine(entity.MetaLocation, filename + Path.GetExtension(clientFileName)); - - // Save to file system - using (var fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) - { - await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - - // 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)) - { - File.Delete(oldImagePath); - } - - // Directory watchers should repeat this, but do a quick refresh first - await entity.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); - } - } - } -} diff --git a/MediaBrowser.Api/Javascript/ApiClient.js b/MediaBrowser.Api/Javascript/ApiClient.js index e82238d24c..84e54597b2 100644 --- a/MediaBrowser.Api/Javascript/ApiClient.js +++ b/MediaBrowser.Api/Javascript/ApiClient.js @@ -613,15 +613,15 @@ var ApiClient = { var data = window.btoa(e.target.result); - var params = { - userId: userId, - type: imageType, - filename: file.name - }; + var url = ApiClient.getUrl("Users/" + userId + "/Images/" + imageType); - var url = ApiClient.getUrl("UploadImage", params); + $.ajax({ + type: "POST", + url: url, + data: data, + contentType: "image/" + file.name.substring(file.name.lastIndexOf('.') + 1) - $.post(url, data).done(function (result) { + }).done(function (result) { deferred.resolveWith(null, [result]); diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 81ff1001be..896e1d438e 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -78,7 +78,6 @@ -