diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 8b931f1621..10556da65d 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -91,31 +91,31 @@ public class ArtistsController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] studios, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -295,31 +295,31 @@ public class ArtistsController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] studios, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index f83c71b578..2f55e88ec4 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -121,10 +121,10 @@ public class ChannelsController : BaseJellyfinApiController [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -197,9 +197,9 @@ public class ChannelsController : BaseJellyfinApiController [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] channelIds) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 2d9f1ed69a..c37f376335 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -50,7 +50,7 @@ public class CollectionController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateCollection( [FromQuery] string? name, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] ids, [FromQuery] Guid? parentId, [FromQuery] bool isLocked = false) { @@ -86,7 +86,7 @@ public class CollectionController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task AddToCollection( [FromRoute, Required] Guid collectionId, - [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids) { await _collectionManager.AddToCollectionAsync(collectionId, ids).ConfigureAwait(true); return NoContent(); @@ -103,7 +103,7 @@ public class CollectionController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RemoveFromCollection( [FromRoute, Required] Guid collectionId, - [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids) { await _collectionManager.RemoveFromCollectionAsync(collectionId, ids).ConfigureAwait(false); return NoContent(); diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index 4abca32713..3f9aa93a64 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -50,8 +50,8 @@ public class FilterController : BaseJellyfinApiController public ActionResult GetQueryFiltersLegacy( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -137,7 +137,7 @@ public class FilterController : BaseJellyfinApiController public ActionResult GetQueryFilters( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isAiring, [FromQuery] bool? isMovie, [FromQuery] bool? isSports, diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 54d48aec21..f0d17decbf 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -76,18 +76,18 @@ public class GenresController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 87a856d38e..e326b925b8 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -73,11 +73,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -117,11 +117,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -161,11 +161,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -203,11 +203,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] string name, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -241,11 +241,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -285,11 +285,11 @@ public class InstantMixController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -330,11 +330,11 @@ public class InstantMixController : BaseJellyfinApiController [FromQuery, Required] Guid id, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { return GetInstantMixFromArtists( id, @@ -368,11 +368,11 @@ public class InstantMixController : BaseJellyfinApiController [FromQuery, Required] Guid id, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 775d723b0b..ed2f49b864 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -171,8 +171,8 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] bool? hasParentalRating, [FromQuery] bool? isHd, [FromQuery] bool? is4K, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] locationTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] excludeLocationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] locationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] excludeLocationTypes, [FromQuery] bool? isMissing, [FromQuery] bool? isUnaired, [FromQuery] double? minCommunityRating, @@ -190,42 +190,42 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] bool? isNews, [FromQuery] bool? isKids, [FromQuery] bool? isSports, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeItemIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeItemIds, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? recursive, [FromQuery] string? searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] imageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] imageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, [FromQuery] bool? isPlayed, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] artists, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] artistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] contributingArtistIds, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] albums, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] VideoType[] videoTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] studios, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] artists, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] artistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] contributingArtistIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] albums, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] VideoType[] videoTypes, [FromQuery] string? minOfficialRating, [FromQuery] bool? isLocked, [FromQuery] bool? isPlaceHolder, @@ -236,12 +236,12 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] bool? is3D, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SeriesStatus[] seriesStatus, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SeriesStatus[] seriesStatus, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { @@ -638,8 +638,8 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] bool? hasParentalRating, [FromQuery] bool? isHd, [FromQuery] bool? is4K, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] locationTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] excludeLocationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] locationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] excludeLocationTypes, [FromQuery] bool? isMissing, [FromQuery] bool? isUnaired, [FromQuery] double? minCommunityRating, @@ -657,42 +657,42 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] bool? isNews, [FromQuery] bool? isKids, [FromQuery] bool? isSports, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeItemIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeItemIds, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? recursive, [FromQuery] string? searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] imageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] imageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, [FromQuery] bool? isPlayed, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] artists, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] artistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] contributingArtistIds, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] albums, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] VideoType[] videoTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] studios, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] artists, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] artistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] contributingArtistIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] albums, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] VideoType[] videoTypes, [FromQuery] string? minOfficialRating, [FromQuery] bool? isLocked, [FromQuery] bool? isPlaceHolder, @@ -703,12 +703,12 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] bool? is3D, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SeriesStatus[] seriesStatus, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SeriesStatus[] seriesStatus, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) => GetItems( @@ -827,13 +827,13 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true, [FromQuery] bool excludeActiveSessions = false) @@ -929,13 +929,13 @@ public class ItemsController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true, [FromQuery] bool excludeActiveSessions = false) diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 0b2d4b0325..7c6160fc49 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -144,8 +144,8 @@ public class LibraryController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] bool inheritFromParent = false, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[]? sortBy = null, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[]? sortOrder = null) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -218,8 +218,8 @@ public class LibraryController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] bool inheritFromParent = false, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[]? sortBy = null, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[]? sortOrder = null) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() @@ -290,8 +290,8 @@ public class LibraryController : BaseJellyfinApiController [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] bool inheritFromParent = false, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[]? sortBy = null, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[]? sortOrder = null) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[]? sortBy = null, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[]? sortOrder = null) { var themeSongs = GetThemeSongs( itemId, @@ -400,7 +400,7 @@ public class LibraryController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteItems([FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) + public ActionResult DeleteItems([FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids) { var isApiKey = User.GetIsApiKey(); var userId = User.GetUserId(); @@ -722,10 +722,10 @@ public class LibraryController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarItems( [FromRoute, Required] Guid itemId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds, [FromQuery] Guid? userId, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields) { userId = RequestHelpers.GetUserId(User, userId); var user = userId.IsNullOrEmpty() diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index 55000fc91e..2a885662b5 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -77,7 +77,7 @@ public class LibraryStructureController : BaseJellyfinApiController public async Task AddVirtualFolder( [FromQuery] string name, [FromQuery] CollectionTypeOptions? collectionType, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] paths, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] paths, [FromBody] AddVirtualFolderDto? libraryOptionsDto, [FromQuery] bool refreshLibrary = false) { diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 421f23fa1e..a3b4c87004 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -159,10 +159,10 @@ public class LiveTvController : BaseJellyfinApiController [FromQuery] bool? isDisliked, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, [FromQuery] SortOrder? sortOrder, [FromQuery] bool enableFavoriteSorting = false, [FromQuery] bool addCurrentProgram = true) @@ -283,8 +283,8 @@ public class LiveTvController : BaseJellyfinApiController [FromQuery] string? seriesTimerId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, @@ -371,8 +371,8 @@ public class LiveTvController : BaseJellyfinApiController [FromQuery] string? seriesTimerId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, [FromQuery] bool enableTotalRecordCount = true) { @@ -566,7 +566,7 @@ public class LiveTvController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.LiveTvAccess)] public async Task>> GetLiveTvPrograms( - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] channelIds, [FromQuery] Guid? userId, [FromQuery] DateTime? minStartDate, [FromQuery] bool? hasAired, @@ -581,17 +581,17 @@ public class LiveTvController : BaseJellyfinApiController [FromQuery] bool? isSports, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] string? seriesTimerId, [FromQuery] Guid? librarySeriesId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool enableTotalRecordCount = true) { userId = RequestHelpers.GetUserId(User, userId); @@ -730,9 +730,9 @@ public class LiveTvController : BaseJellyfinApiController [FromQuery] bool? isSports, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, [FromQuery] bool enableTotalRecordCount = true) { diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index 2d917d61fb..cbbaaddbfe 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -65,7 +65,7 @@ public class MoviesController : BaseJellyfinApiController public ActionResult> GetMovieRecommendations( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] int categoryLimit = 5, [FromQuery] int itemLimit = 8) { diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 5411baa3e7..e8bc8f2657 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -76,18 +76,18 @@ public class MusicGenresController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 6ca3086015..b0c493fbec 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -67,14 +67,14 @@ public class PersonsController : BaseJellyfinApiController public ActionResult> GetPersons( [FromQuery] int? limit, [FromQuery] string? searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludePersonTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] excludePersonTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, [FromQuery] Guid? appearsInItemId, [FromQuery] Guid? userId, [FromQuery] bool? enableImages = true) diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 1ab36ccc64..ec5fdab38e 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -76,7 +76,7 @@ public class PlaylistsController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreatePlaylist( [FromQuery, ParameterObsolete] string? name, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder)), ParameterObsolete] IReadOnlyList ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder)), ParameterObsolete] IReadOnlyList ids, [FromQuery, ParameterObsolete] Guid? userId, [FromQuery, ParameterObsolete] MediaType? mediaType, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] CreatePlaylistDto? createPlaylistRequest) @@ -370,7 +370,7 @@ public class PlaylistsController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task AddItemToPlaylist( [FromRoute, Required] Guid playlistId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids, [FromQuery] Guid? userId) { userId = RequestHelpers.GetUserId(User, userId); @@ -446,7 +446,7 @@ public class PlaylistsController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task RemoveItemFromPlaylist( [FromRoute, Required] string playlistId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] entryIds) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] entryIds) { var callingUserId = User.GetUserId(); @@ -493,11 +493,11 @@ public class PlaylistsController : BaseJellyfinApiController [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes) + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes) { var callingUserId = userId ?? User.GetUserId(); var playlist = _playlistManager.GetPlaylistForUser(playlistId, callingUserId); diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 8bae6fb9b6..ecf2335ba0 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -84,9 +84,9 @@ public class SearchController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] Guid? userId, [FromQuery, Required] string searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, [FromQuery] Guid? parentId, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index 2f9e9f091d..9886d03dee 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -122,7 +122,7 @@ public class SessionController : BaseJellyfinApiController public async Task Play( [FromRoute, Required] string sessionId, [FromQuery, Required] PlayCommand playCommand, - [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] itemIds, + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] itemIds, [FromQuery] long? startPositionTicks, [FromQuery] string? mediaSourceId, [FromQuery] int? audioStreamIndex, @@ -347,8 +347,8 @@ public class SessionController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task PostCapabilities( [FromQuery] string? id, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] playableMediaTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] GeneralCommandType[] supportedCommands, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] playableMediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] GeneralCommandType[] supportedCommands, [FromQuery] bool supportsMediaControl = false, [FromQuery] bool supportsPersistentIdentifier = true) { diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 708fc7436f..43c5384dce 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -73,13 +73,13 @@ public class StudiosController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] string? searchTerm, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index ad625cc6e0..9b56d08494 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -59,8 +59,8 @@ public class SuggestionsController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSuggestions( [FromQuery] Guid? userId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaType, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] type, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaType, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] type, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool enableTotalRecordCount = false) @@ -115,8 +115,8 @@ public class SuggestionsController : BaseJellyfinApiController [ApiExplorerSettings(IgnoreApi = true)] public ActionResult> GetSuggestionsLegacy( [FromRoute, Required] Guid userId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaType, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] type, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaType, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] type, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool enableTotalRecordCount = false) diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index d7d0cc4544..7ee4396bba 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -130,8 +130,8 @@ public class TrailersController : BaseJellyfinApiController [FromQuery] bool? hasParentalRating, [FromQuery] bool? isHd, [FromQuery] bool? is4K, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] locationTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] excludeLocationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] locationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] LocationType[] excludeLocationTypes, [FromQuery] bool? isMissing, [FromQuery] bool? isUnaired, [FromQuery] double? minCommunityRating, @@ -149,41 +149,41 @@ public class TrailersController : BaseJellyfinApiController [FromQuery] bool? isNews, [FromQuery] bool? isKids, [FromQuery] bool? isSports, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeItemIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeItemIds, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? recursive, [FromQuery] string? searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] imageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] imageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, [FromQuery] bool? isPlayed, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, - [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedCollectionModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] studios, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] artists, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] artistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] contributingArtistIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] albums, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] VideoType[] videoTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] studios, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] artists, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] artistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] contributingArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] albums, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] albumIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] VideoType[] videoTypes, [FromQuery] string? minOfficialRating, [FromQuery] bool? isLocked, [FromQuery] bool? isPlaceHolder, @@ -194,12 +194,12 @@ public class TrailersController : BaseJellyfinApiController [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] bool? is3D, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SeriesStatus[] seriesStatus, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SeriesStatus[] seriesStatus, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] genreIds, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 914ccd7f93..df46c2dac9 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -77,12 +77,12 @@ public class TvShowsController : BaseJellyfinApiController [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] Guid? seriesId, [FromQuery] Guid? parentId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] DateTime? nextUpDateCutoff, [FromQuery] bool enableTotalRecordCount = true, @@ -143,11 +143,11 @@ public class TvShowsController : BaseJellyfinApiController [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] Guid? parentId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData) { userId = RequestHelpers.GetUserId(User, userId); @@ -208,7 +208,7 @@ public class TvShowsController : BaseJellyfinApiController public ActionResult> GetEpisodes( [FromRoute, Required] Guid seriesId, [FromQuery] Guid? userId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] int? season, [FromQuery] Guid? seasonId, [FromQuery] bool? isMissing, @@ -218,7 +218,7 @@ public class TvShowsController : BaseJellyfinApiController [FromQuery] int? limit, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] ItemSortBy? sortBy) { @@ -332,13 +332,13 @@ public class TvShowsController : BaseJellyfinApiController public ActionResult> GetSeasons( [FromRoute, Required] Guid seriesId, [FromQuery] Guid? userId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, [FromQuery] bool? isSpecialSeason, [FromQuery] bool? isMissing, [FromQuery] Guid? adjacentTo, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData) { userId = RequestHelpers.GetUserId(User, userId); diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 4fe2d52daf..a5b5fde626 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -98,7 +98,7 @@ public class UniversalAudioController : BaseJellyfinApiController [ProducesAudioFile] public async Task GetUniversalAudioStream( [FromRoute, Required] Guid itemId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] container, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] string[] container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 7cce13e424..6cc2b4244c 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -523,12 +523,12 @@ public class UserLibraryController : BaseJellyfinApiController public ActionResult> GetLatestMedia( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isPlayed, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] int limit = 20, [FromQuery] bool groupItems = true) @@ -608,12 +608,12 @@ public class UserLibraryController : BaseJellyfinApiController public ActionResult> GetLatestMediaLegacy( [FromRoute, Required] Guid userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isPlayed, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] int limit = 20, [FromQuery] bool groupItems = true) diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index e24f78a888..64b2dffb32 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -66,7 +66,7 @@ public class UserViewsController : BaseJellyfinApiController public QueryResult GetUserViews( [FromQuery] Guid? userId, [FromQuery] bool? includeExternalContent, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] CollectionType?[] presetViews, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] CollectionType?[] presetViews, [FromQuery] bool includeHidden = false) { userId = RequestHelpers.GetUserId(User, userId); @@ -110,7 +110,7 @@ public class UserViewsController : BaseJellyfinApiController public QueryResult GetUserViewsLegacy( [FromRoute, Required] Guid userId, [FromQuery] bool? includeExternalContent, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] CollectionType?[] presetViews, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] CollectionType?[] presetViews, [FromQuery] bool includeHidden = false) => GetUserViews(userId, includeExternalContent, presetViews, includeHidden); diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 8348fd937d..6f18c1603b 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -184,7 +184,7 @@ public class VideosController : BaseJellyfinApiController [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task MergeVersions([FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) + public async Task MergeVersions([FromQuery, Required, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] ids) { var userId = User.GetUserId(); var items = ids diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index e709e43e26..2b32ae728c 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -72,16 +72,16 @@ public class YearsController : BaseJellyfinApiController public ActionResult> GetYears( [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] MediaType[] mediaTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemSortBy[] sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] MediaType[] mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, [FromQuery] Guid? userId, [FromQuery] bool recursive = true, [FromQuery] bool? enableImages = true) diff --git a/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs b/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs similarity index 88% rename from Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs rename to Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs index 3e3604b2ad..25b84cbcc5 100644 --- a/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs +++ b/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs @@ -8,18 +8,18 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Api.ModelBinders; /// -/// Comma delimited array model binder. +/// Comma delimited collection model binder. /// Returns an empty array of specified type if there is no query parameter. /// -public class CommaDelimitedArrayModelBinder : IModelBinder +public class CommaDelimitedCollectionModelBinder : IModelBinder { - private readonly ILogger _logger; + private readonly ILogger _logger; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Instance of the interface. - public CommaDelimitedArrayModelBinder(ILogger logger) + /// Instance of the interface. + public CommaDelimitedCollectionModelBinder(ILogger logger) { _logger = logger; } diff --git a/Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs b/Jellyfin.Api/ModelBinders/PipeDelimitedCollectionModelBinder.cs similarity index 85% rename from Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs rename to Jellyfin.Api/ModelBinders/PipeDelimitedCollectionModelBinder.cs index ae9f0a8cdb..7d0fb2e191 100644 --- a/Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs +++ b/Jellyfin.Api/ModelBinders/PipeDelimitedCollectionModelBinder.cs @@ -8,18 +8,18 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Api.ModelBinders; /// -/// Comma delimited array model binder. -/// Returns an empty array of specified type if there is no query parameter. +/// Comma delimited collection model binder. +/// Returns an empty collection of specified type if there is no query parameter. /// -public class PipeDelimitedArrayModelBinder : IModelBinder +public class PipeDelimitedCollectionModelBinder : IModelBinder { - private readonly ILogger _logger; + private readonly ILogger _logger; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Instance of the interface. - public PipeDelimitedArrayModelBinder(ILogger logger) + /// Instance of the interface. + public PipeDelimitedCollectionModelBinder(ILogger logger) { _logger = logger; } diff --git a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs index 190d90681f..dece664262 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs @@ -17,7 +17,7 @@ public class GetProgramsDto /// /// Gets or sets the channels to return guide information for. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? ChannelIds { get; set; } /// @@ -93,25 +93,25 @@ public class GetProgramsDto /// /// Gets or sets specify one or more sort orders, comma delimited. Options: Name, StartDate. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? SortBy { get; set; } /// /// Gets or sets sort order. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? SortOrder { get; set; } /// /// Gets or sets the genres to return guide information for. /// - [JsonConverter(typeof(JsonPipeDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonPipeDelimitedCollectionConverterFactory))] public IReadOnlyList? Genres { get; set; } /// /// Gets or sets the genre ids to return guide information for. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? GenreIds { get; set; } /// @@ -133,7 +133,7 @@ public class GetProgramsDto /// /// Gets or sets the image types to include in the output. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? EnableImageTypes { get; set; } /// @@ -154,6 +154,6 @@ public class GetProgramsDto /// /// Gets or sets specify additional fields of information to return in the output. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? Fields { get; set; } } diff --git a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs index 61a3f2ed60..891d758c48 100644 --- a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs +++ b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs @@ -20,7 +20,7 @@ public class CreatePlaylistDto /// /// Gets or sets item ids to add to the playlist. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList Ids { get; set; } = []; /// diff --git a/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs b/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs index 80e20995c6..339a0d5d28 100644 --- a/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs +++ b/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs @@ -19,7 +19,7 @@ public class UpdatePlaylistDto /// /// Gets or sets item ids of the playlist. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList? Ids { get; set; } /// diff --git a/MediaBrowser.Model/Dto/ClientCapabilitiesDto.cs b/MediaBrowser.Model/Dto/ClientCapabilitiesDto.cs index 5963ed270d..d481593cd5 100644 --- a/MediaBrowser.Model/Dto/ClientCapabilitiesDto.cs +++ b/MediaBrowser.Model/Dto/ClientCapabilitiesDto.cs @@ -15,13 +15,13 @@ public class ClientCapabilitiesDto /// /// Gets or sets the list of playable media types. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList PlayableMediaTypes { get; set; } = []; /// /// Gets or sets the list of supported commands. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList SupportedCommands { get; set; } = []; /// diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverter.cs similarity index 57% rename from src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs rename to src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverter.cs index ccbc296fd9..b1946143dd 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverter.cs @@ -1,15 +1,15 @@ namespace Jellyfin.Extensions.Json.Converters { /// - /// Convert comma delimited string to array of type. + /// Convert comma delimited string to collection of type. /// /// Type to convert to. - public sealed class JsonCommaDelimitedArrayConverter : JsonDelimitedArrayConverter + public sealed class JsonCommaDelimitedCollectionConverter : JsonDelimitedCollectionConverter { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public JsonCommaDelimitedArrayConverter() : base() + public JsonCommaDelimitedCollectionConverter() : base() { } diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverterFactory.cs similarity index 57% rename from src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs rename to src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverterFactory.cs index a95e493dbb..daa79b2b5a 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverterFactory.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedCollectionConverterFactory.cs @@ -1,28 +1,31 @@ using System; +using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; namespace Jellyfin.Extensions.Json.Converters { /// - /// Json comma delimited array converter factory. + /// Json comma delimited collection converter factory. /// /// /// This must be applied as an attribute, adding to the JsonConverter list causes stack overflow. /// - public class JsonCommaDelimitedArrayConverterFactory : JsonConverterFactory + public class JsonCommaDelimitedCollectionConverterFactory : JsonConverterFactory { /// public override bool CanConvert(Type typeToConvert) { - return true; + return typeToConvert.IsArray + || (typeToConvert.IsGenericType + && (typeToConvert.GetGenericTypeDefinition().IsAssignableFrom(typeof(IReadOnlyCollection<>)) || typeToConvert.GetGenericTypeDefinition().IsAssignableFrom(typeof(IReadOnlyList<>)))); } /// public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var structType = typeToConvert.GetElementType() ?? typeToConvert.GenericTypeArguments[0]; - return (JsonConverter?)Activator.CreateInstance(typeof(JsonCommaDelimitedArrayConverter<>).MakeGenericType(structType)); + return (JsonConverter?)Activator.CreateInstance(typeof(JsonCommaDelimitedCollectionConverter<>).MakeGenericType(structType)); } } } diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedCollectionConverter.cs similarity index 67% rename from src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs rename to src/Jellyfin.Extensions/Json/Converters/JsonDelimitedCollectionConverter.cs index 7472f9c663..fe85d7f73f 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedArrayConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonDelimitedCollectionConverter.cs @@ -10,14 +10,14 @@ namespace Jellyfin.Extensions.Json.Converters /// Convert delimited string to array of type. /// /// Type to convert to. - public abstract class JsonDelimitedArrayConverter : JsonConverter + public abstract class JsonDelimitedCollectionConverter : JsonConverter> { private readonly TypeConverter _typeConverter; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected JsonDelimitedArrayConverter() + protected JsonDelimitedCollectionConverter() { _typeConverter = TypeDescriptor.GetConverter(typeof(T)); } @@ -28,7 +28,7 @@ namespace Jellyfin.Extensions.Json.Converters protected virtual char Delimiter { get; } /// - public override T[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IReadOnlyCollection? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { @@ -56,35 +56,21 @@ namespace Jellyfin.Extensions.Json.Converters } } - return typedValues.ToArray(); + if (typeToConvert.IsArray) + { + return typedValues.ToArray(); + } + + return typedValues; } return JsonSerializer.Deserialize(ref reader, options); } /// - public override void Write(Utf8JsonWriter writer, T[]? value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IReadOnlyCollection? value, JsonSerializerOptions options) { - if (value is not null) - { - writer.WriteStartArray(); - if (value.Length > 0) - { - foreach (var it in value) - { - if (it is not null) - { - writer.WriteStringValue(it.ToString()); - } - } - } - - writer.WriteEndArray(); - } - else - { - writer.WriteNullValue(); - } + JsonSerializer.Serialize(writer, value, options); } } } diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverter.cs similarity index 66% rename from src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs rename to src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverter.cs index 55720ee4f3..57378a360a 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverter.cs @@ -4,12 +4,12 @@ namespace Jellyfin.Extensions.Json.Converters /// Convert Pipe delimited string to array of type. /// /// Type to convert to. - public sealed class JsonPipeDelimitedArrayConverter : JsonDelimitedArrayConverter + public sealed class JsonPipeDelimitedCollectionConverter : JsonDelimitedCollectionConverter { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public JsonPipeDelimitedArrayConverter() : base() + public JsonPipeDelimitedCollectionConverter() : base() { } diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverterFactory.cs similarity index 57% rename from src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs rename to src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverterFactory.cs index ae9e1f67a0..f487fcaca4 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedCollectionConverterFactory.cs @@ -1,28 +1,31 @@ using System; +using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; namespace Jellyfin.Extensions.Json.Converters { /// - /// Json Pipe delimited array converter factory. + /// Json Pipe delimited collection converter factory. /// /// /// This must be applied as an attribute, adding to the JsonConverter list causes stack overflow. /// - public class JsonPipeDelimitedArrayConverterFactory : JsonConverterFactory + public class JsonPipeDelimitedCollectionConverterFactory : JsonConverterFactory { /// public override bool CanConvert(Type typeToConvert) { - return true; + return typeToConvert.IsArray + || (typeToConvert.IsGenericType + && (typeToConvert.GetGenericTypeDefinition().IsAssignableFrom(typeof(IReadOnlyCollection<>)) || typeToConvert.GetGenericTypeDefinition().IsAssignableFrom(typeof(IReadOnlyList<>)))); } /// public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var structType = typeToConvert.GetElementType() ?? typeToConvert.GenericTypeArguments[0]; - return (JsonConverter?)Activator.CreateInstance(typeof(JsonPipeDelimitedArrayConverter<>).MakeGenericType(structType)); + return (JsonConverter?)Activator.CreateInstance(typeof(JsonPipeDelimitedCollectionConverter<>).MakeGenericType(structType)); } } } diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedCollectionModelBinderTests.cs similarity index 91% rename from tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs rename to tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedCollectionModelBinderTests.cs index e37c9d91f3..e6b9acfe19 100644 --- a/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs +++ b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedCollectionModelBinderTests.cs @@ -12,7 +12,7 @@ using Xunit; namespace Jellyfin.Api.Tests.ModelBinders { - public sealed class CommaDelimitedArrayModelBinderTests + public sealed class CommaDelimitedCollectionModelBinderTests { [Fact] public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedStringArrayQuery() @@ -22,7 +22,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "lol,xd"; var queryParamType = typeof(string[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -47,7 +47,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "42,0"; var queryParamType = typeof(int[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -72,7 +72,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "How,Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -97,7 +97,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "How,,Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -123,7 +123,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString2 = "Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), @@ -151,7 +151,7 @@ namespace Jellyfin.Api.Tests.ModelBinders IReadOnlyList queryParamValues = Array.Empty(); var queryParamType = typeof(TestType[]); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), @@ -179,7 +179,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "🔥,😢"; var queryParamType = typeof(IReadOnlyList); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -205,7 +205,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString2 = "😱"; var queryParamType = typeof(IReadOnlyList); - var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs b/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedCollectionModelBinderTests.cs similarity index 91% rename from tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs rename to tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedCollectionModelBinderTests.cs index 7c05ee0362..941f4f12cc 100644 --- a/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs +++ b/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedCollectionModelBinderTests.cs @@ -12,7 +12,7 @@ using Xunit; namespace Jellyfin.Api.Tests.ModelBinders { - public sealed class PipeDelimitedArrayModelBinderTests + public sealed class PipeDelimitedCollectionModelBinderTests { [Fact] public async Task BindModelAsync_CorrectlyBindsValidPipeDelimitedStringArrayQuery() @@ -22,7 +22,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "lol|xd"; var queryParamType = typeof(string[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -47,7 +47,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "42|0"; var queryParamType = typeof(int[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -72,7 +72,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "How|Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -97,7 +97,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "How||Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -123,7 +123,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString2 = "Much"; var queryParamType = typeof(TestType[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), @@ -151,7 +151,7 @@ namespace Jellyfin.Api.Tests.ModelBinders IReadOnlyList queryParamValues = Array.Empty(); var queryParamType = typeof(TestType[]); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), @@ -179,7 +179,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString = "🔥|😢"; var queryParamType = typeof(IReadOnlyList); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), new QueryCollection(new Dictionary { { queryParamName, new StringValues(queryParamString) } }), @@ -205,7 +205,7 @@ namespace Jellyfin.Api.Tests.ModelBinders var queryParamString2 = "😱"; var queryParamType = typeof(IReadOnlyList); - var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger()); + var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger()); var valueProvider = new QueryStringValueProvider( new BindingSource(string.Empty, string.Empty, false, false), diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs similarity index 62% rename from tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs rename to tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs index d247b8cb18..83f917c17f 100644 --- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedArrayTests.cs +++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedCollectionTests.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Jellyfin.Extensions.Tests.Json.Models; @@ -7,7 +10,7 @@ using Xunit; namespace Jellyfin.Extensions.Tests.Json.Converters { - public class JsonCommaDelimitedArrayTests + public class JsonCommaDelimitedCollectionTests { private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions() { @@ -36,6 +39,29 @@ namespace Jellyfin.Extensions.Tests.Json.Converters Assert.Equal(desiredValue.Value, value?.Value); } + [Fact] + public void Deserialize_EmptyList_Success() + { + var desiredValue = new GenericBodyListModel + { + Value = [] + }; + + Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": """" }", _jsonOptions)); + } + + [Fact] + public void Deserialize_EmptyIReadOnlyList_Success() + { + var desiredValue = new GenericBodyIReadOnlyListModel + { + Value = [] + }; + + var value = JsonSerializer.Deserialize>(@"{ ""Value"": """" }", _jsonOptions); + Assert.Equal(desiredValue.Value, value?.Value); + } + [Fact] public void Deserialize_String_Valid_Success() { @@ -48,6 +74,17 @@ namespace Jellyfin.Extensions.Tests.Json.Converters Assert.Equal(desiredValue.Value, value?.Value); } + [Fact] + public void Deserialize_StringList_Valid_Success() + { + var desiredValue = new GenericBodyListModel + { + Value = ["a", "b", "c"] + }; + + Assert.Throws(() => JsonSerializer.Deserialize>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions)); + } + [Fact] public void Deserialize_String_Space_Valid_Success() { @@ -131,5 +168,41 @@ namespace Jellyfin.Extensions.Tests.Json.Converters var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions); Assert.Equal(desiredValue.Value, value?.Value); } + + [Fact] + public void Serialize_GenericCommandType_ReadOnlyArray_Valid_Success() + { + var valueToSerialize = new GenericBodyIReadOnlyCollectionModel + { + Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }.AsReadOnly() + }; + + string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions); + Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value); + } + + [Fact] + public void Serialize_GenericCommandType_ImmutableArrayArray_Valid_Success() + { + var valueToSerialize = new GenericBodyIReadOnlyCollectionModel + { + Value = ImmutableArray.Create(new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }) + }; + + string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions); + Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value); + } + + [Fact] + public void Serialize_GenericCommandType_List_Valid_Success() + { + var valueToSerialize = new GenericBodyIReadOnlyListModel + { + Value = new List { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown } + }; + + string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions); + Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value); + } } } diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs index 9b977b9a5d..26989d59b2 100644 --- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs +++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonCommaDelimitedIReadOnlyListTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; using Jellyfin.Extensions.Tests.Json.Models; @@ -87,5 +88,17 @@ namespace Jellyfin.Extensions.Tests.Json.Converters var value = JsonSerializer.Deserialize>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions); Assert.Equal(desiredValue.Value, value?.Value); } + + [Fact] + public void Serialize_GenericCommandType_IReadOnlyList_Valid_Success() + { + var valueToSerialize = new GenericBodyIReadOnlyListModel + { + Value = new List { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown } + }; + + string value = JsonSerializer.Serialize>(valueToSerialize, _jsonOptions); + Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value); + } } } diff --git a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs index 76669ea19c..a698c9c92b 100644 --- a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs +++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyArrayModel.cs @@ -14,7 +14,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models /// Gets or sets the value. /// [SuppressMessage("Microsoft.Performance", "CA1819:Properties should not return arrays", MessageId = "Value", Justification = "Imported from ServiceStack")] - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public T[] Value { get; set; } = default!; } } diff --git a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyCollectionModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyCollectionModel.cs new file mode 100644 index 0000000000..14cbc0f501 --- /dev/null +++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyCollectionModel.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Jellyfin.Extensions.Json.Converters; + +namespace Jellyfin.Extensions.Tests.Json.Models +{ + /// + /// The generic body IReadOnlyCollection model. + /// + /// The value type. + public sealed class GenericBodyIReadOnlyCollectionModel + { + /// + /// Gets or sets the value. + /// + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] + public IReadOnlyCollection Value { get; set; } = default!; + } +} diff --git a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs index 7e6b97afe1..eaa06a5dd4 100644 --- a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs +++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyIReadOnlyListModel.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models /// /// Gets or sets the value. /// - [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))] + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] public IReadOnlyList Value { get; set; } = default!; } } diff --git a/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyListModel.cs b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyListModel.cs new file mode 100644 index 0000000000..463f9922f6 --- /dev/null +++ b/tests/Jellyfin.Extensions.Tests/Json/Models/GenericBodyListModel.cs @@ -0,0 +1,22 @@ +#pragma warning disable CA1002 // Do not expose generic lists +#pragma warning disable CA2227 // Collection properties should be read only + +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Jellyfin.Extensions.Json.Converters; + +namespace Jellyfin.Extensions.Tests.Json.Models +{ + /// + /// The generic body List model. + /// + /// The value type. + public sealed class GenericBodyListModel + { + /// + /// Gets or sets the value. + /// + [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))] + public List Value { get; set; } = default!; + } +}