Преглед изворни кода

Merge pull request #10573 from arabcoders/master

Add new API endpoint to view/update Item UserData
Bond-009 пре 1 година
родитељ
комит
24cbd64450

+ 47 - 0
Emby.Server.Implementations/Library/UserDataManager.cs

@@ -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>

+ 65 - 1
Jellyfin.Api/Controllers/ItemsController.cs

@@ -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);
+    }
 }

+ 9 - 0
MediaBrowser.Controller/Library/IUserDataManager.cs

@@ -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);

+ 76 - 0
MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs

@@ -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; }
+    }
+}

+ 6 - 1
MediaBrowser.Model/Entities/UserDataSaveReason.cs

@@ -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,
     }
 }