Merge pull request #10573 from arabcoders/master

Add new API endpoint to view/update Item UserData
This commit is contained in:
Bond-009 2023-12-15 18:00:50 +01:00 committed by GitHub
commit 24cbd64450
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 203 additions and 2 deletions

View File

@ -81,6 +81,53 @@ namespace Emby.Server.Implementations.Library
});
}
public void SaveUserData(User user, BaseItem item, UpdateUserItemDataDto userDataDto, UserDataSaveReason reason)
{
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(item);
ArgumentNullException.ThrowIfNull(reason);
ArgumentNullException.ThrowIfNull(userDataDto);
var userData = GetUserData(user, item);
if (userDataDto.PlaybackPositionTicks.HasValue)
{
userData.PlaybackPositionTicks = userDataDto.PlaybackPositionTicks.Value;
}
if (userDataDto.PlayCount.HasValue)
{
userData.PlayCount = userDataDto.PlayCount.Value;
}
if (userDataDto.IsFavorite.HasValue)
{
userData.IsFavorite = userDataDto.IsFavorite.Value;
}
if (userDataDto.Likes.HasValue)
{
userData.Likes = userDataDto.Likes.Value;
}
if (userDataDto.Played.HasValue)
{
userData.Played = userDataDto.Played.Value;
}
if (userDataDto.LastPlayedDate.HasValue)
{
userData.LastPlayedDate = userDataDto.LastPlayedDate.Value;
}
if (userDataDto.Rating.HasValue)
{
userData.Rating = userDataDto.Rating.Value;
}
SaveUserData(user, item, userData, reason, CancellationToken.None);
}
/// <summary>
/// Save the provided user data for the given user. Batch operation. Does not fire any events or update the cache.
/// </summary>

View File

@ -34,6 +34,7 @@ public class ItemsController : BaseJellyfinApiController
private readonly IDtoService _dtoService;
private readonly ILogger<ItemsController> _logger;
private readonly ISessionManager _sessionManager;
private readonly IUserDataManager _userDataRepository;
/// <summary>
/// Initializes a new instance of the <see cref="ItemsController"/> class.
@ -44,13 +45,15 @@ public class ItemsController : BaseJellyfinApiController
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
/// <param name="userDataRepository">Instance of the <see cref="IUserDataManager"/> interface.</param>
public ItemsController(
IUserManager userManager,
ILibraryManager libraryManager,
ILocalizationManager localization,
IDtoService dtoService,
ILogger<ItemsController> logger,
ISessionManager sessionManager)
ISessionManager sessionManager,
IUserDataManager userDataRepository)
{
_userManager = userManager;
_libraryManager = libraryManager;
@ -58,6 +61,7 @@ public class ItemsController : BaseJellyfinApiController
_dtoService = dtoService;
_logger = logger;
_sessionManager = sessionManager;
_userDataRepository = userDataRepository;
}
/// <summary>
@ -881,4 +885,64 @@ public class ItemsController : BaseJellyfinApiController
itemsResult.TotalRecordCount,
returnItems);
}
/// <summary>
/// Get Item User Data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <response code="200">return item user data.</response>
/// <response code="404">Item is not found.</response>
/// <returns>Return <see cref="UserItemDataDto"/>.</returns>
[HttpGet("Users/{userId}/Items/{itemId}/UserData")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<UserItemDataDto> GetItemUserData(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId)
{
if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true))
{
return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to view this item user data.");
}
var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException();
var item = _libraryManager.GetItemById(itemId);
return (item == null) ? NotFound() : _userDataRepository.GetUserDataDto(item, user);
}
/// <summary>
/// Update Item User Data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="userDataDto">New user data object.</param>
/// <response code="200">return updated user item data.</response>
/// <response code="404">Item is not found.</response>
/// <returns>Return <see cref="UserItemDataDto"/>.</returns>
[HttpPost("Users/{userId}/Items/{itemId}/UserData")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<UserItemDataDto> UpdateItemUserData(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId,
[FromBody, Required] UpdateUserItemDataDto userDataDto)
{
if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true))
{
return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update this item user data.");
}
var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException();
var item = _libraryManager.GetItemById(itemId);
if (item == null)
{
return NotFound();
}
_userDataRepository.SaveUserData(user, item, userDataDto, UserDataSaveReason.UpdateUserData);
return _userDataRepository.GetUserDataDto(item, user);
}
}

View File

@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Library
void SaveUserData(User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
/// <summary>
/// Save the provided user data for the given user.
/// </summary>
/// <param name="user">The user.</param>
/// <param name="item">The item.</param>
/// <param name="userDataDto">The reason for updating the user data.</param>
/// <param name="reason">The reason.</param>
void SaveUserData(User user, BaseItem item, UpdateUserItemDataDto userDataDto, UserDataSaveReason reason);
UserItemData GetUserData(User user, BaseItem item);
UserItemData GetUserData(Guid userId, BaseItem item);

View File

@ -0,0 +1,76 @@
using System;
namespace MediaBrowser.Model.Dto
{
/// <summary>
/// This is used by the api to get information about a item user data.
/// </summary>
public class UpdateUserItemDataDto
{
/// <summary>
/// Gets or sets the rating.
/// </summary>
/// <value>The rating.</value>
public double? Rating { get; set; }
/// <summary>
/// Gets or sets the played percentage.
/// </summary>
/// <value>The played percentage.</value>
public double? PlayedPercentage { get; set; }
/// <summary>
/// Gets or sets the unplayed item count.
/// </summary>
/// <value>The unplayed item count.</value>
public int? UnplayedItemCount { get; set; }
/// <summary>
/// Gets or sets the playback position ticks.
/// </summary>
/// <value>The playback position ticks.</value>
public long? PlaybackPositionTicks { get; set; }
/// <summary>
/// Gets or sets the play count.
/// </summary>
/// <value>The play count.</value>
public int? PlayCount { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is favorite.
/// </summary>
/// <value><c>true</c> if this instance is favorite; otherwise, <c>false</c>.</value>
public bool? IsFavorite { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="UpdateUserItemDataDto" /> is likes.
/// </summary>
/// <value><c>null</c> if [likes] contains no value, <c>true</c> if [likes]; otherwise, <c>false</c>.</value>
public bool? Likes { get; set; }
/// <summary>
/// Gets or sets the last played date.
/// </summary>
/// <value>The last played date.</value>
public DateTime? LastPlayedDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="UserItemDataDto" /> is played.
/// </summary>
/// <value><c>true</c> if played; otherwise, <c>false</c>.</value>
public bool? Played { get; set; }
/// <summary>
/// Gets or sets the key.
/// </summary>
/// <value>The key.</value>
public string? Key { get; set; }
/// <summary>
/// Gets or sets the item identifier.
/// </summary>
/// <value>The item identifier.</value>
public string? ItemId { get; set; }
}
}

View File

@ -33,6 +33,11 @@ namespace MediaBrowser.Model.Entities
/// <summary>
/// The import.
/// </summary>
Import = 6
Import = 6,
/// <summary>
/// API call updated item user data.
/// </summary>
UpdateUserData = 7,
}
}