From bce22fcc2a50d533e4d69760ec99cd09c4cb7ad7 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 12 Nov 2023 17:52:24 +0300 Subject: [PATCH 1/8] Added new API endpoint to update User item data --- Jellyfin.Api/Controllers/ItemsController.cs | 106 +++++++++++++++++- .../Entities/UserDataSaveReason.cs | 7 +- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 4e46e808ae..38a7d115e5 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Threading; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; @@ -34,6 +35,7 @@ public class ItemsController : BaseJellyfinApiController private readonly IDtoService _dtoService; private readonly ILogger _logger; private readonly ISessionManager _sessionManager; + private readonly IUserDataManager _userDataRepository; /// /// Initializes a new instance of the class. @@ -44,13 +46,15 @@ public class ItemsController : BaseJellyfinApiController /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. + /// Instance of the interface. public ItemsController( IUserManager userManager, ILibraryManager libraryManager, ILocalizationManager localization, IDtoService dtoService, ILogger logger, - ISessionManager sessionManager) + ISessionManager sessionManager, + IUserDataManager userDataRepository) { _userManager = userManager; _libraryManager = libraryManager; @@ -58,6 +62,7 @@ public class ItemsController : BaseJellyfinApiController _dtoService = dtoService; _logger = logger; _sessionManager = sessionManager; + _userDataRepository = userDataRepository; } /// @@ -881,4 +886,103 @@ public class ItemsController : BaseJellyfinApiController itemsResult.TotalRecordCount, returnItems); } + + /// + /// Get Item User Data. + /// + /// The user id. + /// The item id. + /// item user data returned. + /// When item is not found. + /// Return Item . + [HttpGet("Users/{userId}/Items/{itemId}/UserData")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult GetItemUserData( + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId) + { + var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException(); + var item = _libraryManager.GetItemById(itemId); + + return (item == null) ? NotFound() : _userDataRepository.GetUserDataDto(item, user); + } + + /// + /// Update Item User Data. + /// + /// The user id. + /// The item id. + /// Optional. Whether to mark the item as played. + /// Optional. Whether to mark the item as favorite. + /// Optional. Whether mark the item as liked. + /// Optional. User item rating. + /// Optional. User Item playback Position Ticks. 1 tick = 10000 ms. + /// Item user data. + /// Optional. The date the item was played. + /// update user data returned. + /// When item is not found. + /// . + [HttpPost("Users/{userId}/Items/{itemId}/UserData")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult UpdateItemUserData( + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId, + [FromQuery] bool? played, + [FromQuery] bool? favorite, + [FromQuery] bool? likes, + [FromQuery] double? rating, + [FromQuery] long? playbackPositionTicks, + [FromQuery] int? playCount, + [FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? lastPlayedDate) + { + var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException(); + var item = _libraryManager.GetItemById(itemId); + if (item == null) + { + return NotFound(); + } + + var userData = _userDataRepository.GetUserData(user, item); + + if (played.HasValue) + { + userData.Played = played.Value; + } + + if (favorite.HasValue) + { + userData.IsFavorite = favorite.Value; + } + + if (likes.HasValue) + { + userData.Likes = likes.Value; + } + + if (rating.HasValue) + { + userData.Rating = rating.Value; + } + + if (playbackPositionTicks.HasValue) + { + userData.PlaybackPositionTicks = playbackPositionTicks.Value; + } + + if (playCount.HasValue) + { + userData.PlayCount = playCount.Value; + } + + if (lastPlayedDate.HasValue) + { + userData.LastPlayedDate = lastPlayedDate.Value; + } + + _userDataRepository.SaveUserData(user.Id, item, userData, UserDataSaveReason.UpdateUserData, CancellationToken.None); + + return _userDataRepository.GetUserDataDto(item, user); + } } diff --git a/MediaBrowser.Model/Entities/UserDataSaveReason.cs b/MediaBrowser.Model/Entities/UserDataSaveReason.cs index 20404e6f4d..b8e73a98cd 100644 --- a/MediaBrowser.Model/Entities/UserDataSaveReason.cs +++ b/MediaBrowser.Model/Entities/UserDataSaveReason.cs @@ -33,6 +33,11 @@ namespace MediaBrowser.Model.Entities /// /// The import. /// - Import = 6 + Import = 6, + + /// + /// API call updated item user data. + /// + UpdateUserData = 7, } } From 250e795c3be21586f50414efff2a9846588ac864 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 12 Nov 2023 18:12:34 +0300 Subject: [PATCH 2/8] Typo fixes. --- Jellyfin.Api/Controllers/ItemsController.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 38a7d115e5..8c816f8022 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -892,9 +892,9 @@ public class ItemsController : BaseJellyfinApiController /// /// The user id. /// The item id. - /// item user data returned. - /// When item is not found. - /// Return Item . + /// return item user data. + /// Item is not found. + /// Return . [HttpGet("Users/{userId}/Items/{itemId}/UserData")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -915,14 +915,14 @@ public class ItemsController : BaseJellyfinApiController /// The item id. /// Optional. Whether to mark the item as played. /// Optional. Whether to mark the item as favorite. - /// Optional. Whether mark the item as liked. + /// Optional. Whether to mark the item as liked. /// Optional. User item rating. - /// Optional. User Item playback Position Ticks. 1 tick = 10000 ms. - /// Item user data. + /// Optional. Item playback position ticks. 1 tick = 10000 ms. + /// Optional. How many times the user played the item. /// Optional. The date the item was played. - /// update user data returned. - /// When item is not found. - /// . + /// return updated user item data. + /// Item is not found. + /// Return . [HttpPost("Users/{userId}/Items/{itemId}/UserData")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] From 2a25c5a2e3e37e734993d17b7462598babcb0b97 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Mon, 13 Nov 2023 15:51:06 +0300 Subject: [PATCH 3/8] Refactored api call logic handling. --- .../Library/UserDataManager.cs | 37 ++++++++++++ Jellyfin.Api/Controllers/ItemsController.cs | 60 +++---------------- .../Library/IUserDataManager.cs | 9 +++ MediaBrowser.Model/Dto/UserDataDto.cs | 43 +++++++++++++ 4 files changed, 97 insertions(+), 52 deletions(-) create mode 100644 MediaBrowser.Model/Dto/UserDataDto.cs diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index a0a90b129f..0d67f2cda3 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Reflection; using System.Threading; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; @@ -81,6 +82,42 @@ namespace Emby.Server.Implementations.Library }); } + public void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason) + { + ArgumentNullException.ThrowIfNull(user); + ArgumentNullException.ThrowIfNull(item); + ArgumentNullException.ThrowIfNull(reason); + ArgumentNullException.ThrowIfNull(userDataDto); + + var userData = GetUserData(user, item); + + var parentProperties = userDataDto.GetType().GetProperties(); + var childProperties = userData.GetType().GetProperties(); + + foreach (var parentProperty in parentProperties) + { + foreach (var childProperty in childProperties) + { + if (parentProperty.Name != childProperty.Name) + { + continue; + } + + var value = parentProperty.GetValue(userDataDto, null); + + if (value is null) + { + continue; + } + + childProperty.SetValue(userData, value, null); + break; + } + } + + SaveUserData(user, item, userData, reason, CancellationToken.None); + } + /// /// Save the provided user data for the given user. Batch operation. Does not fire any events or update the cache. /// diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 8c816f8022..2a346be685 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -913,13 +913,7 @@ public class ItemsController : BaseJellyfinApiController /// /// The user id. /// The item id. - /// Optional. Whether to mark the item as played. - /// Optional. Whether to mark the item as favorite. - /// Optional. Whether to mark the item as liked. - /// Optional. User item rating. - /// Optional. Item playback position ticks. 1 tick = 10000 ms. - /// Optional. How many times the user played the item. - /// Optional. The date the item was played. + /// New user data object. /// return updated user item data. /// Item is not found. /// Return . @@ -929,14 +923,13 @@ public class ItemsController : BaseJellyfinApiController public ActionResult UpdateItemUserData( [FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, - [FromQuery] bool? played, - [FromQuery] bool? favorite, - [FromQuery] bool? likes, - [FromQuery] double? rating, - [FromQuery] long? playbackPositionTicks, - [FromQuery] int? playCount, - [FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? lastPlayedDate) + [FromBody, Required] UserDataDto 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) @@ -944,44 +937,7 @@ public class ItemsController : BaseJellyfinApiController return NotFound(); } - var userData = _userDataRepository.GetUserData(user, item); - - if (played.HasValue) - { - userData.Played = played.Value; - } - - if (favorite.HasValue) - { - userData.IsFavorite = favorite.Value; - } - - if (likes.HasValue) - { - userData.Likes = likes.Value; - } - - if (rating.HasValue) - { - userData.Rating = rating.Value; - } - - if (playbackPositionTicks.HasValue) - { - userData.PlaybackPositionTicks = playbackPositionTicks.Value; - } - - if (playCount.HasValue) - { - userData.PlayCount = playCount.Value; - } - - if (lastPlayedDate.HasValue) - { - userData.LastPlayedDate = lastPlayedDate.Value; - } - - _userDataRepository.SaveUserData(user.Id, item, userData, UserDataSaveReason.UpdateUserData, CancellationToken.None); + _userDataRepository.SaveUserData(user, item, userDataDto, UserDataSaveReason.UpdateUserData); return _userDataRepository.GetUserDataDto(item, user); } diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 034c405910..8849c098fb 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/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); + /// + /// Save the provided user data for the given user. + /// + /// The user. + /// The item. + /// The reason for updating the user data. + /// The reason. + void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason); + UserItemData GetUserData(User user, BaseItem item); UserItemData GetUserData(Guid userId, BaseItem item); diff --git a/MediaBrowser.Model/Dto/UserDataDto.cs b/MediaBrowser.Model/Dto/UserDataDto.cs new file mode 100644 index 0000000000..3012916f84 --- /dev/null +++ b/MediaBrowser.Model/Dto/UserDataDto.cs @@ -0,0 +1,43 @@ +#nullable disable +using System; + +namespace MediaBrowser.Model.Dto +{ + /// + /// Class UserDataDto extends UserItemDataDto to allow nullable members. + /// This change allow us to implement the new /Users/{UserId}/Items/{ItemId}/UserData endpoint. + /// This object allows the requestor to update all or specific user data fields without altering the non-nullable members state. + /// + public class UserDataDto : UserItemDataDto + { + /// + /// Gets or sets the playback position ticks. + /// + /// The playback position ticks. + public new long? PlaybackPositionTicks { get; set; } + + /// + /// Gets or sets the play count. + /// + /// The play count. + public new int? PlayCount { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is favorite. + /// + /// true if this instance is favorite; otherwise, false. + public new bool? IsFavorite { get; set; } + + /// + /// Gets or sets a value indicating whether this is likes. + /// + /// null if [likes] contains no value, true if [likes]; otherwise, false. + public new bool? Likes { get; set; } + + /// + /// Gets or sets a value indicating whether this is played. + /// + /// true if played; otherwise, false. + public new bool? Played { get; set; } + } +} From faa036aa7b696fd5091e52fd2bed6ed67ca63481 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Mon, 13 Nov 2023 15:55:12 +0300 Subject: [PATCH 4/8] Added access validation to view item user data. --- Jellyfin.Api/Controllers/ItemsController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 2a346be685..dd54e6ca78 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -902,6 +902,11 @@ public class ItemsController : BaseJellyfinApiController [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); From 07db2025a177bf5bed1cc898426a2442803ae151 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Mon, 13 Nov 2023 17:32:24 +0300 Subject: [PATCH 5/8] Refactored the code to not use reflection. --- .../Library/UserDataManager.cs | 47 ++++++++++++------- MediaBrowser.Model/Dto/UserDataDto.cs | 3 -- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 0d67f2cda3..585fdd4f09 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -91,28 +91,39 @@ namespace Emby.Server.Implementations.Library var userData = GetUserData(user, item); - var parentProperties = userDataDto.GetType().GetProperties(); - var childProperties = userData.GetType().GetProperties(); - - foreach (var parentProperty in parentProperties) + if (userDataDto.PlaybackPositionTicks.HasValue) { - foreach (var childProperty in childProperties) - { - if (parentProperty.Name != childProperty.Name) - { - continue; - } + userData.PlaybackPositionTicks = userDataDto.PlaybackPositionTicks.Value; + } - var value = parentProperty.GetValue(userDataDto, null); + if (userDataDto.PlayCount.HasValue) + { + userData.PlayCount = userDataDto.PlayCount.Value; + } - if (value is null) - { - continue; - } + if (userDataDto.IsFavorite.HasValue) + { + userData.IsFavorite = userDataDto.IsFavorite.Value; + } - childProperty.SetValue(userData, value, null); - break; - } + 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); diff --git a/MediaBrowser.Model/Dto/UserDataDto.cs b/MediaBrowser.Model/Dto/UserDataDto.cs index 3012916f84..6d8c8969b0 100644 --- a/MediaBrowser.Model/Dto/UserDataDto.cs +++ b/MediaBrowser.Model/Dto/UserDataDto.cs @@ -1,6 +1,3 @@ -#nullable disable -using System; - namespace MediaBrowser.Model.Dto { /// From c4013d2e10c2c526e21dd0229d60ab9e6c51d252 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Wed, 15 Nov 2023 13:55:14 +0300 Subject: [PATCH 6/8] Updated the summary and the Dto name. --- Emby.Server.Implementations/Library/UserDataManager.cs | 3 +-- Jellyfin.Api/Controllers/ItemsController.cs | 3 +-- MediaBrowser.Controller/Library/IUserDataManager.cs | 2 +- .../Dto/{UserDataDto.cs => UpdateUserItemDataDto.cs} | 6 ++---- 4 files changed, 5 insertions(+), 9 deletions(-) rename MediaBrowser.Model/Dto/{UserDataDto.cs => UpdateUserItemDataDto.cs} (78%) diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 585fdd4f09..8beeb8041f 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; -using System.Reflection; using System.Threading; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; @@ -82,7 +81,7 @@ namespace Emby.Server.Implementations.Library }); } - public void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason) + public void SaveUserData(User user, BaseItem item, UpdateUserItemDataDto userDataDto, UserDataSaveReason reason) { ArgumentNullException.ThrowIfNull(user); ArgumentNullException.ThrowIfNull(item); diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index dd54e6ca78..ae80d15e60 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; using System.Linq; -using System.Threading; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; @@ -928,7 +927,7 @@ public class ItemsController : BaseJellyfinApiController public ActionResult UpdateItemUserData( [FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, - [FromBody, Required] UserDataDto userDataDto) + [FromBody, Required] UpdateUserItemDataDto userDataDto) { if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true)) { diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 8849c098fb..43cccfc65c 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Controller.Library /// The item. /// The reason for updating the user data. /// The reason. - void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason); + void SaveUserData(User user, BaseItem item, UpdateUserItemDataDto userDataDto, UserDataSaveReason reason); UserItemData GetUserData(User user, BaseItem item); diff --git a/MediaBrowser.Model/Dto/UserDataDto.cs b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs similarity index 78% rename from MediaBrowser.Model/Dto/UserDataDto.cs rename to MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs index 6d8c8969b0..9ff09cb22c 100644 --- a/MediaBrowser.Model/Dto/UserDataDto.cs +++ b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs @@ -1,11 +1,9 @@ namespace MediaBrowser.Model.Dto { /// - /// Class UserDataDto extends UserItemDataDto to allow nullable members. - /// This change allow us to implement the new /Users/{UserId}/Items/{ItemId}/UserData endpoint. - /// This object allows the requestor to update all or specific user data fields without altering the non-nullable members state. + /// This is used by the api to get information about a item user data. /// - public class UserDataDto : UserItemDataDto + public class UpdateUserItemDataDto : UserItemDataDto { /// /// Gets or sets the playback position ticks. From 22c90141e7eaed43be399df06354f993636c64a3 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Thu, 23 Nov 2023 12:14:31 +0300 Subject: [PATCH 7/8] Made UpdateUserItemDataDto standalone object. --- .../Dto/UpdateUserItemDataDto.cs | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs index 9ff09cb22c..5c89c2470d 100644 --- a/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs +++ b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs @@ -1,38 +1,77 @@ +#nullable disable +using System; + namespace MediaBrowser.Model.Dto { /// /// This is used by the api to get information about a item user data. /// - public class UpdateUserItemDataDto : UserItemDataDto + public class UpdateUserItemDataDto { + /// + /// Gets or sets the rating. + /// + /// The rating. + public double? Rating { get; set; } + + /// + /// Gets or sets the played percentage. + /// + /// The played percentage. + public double? PlayedPercentage { get; set; } + + /// + /// Gets or sets the unplayed item count. + /// + /// The unplayed item count. + public int? UnplayedItemCount { get; set; } + /// /// Gets or sets the playback position ticks. /// /// The playback position ticks. - public new long? PlaybackPositionTicks { get; set; } + public long? PlaybackPositionTicks { get; set; } /// /// Gets or sets the play count. /// /// The play count. - public new int? PlayCount { get; set; } + public int? PlayCount { get; set; } /// /// Gets or sets a value indicating whether this instance is favorite. /// /// true if this instance is favorite; otherwise, false. - public new bool? IsFavorite { get; set; } + public bool? IsFavorite { get; set; } /// - /// Gets or sets a value indicating whether this is likes. + /// Gets or sets a value indicating whether this is likes. /// /// null if [likes] contains no value, true if [likes]; otherwise, false. - public new bool? Likes { get; set; } + public bool? Likes { get; set; } + + /// + /// Gets or sets the last played date. + /// + /// The last played date. + public DateTime? LastPlayedDate { get; set; } /// /// Gets or sets a value indicating whether this is played. /// /// true if played; otherwise, false. - public new bool? Played { get; set; } + public bool? Played { get; set; } + + /// + /// Gets or sets the key. + /// + /// The key. + public string Key { get; set; } + + /// + /// Gets or sets the item identifier. + /// + /// The item identifier. + public string ItemId { get; set; } } } From 324c86e14d9d76670b4e3439c2ed5fcbbfb9f8ff Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Thu, 23 Nov 2023 14:37:37 +0300 Subject: [PATCH 8/8] Made key & itemId nullable --- MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs index 5c89c2470d..7bfedf9735 100644 --- a/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs +++ b/MediaBrowser.Model/Dto/UpdateUserItemDataDto.cs @@ -1,4 +1,3 @@ -#nullable disable using System; namespace MediaBrowser.Model.Dto @@ -66,12 +65,12 @@ namespace MediaBrowser.Model.Dto /// Gets or sets the key. /// /// The key. - public string Key { get; set; } + public string? Key { get; set; } /// /// Gets or sets the item identifier. /// /// The item identifier. - public string ItemId { get; set; } + public string? ItemId { get; set; } } }