From 6e5ec99ea10557c141ed8d755e672cef628d35f0 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 3 Mar 2024 13:51:31 -0700 Subject: Move userId in API from route to optional query parameter (#11074) * Move userId in API from route to optional query parameter * Standardize UserViewsController * Move userId to query in ImageController * Move userId to query in ItemsController * Move userId to query in PlaystateController * Move userId to query in SuggestionsController * Move userId from route to query in UserLibraryController * Clean up routes * Move userId to query in UserController * fix bad merge --------- Co-authored-by: Niels van Velzen --- Jellyfin.Api/Controllers/ImageController.cs | 335 ++++++++++++++-------------- 1 file changed, 168 insertions(+), 167 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 8368b846d..6b38fa7d3 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -11,7 +11,9 @@ using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; +using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; @@ -86,31 +88,26 @@ public class ImageController : BaseJellyfinApiController /// Sets the user image. /// /// User Id. - /// (Unused) Image type. - /// (Unused) Image index. /// Image updated. /// User does not have permission to delete the image. /// A . - [HttpPost("Users/{userId}/Images/{imageType}")] + [HttpPost("UserImage")] [Authorize] [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] public async Task PostUserImage( - [FromRoute, Required] Guid userId, - [FromRoute, Required] ImageType imageType, - [FromQuery] int? index = null) + [FromQuery] Guid? userId) { - var user = _userManager.GetUserById(userId); + var requestUserId = RequestHelpers.GetUserId(User, userId); + var user = _userManager.GetUserById(requestUserId); if (user is null) { return NotFound(); } - if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) + if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, requestUserId, true)) { return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); } @@ -142,6 +139,28 @@ public class ImageController : BaseJellyfinApiController } } + /// + /// Sets the user image. + /// + /// User Id. + /// (Unused) Image type. + /// Image updated. + /// User does not have permission to delete the image. + /// A . + [HttpPost("Users/{userId}/Images/{imageType}")] + [Authorize] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] + [AcceptsImageFile] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] + public Task PostUserImageLegacy( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType) + => PostUserImage(userId); + /// /// Sets the user image. /// @@ -153,81 +172,41 @@ public class ImageController : BaseJellyfinApiController /// A . [HttpPost("Users/{userId}/Images/{imageType}/{index}")] [Authorize] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] - public async Task PostUserImageByIndex( + public Task PostUserImageByIndexLegacy( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, [FromRoute] int index) - { - var user = _userManager.GetUserById(userId); - if (user is null) - { - return NotFound(); - } - - if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) - { - return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); - } - - if (!TryGetImageExtensionFromContentType(Request.ContentType, out string? extension)) - { - return BadRequest("Incorrect ContentType."); - } - - var stream = GetFromBase64Stream(Request.Body); - await using (stream.ConfigureAwait(false)) - { - // Handle image/png; charset=utf-8 - var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); - var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); - if (user.ProfileImage is not null) - { - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - } - - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension)); - - await _providerManager - .SaveImage(stream, mimeType, user.ProfileImage.Path) - .ConfigureAwait(false); - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - - return NoContent(); - } - } + => PostUserImage(userId); /// /// Delete the user's image. /// /// User Id. - /// (Unused) Image type. - /// (Unused) Image index. /// Image deleted. /// User does not have permission to delete the image. /// A . - [HttpDelete("Users/{userId}/Images/{imageType}")] + [HttpDelete("UserImage")] [Authorize] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task DeleteUserImage( - [FromRoute, Required] Guid userId, - [FromRoute, Required] ImageType imageType, - [FromQuery] int? index = null) + [FromQuery] Guid? userId) { - if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) + var requestUserId = RequestHelpers.GetUserId(User, userId); + if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, requestUserId, true)) { return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to delete the image."); } - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(requestUserId); if (user?.ProfileImage is null) { return NoContent(); @@ -246,6 +225,29 @@ public class ImageController : BaseJellyfinApiController return NoContent(); } + /// + /// Delete the user's image. + /// + /// User Id. + /// (Unused) Image type. + /// (Unused) Image index. + /// Image deleted. + /// User does not have permission to delete the image. + /// A . + [HttpDelete("Users/{userId}/Images/{imageType}")] + [Authorize] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public Task DeleteUserImageLegacy( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromQuery] int? index = null) + => DeleteUserImage(userId); + /// /// Delete the user's image. /// @@ -257,38 +259,17 @@ public class ImageController : BaseJellyfinApiController /// A . [HttpDelete("Users/{userId}/Images/{imageType}/{index}")] [Authorize] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task DeleteUserImageByIndex( + public Task DeleteUserImageByIndexLegacy( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, [FromRoute] int index) - { - if (!RequestHelpers.AssertCanUpdateUser(_userManager, HttpContext.User, userId, true)) - { - return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to delete the image."); - } - - var user = _userManager.GetUserById(userId); - if (user?.ProfileImage is null) - { - return NoContent(); - } - - try - { - System.IO.File.Delete(user.ProfileImage.Path); - } - catch (IOException e) - { - _logger.LogError(e, "Error deleting user profile image:"); - } - - await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); - return NoContent(); - } + => DeleteUserImage(userId); /// /// Delete an item's image. @@ -541,7 +522,6 @@ public class ImageController : BaseJellyfinApiController /// Width of box to fill. /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. @@ -571,7 +551,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery] string? tag, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, [FromQuery] double? percentPlayed, [FromQuery] int? unplayedCount, @@ -622,7 +601,6 @@ public class ImageController : BaseJellyfinApiController /// Width of box to fill. /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. @@ -652,7 +630,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery] string? tag, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, [FromQuery] double? percentPlayed, [FromQuery] int? unplayedCount, @@ -701,7 +678,6 @@ public class ImageController : BaseJellyfinApiController /// Width of box to fill. /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Determines the output format of the image - original,gif,jpg,png. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. @@ -731,7 +707,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromRoute, Required] string tag, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromRoute, Required] ImageFormat format, [FromRoute, Required] double percentPlayed, [FromRoute, Required] int unplayedCount, @@ -784,7 +759,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -814,7 +788,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -864,7 +837,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -894,7 +866,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -945,7 +916,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -975,7 +945,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1024,7 +993,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1054,7 +1022,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1105,7 +1072,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1135,7 +1101,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1184,7 +1149,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1214,7 +1178,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1265,7 +1228,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1295,7 +1257,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1344,7 +1305,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1374,7 +1334,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, @@ -1425,7 +1384,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1455,7 +1413,6 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) @@ -1492,7 +1449,6 @@ public class ImageController : BaseJellyfinApiController /// Get user profile image. /// /// User id. - /// Image type. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Determines the output format of the image - original,gif,jpg,png. /// The maximum image width to return. @@ -1504,25 +1460,25 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. /// Image index. /// Image stream returned. + /// User id not provided. /// Item not found. /// /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Users/{userId}/Images/{imageType}")] - [HttpHead("Users/{userId}/Images/{imageType}", Name = "HeadUserImage")] + [HttpGet("UserImage")] + [HttpHead("UserImage", Name = "HeadUserImage")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] public async Task GetUserImage( - [FromRoute, Required] Guid userId, - [FromRoute, Required] ImageType imageType, + [FromQuery] Guid? userId, [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, @@ -1534,13 +1490,18 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, [FromQuery] int? imageIndex) { - var user = _userManager.GetUserById(userId); + var requestUserId = userId ?? User.GetUserId(); + if (requestUserId.IsEmpty()) + { + return BadRequest("UserId is required if unauthenticated"); + } + + var user = _userManager.GetUserById(requestUserId); if (user?.ProfileImage is null) { return NotFound(); @@ -1565,7 +1526,7 @@ public class ImageController : BaseJellyfinApiController return await GetImageInternal( user.Id, - imageType, + ImageType.Profile, imageIndex, tag, format, @@ -1586,6 +1547,75 @@ public class ImageController : BaseJellyfinApiController .ConfigureAwait(false); } + /// + /// Get user profile image. + /// + /// User id. + /// Image type. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image index. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Users/{userId}/Images/{imageType}")] + [HttpHead("Users/{userId}/Images/{imageType}", Name = "HeadUserImageLegacy")] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public Task GetUserImageLegacy( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromQuery] string? tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer, + [FromQuery] int? imageIndex) + => GetUserImage( + userId, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + fillWidth, + fillHeight, + blur, + backgroundColor, + foregroundLayer, + imageIndex); + /// /// Get user profile image. /// @@ -1603,7 +1633,6 @@ public class ImageController : BaseJellyfinApiController /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Width of box to fill. /// Height of box to fill. - /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. @@ -1614,11 +1643,13 @@ public class ImageController : BaseJellyfinApiController /// or a if item not found. /// [HttpGet("Users/{userId}/Images/{imageType}/{imageIndex}")] - [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex}", Name = "HeadUserImageByIndex")] + [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex}", Name = "HeadUserImageByIndexLegacy")] + [Obsolete("Kept for backwards compatibility")] + [ApiExplorerSettings(IgnoreApi = true)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetUserImageByIndex( + public Task GetUserImageByIndexLegacy( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, [FromRoute, Required] int imageIndex, @@ -1633,56 +1664,26 @@ public class ImageController : BaseJellyfinApiController [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer) - { - var user = _userManager.GetUserById(userId); - if (user?.ProfileImage is null) - { - return NotFound(); - } - - var info = new ItemImageInfo - { - Path = user.ProfileImage.Path, - Type = ImageType.Profile, - DateModified = user.ProfileImage.LastModified - }; - - if (width.HasValue) - { - info.Width = width.Value; - } - - if (height.HasValue) - { - info.Height = height.Value; - } - - return await GetImageInternal( - user.Id, - imageType, - imageIndex, - tag, - format, - maxWidth, - maxHeight, - percentPlayed, - unplayedCount, - width, - height, - quality, - fillWidth, - fillHeight, - blur, - backgroundColor, - foregroundLayer, - null, - info) - .ConfigureAwait(false); - } + => GetUserImage( + userId, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + fillWidth, + fillHeight, + blur, + backgroundColor, + foregroundLayer, + imageIndex); /// /// Generates or gets the splashscreen. -- cgit v1.2.3