|
@@ -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.
|
|
|
/// </summary>
|
|
|
/// <param name="userId">User Id.</param>
|
|
|
- /// <param name="imageType">(Unused) Image type.</param>
|
|
|
- /// <param name="index">(Unused) Image index.</param>
|
|
|
/// <response code="204">Image updated.</response>
|
|
|
/// <response code="403">User does not have permission to delete the image.</response>
|
|
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
- [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<ActionResult> 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
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Sets the user image.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="userId">User Id.</param>
|
|
|
+ /// <param name="imageType">(Unused) Image type.</param>
|
|
|
+ /// <response code="204">Image updated.</response>
|
|
|
+ /// <response code="403">User does not have permission to delete the image.</response>
|
|
|
+ /// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
+ [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<ActionResult> PostUserImageLegacy(
|
|
|
+ [FromRoute, Required] Guid userId,
|
|
|
+ [FromRoute, Required] ImageType imageType)
|
|
|
+ => PostUserImage(userId);
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Sets the user image.
|
|
|
/// </summary>
|
|
@@ -153,81 +172,41 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
[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<ActionResult> PostUserImageByIndex(
|
|
|
+ public Task<ActionResult> 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);
|
|
|
|
|
|
/// <summary>
|
|
|
/// Delete the user's image.
|
|
|
/// </summary>
|
|
|
/// <param name="userId">User Id.</param>
|
|
|
- /// <param name="imageType">(Unused) Image type.</param>
|
|
|
- /// <param name="index">(Unused) Image index.</param>
|
|
|
/// <response code="204">Image deleted.</response>
|
|
|
/// <response code="403">User does not have permission to delete the image.</response>
|
|
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
- [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<ActionResult> 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();
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Delete the user's image.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="userId">User Id.</param>
|
|
|
+ /// <param name="imageType">(Unused) Image type.</param>
|
|
|
+ /// <param name="index">(Unused) Image index.</param>
|
|
|
+ /// <response code="204">Image deleted.</response>
|
|
|
+ /// <response code="403">User does not have permission to delete the image.</response>
|
|
|
+ /// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
+ [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<ActionResult> DeleteUserImageLegacy(
|
|
|
+ [FromRoute, Required] Guid userId,
|
|
|
+ [FromRoute, Required] ImageType imageType,
|
|
|
+ [FromQuery] int? index = null)
|
|
|
+ => DeleteUserImage(userId);
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Delete the user's image.
|
|
|
/// </summary>
|
|
@@ -257,38 +259,17 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
|
|
[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<ActionResult> DeleteUserImageByIndex(
|
|
|
+ public Task<ActionResult> 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);
|
|
|
|
|
|
/// <summary>
|
|
|
/// Delete an item's image.
|
|
@@ -541,7 +522,6 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="format">Optional. The <see cref="ImageFormat"/> of the returned image.</param>
|
|
|
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
|
|
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
|
@@ -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
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="format">Optional. The <see cref="ImageFormat"/> of the returned image.</param>
|
|
|
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
|
|
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
|
@@ -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
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
|
|
/// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
|
|
/// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -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.
|
|
|
/// </summary>
|
|
|
/// <param name="userId">User id.</param>
|
|
|
- /// <param name="imageType">Image type.</param>
|
|
|
/// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
|
|
/// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
|
|
/// <param name="maxWidth">The maximum image width to return.</param>
|
|
@@ -1504,25 +1460,25 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
|
/// <param name="imageIndex">Image index.</param>
|
|
|
/// <response code="200">Image stream returned.</response>
|
|
|
+ /// <response code="400">User id not provided.</response>
|
|
|
/// <response code="404">Item not found.</response>
|
|
|
/// <returns>
|
|
|
/// A <see cref="FileStreamResult"/> containing the file stream on success,
|
|
|
/// or a <see cref="NotFoundResult"/> if item not found.
|
|
|
/// </returns>
|
|
|
- [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<ActionResult> 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);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Get user profile image.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="userId">User id.</param>
|
|
|
+ /// <param name="imageType">Image type.</param>
|
|
|
+ /// <param name="tag">Optional. Supply the cache tag from the item object to receive strong caching headers.</param>
|
|
|
+ /// <param name="format">Determines the output format of the image - original,gif,jpg,png.</param>
|
|
|
+ /// <param name="maxWidth">The maximum image width to return.</param>
|
|
|
+ /// <param name="maxHeight">The maximum image height to return.</param>
|
|
|
+ /// <param name="percentPlayed">Optional. Percent to render for the percent played overlay.</param>
|
|
|
+ /// <param name="unplayedCount">Optional. Unplayed count overlay to render.</param>
|
|
|
+ /// <param name="width">The fixed image width to return.</param>
|
|
|
+ /// <param name="height">The fixed image height to return.</param>
|
|
|
+ /// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
+ /// <param name="fillWidth">Width of box to fill.</param>
|
|
|
+ /// <param name="fillHeight">Height of box to fill.</param>
|
|
|
+ /// <param name="blur">Optional. Blur image.</param>
|
|
|
+ /// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
+ /// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
|
+ /// <param name="imageIndex">Image index.</param>
|
|
|
+ /// <response code="200">Image stream returned.</response>
|
|
|
+ /// <response code="404">Item not found.</response>
|
|
|
+ /// <returns>
|
|
|
+ /// A <see cref="FileStreamResult"/> containing the file stream on success,
|
|
|
+ /// or a <see cref="NotFoundResult"/> if item not found.
|
|
|
+ /// </returns>
|
|
|
+ [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<ActionResult> 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);
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Get user profile image.
|
|
|
/// </summary>
|
|
@@ -1603,7 +1633,6 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// <param name="quality">Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.</param>
|
|
|
/// <param name="fillWidth">Width of box to fill.</param>
|
|
|
/// <param name="fillHeight">Height of box to fill.</param>
|
|
|
- /// <param name="cropWhitespace">Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.</param>
|
|
|
/// <param name="blur">Optional. Blur image.</param>
|
|
|
/// <param name="backgroundColor">Optional. Apply a background color for transparent images.</param>
|
|
|
/// <param name="foregroundLayer">Optional. Apply a foreground layer on top of the image.</param>
|
|
@@ -1614,11 +1643,13 @@ public class ImageController : BaseJellyfinApiController
|
|
|
/// or a <see cref="NotFoundResult"/> if item not found.
|
|
|
/// </returns>
|
|
|
[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<ActionResult> GetUserImageByIndex(
|
|
|
+ public Task<ActionResult> 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);
|
|
|
|
|
|
/// <summary>
|
|
|
/// Generates or gets the splashscreen.
|