aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api')
-rw-r--r--Jellyfin.Api/Auth/CustomAuthenticationHandler.cs14
-rw-r--r--Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs3
-rw-r--r--Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs1
-rw-r--r--Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs1
-rw-r--r--Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs2
-rw-r--r--Jellyfin.Api/Controllers/ArtistsController.cs71
-rw-r--r--Jellyfin.Api/Controllers/AudioController.cs2
-rw-r--r--Jellyfin.Api/Controllers/ChannelsController.cs15
-rw-r--r--Jellyfin.Api/Controllers/CollectionController.cs6
-rw-r--r--Jellyfin.Api/Controllers/DisplayPreferencesController.cs4
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs12
-rw-r--r--Jellyfin.Api/Controllers/FilterController.cs6
-rw-r--r--Jellyfin.Api/Controllers/GenresController.cs15
-rw-r--r--Jellyfin.Api/Controllers/ImageController.cs2
-rw-r--r--Jellyfin.Api/Controllers/InstantMixController.cs50
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs154
-rw-r--r--Jellyfin.Api/Controllers/LibraryController.cs25
-rw-r--r--Jellyfin.Api/Controllers/LibraryStructureController.cs5
-rw-r--r--Jellyfin.Api/Controllers/LiveTvController.cs38
-rw-r--r--Jellyfin.Api/Controllers/MediaSegmentsController.cs2
-rw-r--r--Jellyfin.Api/Controllers/MoviesController.cs8
-rw-r--r--Jellyfin.Api/Controllers/MusicGenresController.cs15
-rw-r--r--Jellyfin.Api/Controllers/PersonsController.cs12
-rw-r--r--Jellyfin.Api/Controllers/PlaylistsController.cs10
-rw-r--r--Jellyfin.Api/Controllers/PlaystateController.cs12
-rw-r--r--Jellyfin.Api/Controllers/SearchController.cs6
-rw-r--r--Jellyfin.Api/Controllers/SessionController.cs6
-rw-r--r--Jellyfin.Api/Controllers/StartupController.cs1
-rw-r--r--Jellyfin.Api/Controllers/StudiosController.cs10
-rw-r--r--Jellyfin.Api/Controllers/SubtitleController.cs2
-rw-r--r--Jellyfin.Api/Controllers/SuggestionsController.cs11
-rw-r--r--Jellyfin.Api/Controllers/SystemController.cs16
-rw-r--r--Jellyfin.Api/Controllers/TrailersController.cs61
-rw-r--r--Jellyfin.Api/Controllers/TvShowsController.cs21
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs4
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs3
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs48
-rw-r--r--Jellyfin.Api/Controllers/UserViewsController.cs4
-rw-r--r--Jellyfin.Api/Controllers/VideosController.cs2
-rw-r--r--Jellyfin.Api/Controllers/YearsController.cs24
-rw-r--r--Jellyfin.Api/Formatters/CssOutputFormatter.cs24
-rw-r--r--Jellyfin.Api/Formatters/XmlOutputFormatter.cs15
-rw-r--r--Jellyfin.Api/Helpers/DynamicHlsHelper.cs14
-rw-r--r--Jellyfin.Api/Helpers/MediaInfoHelper.cs10
-rw-r--r--Jellyfin.Api/Helpers/RequestHelpers.cs3
-rw-r--r--Jellyfin.Api/Helpers/StreamingHelpers.cs9
-rw-r--r--Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs (renamed from Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs)12
-rw-r--r--Jellyfin.Api/ModelBinders/PipeDelimitedCollectionModelBinder.cs (renamed from Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs)14
-rw-r--r--Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs15
-rw-r--r--Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs2
-rw-r--r--Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs2
-rw-r--r--Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs2
-rw-r--r--Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs2
-rw-r--r--Jellyfin.Api/Models/StartupDtos/StartupRemoteAccessDto.cs2
-rw-r--r--Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs7
-rw-r--r--Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs7
56 files changed, 419 insertions, 425 deletions
diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
index 2853e69b0..f6f2f59c5 100644
--- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
+++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
@@ -3,7 +3,8 @@ using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
-using Jellyfin.Data.Enums;
+using Jellyfin.Data;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Authentication;
@@ -50,7 +51,8 @@ namespace Jellyfin.Api.Auth
}
var role = UserRoles.User;
- if (authorizationInfo.IsApiKey || authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator))
+ if (authorizationInfo.IsApiKey
+ || (authorizationInfo.User?.HasPermission(PermissionKind.IsAdministrator) ?? false))
{
role = UserRoles.Administrator;
}
@@ -60,10 +62,10 @@ namespace Jellyfin.Api.Auth
new Claim(ClaimTypes.Name, authorizationInfo.User?.Username ?? string.Empty),
new Claim(ClaimTypes.Role, role),
new Claim(InternalClaimTypes.UserId, authorizationInfo.UserId.ToString("N", CultureInfo.InvariantCulture)),
- new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId),
- new Claim(InternalClaimTypes.Device, authorizationInfo.Device),
- new Claim(InternalClaimTypes.Client, authorizationInfo.Client),
- new Claim(InternalClaimTypes.Version, authorizationInfo.Version),
+ new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId ?? string.Empty),
+ new Claim(InternalClaimTypes.Device, authorizationInfo.Device ?? string.Empty),
+ new Claim(InternalClaimTypes.Client, authorizationInfo.Client ?? string.Empty),
+ new Claim(InternalClaimTypes.Version, authorizationInfo.Version ?? string.Empty),
new Claim(InternalClaimTypes.Token, authorizationInfo.Token),
new Claim(InternalClaimTypes.IsApiKey, authorizationInfo.IsApiKey.ToString(CultureInfo.InvariantCulture))
};
diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs
index 4928d5ed2..6b80d537f 100644
--- a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs
+++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs
@@ -1,7 +1,8 @@
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Enums;
+using Jellyfin.Data;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
diff --git a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs
index 5fcf72fb4..7efb5b169 100644
--- a/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs
+++ b/Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.SyncPlay;
diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs
index f20779f6c..d139eab16 100644
--- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs
+++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionHandler.cs
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
+using Jellyfin.Data;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Library;
diff --git a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs
index a7c3cce97..152c400cd 100644
--- a/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs
+++ b/Jellyfin.Api/Auth/UserPermissionPolicy/UserPermissionRequirement.cs
@@ -1,5 +1,5 @@
using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
-using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
namespace Jellyfin.Api.Auth.UserPermissionPolicy
{
diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs
index 8b931f162..7ba75dc24 100644
--- a/Jellyfin.Api/Controllers/ArtistsController.cs
+++ b/Jellyfin.Api/Controllers/ArtistsController.cs
@@ -4,8 +4,9 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -91,31 +92,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 +296,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/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index a47c60473..272b4034e 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -238,7 +238,7 @@ public class AudioController : BaseJellyfinApiController
/// <param name="maxVideoBitDepth">Optional. The maximum video bit depth.</param>
/// <param name="requireAvc">Optional. Whether to require avc.</param>
/// <param name="deInterlace">Optional. Whether to deinterlace the video.</param>
- /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamporphic stream.</param>
+ /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamorphic stream.</param>
/// <param name="transcodingMaxAudioChannels">Optional. The maximum number of audio channels to transcode.</param>
/// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param>
/// <param name="liveStreamId">The live stream id.</param>
diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs
index f83c71b57..880b3a82d 100644
--- a/Jellyfin.Api/Controllers/ChannelsController.cs
+++ b/Jellyfin.Api/Controllers/ChannelsController.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Dto;
@@ -121,10 +122,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 +198,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 2d9f1ed69..c37f37633 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<ActionResult<CollectionCreationResult>> 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<ActionResult> 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<ActionResult> 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/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index 6d94d96f3..13064882c 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -4,8 +4,8 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Jellyfin.Api.Helpers;
-using Jellyfin.Data.Entities;
-using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
using MediaBrowser.Model.Dto;
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index a641ec209..ca8ab0ef7 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -459,7 +459,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
- [FromQuery] bool enableAdaptiveBitrateStreaming = true,
+ [FromQuery] bool enableAdaptiveBitrateStreaming = false,
[FromQuery] bool enableTrickplay = true,
[FromQuery] bool enableAudioVbrEncoding = true,
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
@@ -634,7 +634,7 @@ public class DynamicHlsController : BaseJellyfinApiController
[FromQuery] int? videoStreamIndex,
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions,
- [FromQuery] bool enableAdaptiveBitrateStreaming = true,
+ [FromQuery] bool enableAdaptiveBitrateStreaming = false,
[FromQuery] bool enableAudioVbrEncoding = true)
{
var streamingRequest = new HlsAudioRequestDto
@@ -1778,7 +1778,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
else if (state.AudioStream?.CodecTag is not null && state.AudioStream.CodecTag.Equals("ac-4", StringComparison.Ordinal))
{
- // ac-4 audio tends to hava a super weird sample rate that will fail most encoders
+ // ac-4 audio tends to have a super weird sample rate that will fail most encoders
// force resample it to 48KHz
args += " -ar 48000";
}
@@ -2056,16 +2056,16 @@ public class DynamicHlsController : BaseJellyfinApiController
}
}
- private Task DeleteLastFile(string playlistPath, string segmentExtension, int retryCount)
+ private async Task DeleteLastFile(string playlistPath, string segmentExtension, int retryCount)
{
var file = GetLastTranscodingFile(playlistPath, segmentExtension, _fileSystem);
if (file is null)
{
- return Task.CompletedTask;
+ return;
}
- return DeleteFile(file.FullName, retryCount);
+ await DeleteFile(file.FullName, retryCount).ConfigureAwait(false);
}
private async Task DeleteFile(string path, int retryCount)
diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs
index 4abca3271..3f9aa93a6 100644
--- a/Jellyfin.Api/Controllers/FilterController.cs
+++ b/Jellyfin.Api/Controllers/FilterController.cs
@@ -50,8 +50,8 @@ public class FilterController : BaseJellyfinApiController
public ActionResult<QueryFiltersLegacy> 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<QueryFilters> 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 54d48aec2..dd60d01e0 100644
--- a/Jellyfin.Api/Controllers/GenresController.cs
+++ b/Jellyfin.Api/Controllers/GenresController.cs
@@ -4,8 +4,9 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -76,18 +77,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/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index b71199026..e7b7405ca 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -130,7 +130,7 @@ public class ImageController : BaseJellyfinApiController
await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
}
- user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension));
+ user.ProfileImage = new Database.Implementations.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + extension));
await _providerManager
.SaveImage(stream, mimeType, user.ProfileImage.Path)
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index dcbacf1d7..c4b976756 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
+using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -71,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()
@@ -115,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()
@@ -159,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()
@@ -201,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()
@@ -239,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()
@@ -283,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()
@@ -328,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,
@@ -366,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()
@@ -389,23 +391,19 @@ public class InstantMixController : BaseJellyfinApiController
return GetResult(items, user, limit, dtoOptions);
}
- private QueryResult<BaseItemDto> GetResult(List<BaseItem> items, User? user, int? limit, DtoOptions dtoOptions)
+ private QueryResult<BaseItemDto> GetResult(IReadOnlyList<BaseItem> items, User? user, int? limit, DtoOptions dtoOptions)
{
- var list = items;
+ var totalCount = items.Count;
- var totalCount = list.Count;
-
- if (limit.HasValue && limit < list.Count)
+ if (limit.HasValue && limit < items.Count)
{
- list = list.GetRange(0, limit.Value);
+ items = items.Take(limit.Value).ToArray();
}
- var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user);
-
var result = new QueryResult<BaseItemDto>(
0,
totalCount,
- returnList);
+ _dtoService.GetBaseItemDtos(items, dtoOptions, user));
return result;
}
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index 828bd5174..803c2f1f7 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -4,7 +4,9 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
+using Jellyfin.Data;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
@@ -171,8 +173,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 +192,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 +238,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 +640,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 +659,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 +705,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 +829,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 +931,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)
@@ -967,7 +969,7 @@ public class ItemsController : BaseJellyfinApiController
[HttpGet("UserItems/{itemId}/UserData")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<UserItemDataDto> GetItemUserData(
+ public ActionResult<UserItemDataDto?> GetItemUserData(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId)
{
@@ -1005,7 +1007,7 @@ public class ItemsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public ActionResult<UserItemDataDto> GetItemUserDataLegacy(
+ public ActionResult<UserItemDataDto?> GetItemUserDataLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId)
=> GetItemUserData(userId, itemId);
@@ -1022,7 +1024,7 @@ public class ItemsController : BaseJellyfinApiController
[HttpPost("UserItems/{itemId}/UserData")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult<UserItemDataDto> UpdateItemUserData(
+ public ActionResult<UserItemDataDto?> UpdateItemUserData(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId,
[FromBody, Required] UpdateUserItemDataDto userDataDto)
@@ -1064,7 +1066,7 @@ public class ItemsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public ActionResult<UserItemDataDto> UpdateItemUserDataLegacy(
+ public ActionResult<UserItemDataDto?> UpdateItemUserDataLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId,
[FromBody, Required] UpdateUserItemDataDto userDataDto)
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 1b23683fb..bde1758e9 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -11,8 +11,9 @@ using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LibraryDtos;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Extensions;
@@ -144,8 +145,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 +219,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 +291,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 +401,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 +723,10 @@ public class LibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> 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()
@@ -780,11 +781,9 @@ public class LibraryController : BaseJellyfinApiController
Genres = item.Genres,
Limit = limit,
IncludeItemTypes = includeItemTypes.ToArray(),
- SimilarTo = item,
DtoOptions = dtoOptions,
EnableTotalRecordCount = !isMovie ?? true,
EnableGroupByMetadataKey = isMovie ?? false,
- MinSimilarityScore = 2 // A remnant from album/artist scoring
};
// ExcludeArtistIds
@@ -793,7 +792,7 @@ public class LibraryController : BaseJellyfinApiController
query.ExcludeArtistIds = excludeArtistIds;
}
- List<BaseItem> itemsResult = _libraryManager.GetItemList(query);
+ var itemsResult = _libraryManager.GetItemList(query);
var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs
index 93c2393f3..2a885662b 100644
--- a/Jellyfin.Api/Controllers/LibraryStructureController.cs
+++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs
@@ -77,7 +77,7 @@ public class LibraryStructureController : BaseJellyfinApiController
public async Task<ActionResult> 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)
{
@@ -99,6 +99,7 @@ public class LibraryStructureController : BaseJellyfinApiController
/// <param name="name">The name of the folder.</param>
/// <param name="refreshLibrary">Whether to refresh the library.</param>
/// <response code="204">Folder removed.</response>
+ /// <response code="404">Folder not found.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent)]
@@ -106,7 +107,9 @@ public class LibraryStructureController : BaseJellyfinApiController
[FromQuery] string name,
[FromQuery] bool refreshLibrary = false)
{
+ // TODO: refactor! this relies on an FileNotFound exception to return NotFound when attempting to remove a library that does not exist.
await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false);
+
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index 421f23fa1..5461d12fa 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -15,6 +15,7 @@ using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LiveTvDtos;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration;
@@ -159,10 +160,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 +284,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 +372,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 +567,7 @@ public class LiveTvController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.LiveTvAccess)]
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetLiveTvPrograms(
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] Guid[] channelIds,
[FromQuery] Guid? userId,
[FromQuery] DateTime? minStartDate,
[FromQuery] bool? hasAired,
@@ -581,17 +582,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);
@@ -698,6 +699,7 @@ public class LiveTvController : BaseJellyfinApiController
/// Gets recommended live tv epgs.
/// </summary>
/// <param name="userId">Optional. filter by user id.</param>
+ /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
/// <param name="limit">Optional. The maximum number of records to return.</param>
/// <param name="isAiring">Optional. Filter by programs that are currently airing, or not.</param>
/// <param name="hasAired">Optional. Filter by programs that have completed airing, or not.</param>
@@ -720,6 +722,7 @@ public class LiveTvController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetRecommendedPrograms(
[FromQuery] Guid? userId,
+ [FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] bool? isAiring,
[FromQuery] bool? hasAired,
@@ -730,9 +733,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)
{
@@ -744,6 +747,7 @@ public class LiveTvController : BaseJellyfinApiController
var query = new InternalItemsQuery(user)
{
IsAiring = isAiring,
+ StartIndex = startIndex,
Limit = limit,
HasAired = hasAired,
IsSeries = isSeries,
diff --git a/Jellyfin.Api/Controllers/MediaSegmentsController.cs b/Jellyfin.Api/Controllers/MediaSegmentsController.cs
index 2d1d4e2c8..e30e2b54e 100644
--- a/Jellyfin.Api/Controllers/MediaSegmentsController.cs
+++ b/Jellyfin.Api/Controllers/MediaSegmentsController.cs
@@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs
index 471bcd096..363acf815 100644
--- a/Jellyfin.Api/Controllers/MoviesController.cs
+++ b/Jellyfin.Api/Controllers/MoviesController.cs
@@ -5,8 +5,9 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
@@ -65,7 +66,7 @@ public class MoviesController : BaseJellyfinApiController
public ActionResult<IEnumerable<RecommendationDto>> 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)
{
@@ -120,7 +121,7 @@ public class MoviesController : BaseJellyfinApiController
DtoOptions = dtoOptions
});
- var mostRecentMovies = recentlyPlayedMovies.GetRange(0, Math.Min(recentlyPlayedMovies.Count, 6));
+ var mostRecentMovies = recentlyPlayedMovies.Take(Math.Min(recentlyPlayedMovies.Count, 6)).ToList();
// Get recently played directors
var recentDirectors = GetDirectors(mostRecentMovies)
.ToList();
@@ -276,7 +277,6 @@ public class MoviesController : BaseJellyfinApiController
Limit = itemLimit,
IncludeItemTypes = itemTypes.ToArray(),
IsMovie = true,
- SimilarTo = item,
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
});
diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs
index 5411baa3e..1e45e53ca 100644
--- a/Jellyfin.Api/Controllers/MusicGenresController.cs
+++ b/Jellyfin.Api/Controllers/MusicGenresController.cs
@@ -4,8 +4,9 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -76,18 +77,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 6ca308601..4d12dc18f 100644
--- a/Jellyfin.Api/Controllers/PersonsController.cs
+++ b/Jellyfin.Api/Controllers/PersonsController.cs
@@ -4,7 +4,7 @@ using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -67,14 +67,14 @@ public class PersonsController : BaseJellyfinApiController
public ActionResult<QueryResult<BaseItemDto>> 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 1ab36ccc6..ec5fdab38 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<ActionResult<PlaylistCreationResult>> CreatePlaylist(
[FromQuery, ParameterObsolete] string? name,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder)), ParameterObsolete] IReadOnlyList<Guid> ids,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder)), ParameterObsolete] IReadOnlyList<Guid> 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<ActionResult> 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<ActionResult> 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/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs
index 88aa0178f..1577b4594 100644
--- a/Jellyfin.Api/Controllers/PlaystateController.cs
+++ b/Jellyfin.Api/Controllers/PlaystateController.cs
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -72,7 +72,7 @@ public class PlaystateController : BaseJellyfinApiController
[HttpPost("UserPlayedItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult<UserItemDataDto>> MarkPlayedItem(
+ public async Task<ActionResult<UserItemDataDto?>> MarkPlayedItem(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId,
[FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? datePlayed)
@@ -121,7 +121,7 @@ public class PlaystateController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public Task<ActionResult<UserItemDataDto>> MarkPlayedItemLegacy(
+ public Task<ActionResult<UserItemDataDto?>> MarkPlayedItemLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId,
[FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? datePlayed)
@@ -138,7 +138,7 @@ public class PlaystateController : BaseJellyfinApiController
[HttpDelete("UserPlayedItems/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public async Task<ActionResult<UserItemDataDto>> MarkUnplayedItem(
+ public async Task<ActionResult<UserItemDataDto?>> MarkUnplayedItem(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId)
{
@@ -185,7 +185,7 @@ public class PlaystateController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public Task<ActionResult<UserItemDataDto>> MarkUnplayedItemLegacy(
+ public Task<ActionResult<UserItemDataDto?>> MarkUnplayedItemLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId)
=> MarkUnplayedItem(userId, itemId);
@@ -502,7 +502,7 @@ public class PlaystateController : BaseJellyfinApiController
/// <param name="wasPlayed">if set to <c>true</c> [was played].</param>
/// <param name="datePlayed">The date played.</param>
/// <returns>Task.</returns>
- private UserItemDataDto UpdatePlayedStatus(User user, BaseItem item, bool wasPlayed, DateTime? datePlayed)
+ private UserItemDataDto? UpdatePlayedStatus(User user, BaseItem item, bool wasPlayed, DateTime? datePlayed)
{
if (wasPlayed)
{
diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs
index 8bae6fb9b..ecf2335ba 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 2f9e9f091..9886d03de 100644
--- a/Jellyfin.Api/Controllers/SessionController.cs
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -122,7 +122,7 @@ public class SessionController : BaseJellyfinApiController
public async Task<ActionResult> 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<ActionResult> 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/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs
index 41b0858d1..a6bc84311 100644
--- a/Jellyfin.Api/Controllers/StartupController.cs
+++ b/Jellyfin.Api/Controllers/StartupController.cs
@@ -93,7 +93,6 @@ public class StartupController : BaseJellyfinApiController
{
NetworkConfiguration settings = _config.GetNetworkConfiguration();
settings.EnableRemoteAccess = startupRemoteAccessDto.EnableRemoteAccess;
- settings.EnableUPnP = startupRemoteAccessDto.EnableAutomaticPortMapping;
_config.SaveConfiguration(NetworkConfigurationStore.StoreKey, settings);
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs
index 708fc7436..52cb87e72 100644
--- a/Jellyfin.Api/Controllers/StudiosController.cs
+++ b/Jellyfin.Api/Controllers/StudiosController.cs
@@ -3,8 +3,8 @@ using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -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/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs
index 9da1dce93..e5df873f5 100644
--- a/Jellyfin.Api/Controllers/SubtitleController.cs
+++ b/Jellyfin.Api/Controllers/SubtitleController.cs
@@ -395,7 +395,7 @@ public class SubtitleController : BaseJellyfinApiController
var url = string.Format(
CultureInfo.InvariantCulture,
- "stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}",
+ "stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&ApiKey={2}",
positionTicks.ToString(CultureInfo.InvariantCulture),
endPositionTicks.ToString(CultureInfo.InvariantCulture),
accessToken);
diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs
index ad625cc6e..52982c362 100644
--- a/Jellyfin.Api/Controllers/SuggestionsController.cs
+++ b/Jellyfin.Api/Controllers/SuggestionsController.cs
@@ -3,8 +3,9 @@ using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -59,8 +60,8 @@ public class SuggestionsController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> 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 +116,8 @@ public class SuggestionsController : BaseJellyfinApiController
[ApiExplorerSettings(IgnoreApi = true)]
public ActionResult<QueryResult<BaseItemDto>> 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/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs
index 6c5ce4715..0ee11c070 100644
--- a/Jellyfin.Api/Controllers/SystemController.cs
+++ b/Jellyfin.Api/Controllers/SystemController.cs
@@ -212,20 +212,4 @@ public class SystemController : BaseJellyfinApiController
FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
return File(stream, "text/plain; charset=utf-8");
}
-
- /// <summary>
- /// Gets wake on lan information.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <returns>An <see cref="IEnumerable{WakeOnLanInfo}"/> with the WakeOnLan infos.</returns>
- [HttpGet("WakeOnLanInfo")]
- [Authorize]
- [Obsolete("This endpoint is obsolete.")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<IEnumerable<WakeOnLanInfo>> GetWakeOnLanInfo()
- {
- var result = _networkManager.GetMacAddresses()
- .Select(i => new WakeOnLanInfo(i));
- return Ok(result);
- }
}
diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs
index d7d0cc454..3e4bac89a 100644
--- a/Jellyfin.Api/Controllers/TrailersController.cs
+++ b/Jellyfin.Api/Controllers/TrailersController.cs
@@ -1,6 +1,7 @@
using System;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -130,8 +131,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 +150,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 +195,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 914ccd7f9..0f08854d2 100644
--- a/Jellyfin.Api/Controllers/TvShowsController.cs
+++ b/Jellyfin.Api/Controllers/TvShowsController.cs
@@ -2,10 +2,12 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+using Jellyfin.Api.Attributes;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -77,16 +79,16 @@ 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,
- [FromQuery] bool disableFirstEpisode = false,
+ [FromQuery][ParameterObsolete] bool disableFirstEpisode = false,
[FromQuery] bool enableResumable = true,
[FromQuery] bool enableRewatching = false)
{
@@ -109,7 +111,6 @@ public class TvShowsController : BaseJellyfinApiController
StartIndex = startIndex,
User = user,
EnableTotalRecordCount = enableTotalRecordCount,
- DisableFirstEpisode = disableFirstEpisode,
NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue,
EnableResumable = enableResumable,
EnableRewatching = enableRewatching
@@ -143,11 +144,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 +209,7 @@ public class TvShowsController : BaseJellyfinApiController
public ActionResult<QueryResult<BaseItemDto>> 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 +219,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 +333,13 @@ public class TvShowsController : BaseJellyfinApiController
public ActionResult<QueryResult<BaseItemDto>> 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 41c4886d4..a5b5fde62 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<ActionResult> 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,
@@ -222,7 +222,7 @@ public class UniversalAudioController : BaseJellyfinApiController
TranscodeReasons = mediaSource.TranscodeReasons == 0 ? null : mediaSource.TranscodeReasons.ToString(),
Context = EncodingContext.Static,
StreamOptions = new Dictionary<string, string>(),
- EnableAdaptiveBitrateStreaming = true,
+ EnableAdaptiveBitrateStreaming = false,
EnableAudioVbrEncoding = enableAudioVbrEncoding
};
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index d7886d247..d0ced277a 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -7,7 +7,8 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.UserDtos;
-using Jellyfin.Data.Enums;
+using Jellyfin.Data;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Extensions;
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index e7bf71727..0e04beb14 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -7,8 +7,8 @@ using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -305,7 +305,7 @@ public class UserLibraryController : BaseJellyfinApiController
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpDelete("UserItems/{itemId}/Rating")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> DeleteUserItemRating(
+ public ActionResult<UserItemDataDto?> DeleteUserItemRating(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId)
{
@@ -338,7 +338,7 @@ public class UserLibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public ActionResult<UserItemDataDto> DeleteUserItemRatingLegacy(
+ public ActionResult<UserItemDataDto?> DeleteUserItemRatingLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId)
=> DeleteUserItemRating(userId, itemId);
@@ -353,7 +353,7 @@ public class UserLibraryController : BaseJellyfinApiController
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpPost("UserItems/{itemId}/Rating")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<UserItemDataDto> UpdateUserItemRating(
+ public ActionResult<UserItemDataDto?> UpdateUserItemRating(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId,
[FromQuery] bool? likes)
@@ -388,7 +388,7 @@ public class UserLibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public ActionResult<UserItemDataDto> UpdateUserItemRatingLegacy(
+ public ActionResult<UserItemDataDto?> UpdateUserItemRatingLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId,
[FromQuery] bool? likes)
@@ -523,12 +523,12 @@ public class UserLibraryController : BaseJellyfinApiController
public ActionResult<IEnumerable<BaseItemDto>> 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<IEnumerable<BaseItemDto>> 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)
@@ -634,10 +634,10 @@ public class UserLibraryController : BaseJellyfinApiController
{
if (item is Person)
{
- var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary);
- var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3;
+ var hasMetadata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary);
+ var performFullRefresh = !hasMetadata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3;
- if (!hasMetdata)
+ if (!hasMetadata)
{
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
@@ -662,12 +662,15 @@ public class UserLibraryController : BaseJellyfinApiController
// Get the user data for this item
var data = _userDataRepository.GetUserData(user, item);
- // Set favorite status
- data.IsFavorite = isFavorite;
+ if (data is not null)
+ {
+ // Set favorite status
+ data.IsFavorite = isFavorite;
- _userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ _userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ }
- return _userDataRepository.GetUserDataDto(item, user);
+ return _userDataRepository.GetUserDataDto(item, user)!;
}
/// <summary>
@@ -676,14 +679,17 @@ public class UserLibraryController : BaseJellyfinApiController
/// <param name="user">The user.</param>
/// <param name="item">The item.</param>
/// <param name="likes">if set to <c>true</c> [likes].</param>
- private UserItemDataDto UpdateUserItemRatingInternal(User user, BaseItem item, bool? likes)
+ private UserItemDataDto? UpdateUserItemRatingInternal(User user, BaseItem item, bool? likes)
{
// Get the user data for this item
var data = _userDataRepository.GetUserData(user, item);
- data.Likes = likes;
+ if (data is not null)
+ {
+ data.Likes = likes;
- _userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ _userDataRepository.SaveUserData(user, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
+ }
return _userDataRepository.GetUserDataDto(item, user);
}
diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs
index e24f78a88..64b2dffb3 100644
--- a/Jellyfin.Api/Controllers/UserViewsController.cs
+++ b/Jellyfin.Api/Controllers/UserViewsController.cs
@@ -66,7 +66,7 @@ public class UserViewsController : BaseJellyfinApiController
public QueryResult<BaseItemDto> 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<BaseItemDto> 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 8348fd937..6f18c1603 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<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
+ public async Task<ActionResult> 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 e4aa0ea42..ebf98da45 100644
--- a/Jellyfin.Api/Controllers/YearsController.cs
+++ b/Jellyfin.Api/Controllers/YearsController.cs
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -71,16 +73,16 @@ public class YearsController : BaseJellyfinApiController
public ActionResult<QueryResult<BaseItemDto>> 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)
@@ -105,18 +107,18 @@ public class YearsController : BaseJellyfinApiController
bool Filter(BaseItem i) => FilterItem(i, excludeItemTypes, includeItemTypes, mediaTypes);
- IList<BaseItem> items;
+ IReadOnlyList<BaseItem> items;
if (parentItem.IsFolder)
{
var folder = (Folder)parentItem;
if (userId.IsNullOrEmpty())
{
- items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToList();
+ items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToArray();
}
else
{
- items = recursive ? folder.GetRecursiveChildren(user, query).ToList() : folder.GetChildren(user, true).Where(Filter).ToList();
+ items = recursive ? folder.GetRecursiveChildren(user, query) : folder.GetChildren(user, true).Where(Filter).ToArray();
}
}
else
diff --git a/Jellyfin.Api/Formatters/CssOutputFormatter.cs b/Jellyfin.Api/Formatters/CssOutputFormatter.cs
index 495f771e1..9ad1c863e 100644
--- a/Jellyfin.Api/Formatters/CssOutputFormatter.cs
+++ b/Jellyfin.Api/Formatters/CssOutputFormatter.cs
@@ -1,6 +1,4 @@
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
+using System.Net.Mime;
using Microsoft.AspNetCore.Mvc.Formatters;
namespace Jellyfin.Api.Formatters;
@@ -8,28 +6,14 @@ namespace Jellyfin.Api.Formatters;
/// <summary>
/// Css output formatter.
/// </summary>
-public class CssOutputFormatter : TextOutputFormatter
+public sealed class CssOutputFormatter : StringOutputFormatter
{
/// <summary>
/// Initializes a new instance of the <see cref="CssOutputFormatter"/> class.
/// </summary>
public CssOutputFormatter()
{
- SupportedMediaTypes.Add("text/css");
-
- SupportedEncodings.Add(Encoding.UTF8);
- SupportedEncodings.Add(Encoding.Unicode);
- }
-
- /// <summary>
- /// Write context object to stream.
- /// </summary>
- /// <param name="context">Writer context.</param>
- /// <param name="selectedEncoding">Unused. Writer encoding.</param>
- /// <returns>Write stream task.</returns>
- public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
- {
- var stringResponse = context.Object?.ToString();
- return stringResponse is null ? Task.CompletedTask : context.HttpContext.Response.WriteAsync(stringResponse);
+ SupportedMediaTypes.Clear();
+ SupportedMediaTypes.Add(MediaTypeNames.Text.Css);
}
}
diff --git a/Jellyfin.Api/Formatters/XmlOutputFormatter.cs b/Jellyfin.Api/Formatters/XmlOutputFormatter.cs
index 1c9feedcb..8dbb91d0a 100644
--- a/Jellyfin.Api/Formatters/XmlOutputFormatter.cs
+++ b/Jellyfin.Api/Formatters/XmlOutputFormatter.cs
@@ -1,7 +1,4 @@
using System.Net.Mime;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
namespace Jellyfin.Api.Formatters;
@@ -9,7 +6,7 @@ namespace Jellyfin.Api.Formatters;
/// <summary>
/// Xml output formatter.
/// </summary>
-public class XmlOutputFormatter : TextOutputFormatter
+public sealed class XmlOutputFormatter : StringOutputFormatter
{
/// <summary>
/// Initializes a new instance of the <see cref="XmlOutputFormatter"/> class.
@@ -18,15 +15,5 @@ public class XmlOutputFormatter : TextOutputFormatter
{
SupportedMediaTypes.Clear();
SupportedMediaTypes.Add(MediaTypeNames.Text.Xml);
-
- SupportedEncodings.Add(Encoding.UTF8);
- SupportedEncodings.Add(Encoding.Unicode);
- }
-
- /// <inheritdoc />
- public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
- {
- var stringResponse = context.Object?.ToString();
- return stringResponse is null ? Task.CompletedTask : context.HttpContext.Response.WriteAsync(stringResponse);
}
}
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index 0e620e72a..ebd0288ca 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -8,8 +8,8 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
@@ -267,7 +267,7 @@ public class DynamicHlsHelper
if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.GetNormalizedRemoteIP()))
{
- var requestedVideoBitrate = state.VideoRequest is null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
+ var requestedVideoBitrate = state.VideoRequest?.VideoBitRate ?? 0;
// By default, vary by just 200k
var variation = GetBitrateVariation(totalBitrate);
@@ -526,9 +526,7 @@ public class DynamicHlsHelper
return false;
}
- // Having problems in android
- return false;
- // return state.VideoRequest.VideoBitRate.HasValue;
+ return state.VideoRequest?.VideoBitRate.HasValue ?? false;
}
private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder, ClaimsPrincipal user)
@@ -550,7 +548,7 @@ public class DynamicHlsHelper
var url = string.Format(
CultureInfo.InvariantCulture,
- "{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&api_key={3}",
+ "{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&ApiKey={3}",
state.Request.MediaSourceId,
stream.Index.ToString(CultureInfo.InvariantCulture),
30.ToString(CultureInfo.InvariantCulture),
@@ -587,7 +585,7 @@ public class DynamicHlsHelper
var url = string.Format(
CultureInfo.InvariantCulture,
- "Trickplay/{0}/tiles.m3u8?MediaSourceId={1}&api_key={2}",
+ "Trickplay/{0}/tiles.m3u8?MediaSourceId={1}&ApiKey={2}",
width.ToString(CultureInfo.InvariantCulture),
state.Request.MediaSourceId,
user.GetToken());
@@ -616,7 +614,7 @@ public class DynamicHlsHelper
&& state.VideoStream is not null
&& state.VideoStream.Level.HasValue)
{
- levelString = state.VideoStream.Level.Value.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
+ levelString = state.VideoStream.Level.Value.ToString(CultureInfo.InvariantCulture);
}
else
{
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index 4adda0b69..63c9c173b 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -7,8 +7,10 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Entities;
+using Jellyfin.Data;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
@@ -288,9 +290,7 @@ public class MediaInfoHelper
mediaSource.SupportsDirectPlay = false;
mediaSource.SupportsDirectStream = false;
- mediaSource.TranscodingUrl = streamInfo.ToUrl("-", claimsPrincipal.GetToken()).TrimStart('-');
- mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false";
- mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
+ mediaSource.TranscodingUrl = streamInfo.ToUrl(null, claimsPrincipal.GetToken(), "&allowVideoStreamCopy=false&allowAudioStreamCopy=false");
mediaSource.TranscodingContainer = streamInfo.Container;
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
if (streamInfo.AlwaysBurnInSubtitleWhenTranscoding)
@@ -303,7 +303,7 @@ public class MediaInfoHelper
if (!mediaSource.SupportsDirectPlay && (mediaSource.SupportsTranscoding || mediaSource.SupportsDirectStream))
{
streamInfo.PlayMethod = PlayMethod.Transcode;
- mediaSource.TranscodingUrl = streamInfo.ToUrl("-", claimsPrincipal.GetToken()).TrimStart('-');
+ mediaSource.TranscodingUrl = streamInfo.ToUrl(null, claimsPrincipal.GetToken(), null);
if (!allowVideoStreamCopy)
{
diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs
index eb83a37ba..e10e940f2 100644
--- a/Jellyfin.Api/Helpers/RequestHelpers.cs
+++ b/Jellyfin.Api/Helpers/RequestHelpers.cs
@@ -5,8 +5,9 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
-using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index 3a5db2f3f..2601fa3be 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -132,7 +132,7 @@ public static class StreamingHelpers
mediaSource = string.IsNullOrEmpty(streamingRequest.MediaSourceId)
? mediaSources[0]
- : mediaSources.Find(i => string.Equals(i.Id, streamingRequest.MediaSourceId, StringComparison.Ordinal));
+ : mediaSources.FirstOrDefault(i => string.Equals(i.Id, streamingRequest.MediaSourceId, StringComparison.Ordinal));
if (mediaSource is null && Guid.Parse(streamingRequest.MediaSourceId).Equals(streamingRequest.Id))
{
@@ -210,7 +210,7 @@ public static class StreamingHelpers
&& state.VideoRequest.VideoBitRate.Value >= state.VideoStream.BitRate.Value)
{
// Don't downscale the resolution if the width/height/MaxWidth/MaxHeight is not requested,
- // and the requested video bitrate is higher than source video bitrate.
+ // and the requested video bitrate is greater than source video bitrate.
if (state.VideoStream.Width.HasValue || state.VideoStream.Height.HasValue)
{
state.VideoRequest.MaxWidth = state.VideoStream?.Width;
@@ -235,6 +235,11 @@ public static class StreamingHelpers
state.VideoRequest.MaxHeight = resolution.MaxHeight;
}
}
+
+ if (state.AudioStream is not null && !EncodingHelper.IsCopyCodec(state.OutputAudioCodec) && string.Equals(state.AudioStream.Codec, state.OutputAudioCodec, StringComparison.OrdinalIgnoreCase) && state.OutputAudioBitrate.HasValue)
+ {
+ state.OutputAudioCodec = state.SupportedAudioCodecs.Where(c => !EncodingHelper.LosslessAudioCodecs.Contains(c)).FirstOrDefault(mediaEncoder.CanEncodeToAudioCodec);
+ }
}
var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
diff --git a/Jellyfin.Api/ModelBinders/CommaDelimitedArrayModelBinder.cs b/Jellyfin.Api/ModelBinders/CommaDelimitedCollectionModelBinder.cs
index 3e3604b2a..25b84cbcc 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;
/// <summary>
-/// Comma delimited array model binder.
+/// Comma delimited collection model binder.
/// Returns an empty array of specified type if there is no query parameter.
/// </summary>
-public class CommaDelimitedArrayModelBinder : IModelBinder
+public class CommaDelimitedCollectionModelBinder : IModelBinder
{
- private readonly ILogger<CommaDelimitedArrayModelBinder> _logger;
+ private readonly ILogger<CommaDelimitedCollectionModelBinder> _logger;
/// <summary>
- /// Initializes a new instance of the <see cref="CommaDelimitedArrayModelBinder"/> class.
+ /// Initializes a new instance of the <see cref="CommaDelimitedCollectionModelBinder"/> class.
/// </summary>
- /// <param name="logger">Instance of the <see cref="ILogger{CommaDelimitedArrayModelBinder}"/> interface.</param>
- public CommaDelimitedArrayModelBinder(ILogger<CommaDelimitedArrayModelBinder> logger)
+ /// <param name="logger">Instance of the <see cref="ILogger{CommaDelimitedCollectionModelBinder}"/> interface.</param>
+ public CommaDelimitedCollectionModelBinder(ILogger<CommaDelimitedCollectionModelBinder> logger)
{
_logger = logger;
}
diff --git a/Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs b/Jellyfin.Api/ModelBinders/PipeDelimitedCollectionModelBinder.cs
index ae9f0a8cd..7d0fb2e19 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;
/// <summary>
-/// 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.
/// </summary>
-public class PipeDelimitedArrayModelBinder : IModelBinder
+public class PipeDelimitedCollectionModelBinder : IModelBinder
{
- private readonly ILogger<PipeDelimitedArrayModelBinder> _logger;
+ private readonly ILogger<PipeDelimitedCollectionModelBinder> _logger;
/// <summary>
- /// Initializes a new instance of the <see cref="PipeDelimitedArrayModelBinder"/> class.
+ /// Initializes a new instance of the <see cref="PipeDelimitedCollectionModelBinder"/> class.
/// </summary>
- /// <param name="logger">Instance of the <see cref="ILogger{PipeDelimitedArrayModelBinder}"/> interface.</param>
- public PipeDelimitedArrayModelBinder(ILogger<PipeDelimitedArrayModelBinder> logger)
+ /// <param name="logger">Instance of the <see cref="ILogger{PipeDelimitedCollectionModelBinder}"/> interface.</param>
+ public PipeDelimitedCollectionModelBinder(ILogger<PipeDelimitedCollectionModelBinder> logger)
{
_logger = logger;
}
diff --git a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
index 190d90681..2616694d8 100644
--- a/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
+++ b/Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions.Json.Converters;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -17,7 +18,7 @@ public class GetProgramsDto
/// <summary>
/// Gets or sets the channels to return guide information for.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<Guid>? ChannelIds { get; set; }
/// <summary>
@@ -93,25 +94,25 @@ public class GetProgramsDto
/// <summary>
/// Gets or sets specify one or more sort orders, comma delimited. Options: Name, StartDate.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<ItemSortBy>? SortBy { get; set; }
/// <summary>
/// Gets or sets sort order.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<SortOrder>? SortOrder { get; set; }
/// <summary>
/// Gets or sets the genres to return guide information for.
/// </summary>
- [JsonConverter(typeof(JsonPipeDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonPipeDelimitedCollectionConverterFactory))]
public IReadOnlyList<string>? Genres { get; set; }
/// <summary>
/// Gets or sets the genre ids to return guide information for.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<Guid>? GenreIds { get; set; }
/// <summary>
@@ -133,7 +134,7 @@ public class GetProgramsDto
/// <summary>
/// Gets or sets the image types to include in the output.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<ImageType>? EnableImageTypes { get; set; }
/// <summary>
@@ -154,6 +155,6 @@ public class GetProgramsDto
/// <summary>
/// Gets or sets specify additional fields of information to return in the output.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<ItemFields>? Fields { get; set; }
}
diff --git a/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs b/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
index 978e99b35..758c89938 100644
--- a/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
+++ b/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
@@ -61,7 +61,7 @@ public class OpenLiveStreamDto
public bool? EnableDirectPlay { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether to enale direct stream.
+ /// Gets or sets a value indicating whether to enable direct stream.
/// </summary>
public bool? EnableDirectStream { get; set; }
diff --git a/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs b/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
index 82f603ca1..73ab76817 100644
--- a/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
+++ b/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Model.Dlna;
namespace Jellyfin.Api.Models.MediaInfoDtos;
/// <summary>
-/// Plabyback info dto.
+/// Playback info dto.
/// </summary>
public class PlaybackInfoDto
{
diff --git a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
index 61a3f2ed6..891d758c4 100644
--- a/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
+++ b/Jellyfin.Api/Models/PlaylistDtos/CreatePlaylistDto.cs
@@ -20,7 +20,7 @@ public class CreatePlaylistDto
/// <summary>
/// Gets or sets item ids to add to the playlist.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<Guid> Ids { get; set; } = [];
/// <summary>
diff --git a/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs b/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs
index 80e20995c..339a0d5d2 100644
--- a/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs
+++ b/Jellyfin.Api/Models/PlaylistDtos/UpdatePlaylistDto.cs
@@ -19,7 +19,7 @@ public class UpdatePlaylistDto
/// <summary>
/// Gets or sets item ids of the playlist.
/// </summary>
- [JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
+ [JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
public IReadOnlyList<Guid>? Ids { get; set; }
/// <summary>
diff --git a/Jellyfin.Api/Models/StartupDtos/StartupRemoteAccessDto.cs b/Jellyfin.Api/Models/StartupDtos/StartupRemoteAccessDto.cs
index 1ae2cad4b..9c29e372c 100644
--- a/Jellyfin.Api/Models/StartupDtos/StartupRemoteAccessDto.cs
+++ b/Jellyfin.Api/Models/StartupDtos/StartupRemoteAccessDto.cs
@@ -1,3 +1,4 @@
+using System;
using System.ComponentModel.DataAnnotations;
namespace Jellyfin.Api.Models.StartupDtos;
@@ -17,5 +18,6 @@ public class StartupRemoteAccessDto
/// Gets or sets a value indicating whether enable automatic port mapping.
/// </summary>
[Required]
+ [Obsolete("No longer supported")]
public bool EnableAutomaticPortMapping { get; set; }
}
diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
index 99516e938..60379f415 100644
--- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs
@@ -1,7 +1,8 @@
using System;
using System.Threading.Tasks;
-using Jellyfin.Data.Enums;
+using Jellyfin.Data;
using Jellyfin.Data.Events;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Activity;
@@ -70,7 +71,9 @@ public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener<Activi
/// <param name="message">The message.</param>
protected override void Start(WebSocketMessageInfo message)
{
- if (!message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator))
+ if (!message.Connection.AuthorizationInfo.IsApiKey
+ && (message.Connection.AuthorizationInfo.User is null
+ || !message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)))
{
throw new AuthenticationException("Only admin users can retrieve the activity log.");
}
diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
index a6cfe4d56..9d149cc85 100644
--- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
+++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
-using Jellyfin.Data.Enums;
+using Jellyfin.Data;
+using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@@ -79,7 +80,9 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume
/// <param name="message">The message.</param>
protected override void Start(WebSocketMessageInfo message)
{
- if (!message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator))
+ if (!message.Connection.AuthorizationInfo.IsApiKey
+ && (message.Connection.AuthorizationInfo.User is null
+ || !message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)))
{
throw new AuthenticationException("Only admin users can subscribe to session information.");
}