diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs
index fbe68b6b97..a6c89bab88 100644
--- a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs
@@ -2,29 +2,28 @@
using System;
-namespace Jellyfin.Api.Attributes
+namespace Jellyfin.Api.Attributes;
+
+///
+/// Internal produces image attribute.
+///
+[AttributeUsage(AttributeTargets.Method)]
+public class AcceptsFileAttribute : Attribute
{
+ private readonly string[] _contentTypes;
+
///
- /// Internal produces image attribute.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Method)]
- public class AcceptsFileAttribute : Attribute
+ /// Content types this endpoint produces.
+ public AcceptsFileAttribute(params string[] contentTypes)
{
- private readonly string[] _contentTypes;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Content types this endpoint produces.
- public AcceptsFileAttribute(params string[] contentTypes)
- {
- _contentTypes = contentTypes;
- }
-
- ///
- /// Gets the configured content types.
- ///
- /// the configured content types.
- public string[] ContentTypes => _contentTypes;
+ _contentTypes = contentTypes;
}
+
+ ///
+ /// Gets the configured content types.
+ ///
+ /// the configured content types.
+ public string[] ContentTypes => _contentTypes;
}
diff --git a/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs
index 244a29da45..57433202e1 100644
--- a/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs
@@ -1,18 +1,17 @@
-namespace Jellyfin.Api.Attributes
-{
- ///
- /// Produces file attribute of "image/*".
- ///
- public sealed class AcceptsImageFileAttribute : AcceptsFileAttribute
- {
- private const string ContentType = "image/*";
+namespace Jellyfin.Api.Attributes;
- ///
- /// Initializes a new instance of the class.
- ///
- public AcceptsImageFileAttribute()
- : base(ContentType)
- {
- }
+///
+/// Produces file attribute of "image/*".
+///
+public sealed class AcceptsImageFileAttribute : AcceptsFileAttribute
+{
+ private const string ContentType = "image/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AcceptsImageFileAttribute()
+ : base(ContentType)
+ {
}
}
diff --git a/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs b/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs
index 4dcf5976a2..cbd32ed822 100644
--- a/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs
+++ b/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs
@@ -2,29 +2,28 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Routing;
-namespace Jellyfin.Api.Attributes
+namespace Jellyfin.Api.Attributes;
+
+///
+/// Identifies an action that supports the HTTP GET method.
+///
+public sealed class HttpSubscribeAttribute : HttpMethodAttribute
{
+ private static readonly IEnumerable _supportedMethods = new[] { "SUBSCRIBE" };
+
///
- /// Identifies an action that supports the HTTP GET method.
+ /// Initializes a new instance of the class.
///
- public sealed class HttpSubscribeAttribute : HttpMethodAttribute
+ public HttpSubscribeAttribute()
+ : base(_supportedMethods)
{
- private static readonly IEnumerable _supportedMethods = new[] { "SUBSCRIBE" };
-
- ///
- /// Initializes a new instance of the class.
- ///
- public HttpSubscribeAttribute()
- : base(_supportedMethods)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The route template. May not be null.
- public HttpSubscribeAttribute(string template)
- : base(_supportedMethods, template)
- => ArgumentNullException.ThrowIfNull(template);
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The route template. May not be null.
+ public HttpSubscribeAttribute(string template)
+ : base(_supportedMethods, template)
+ => ArgumentNullException.ThrowIfNull(template);
}
diff --git a/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs b/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs
index d0238424a7..f4a6dcdaf9 100644
--- a/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs
+++ b/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs
@@ -2,29 +2,28 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Routing;
-namespace Jellyfin.Api.Attributes
+namespace Jellyfin.Api.Attributes;
+
+///
+/// Identifies an action that supports the HTTP GET method.
+///
+public sealed class HttpUnsubscribeAttribute : HttpMethodAttribute
{
+ private static readonly IEnumerable _supportedMethods = new[] { "UNSUBSCRIBE" };
+
///
- /// Identifies an action that supports the HTTP GET method.
+ /// Initializes a new instance of the class.
///
- public sealed class HttpUnsubscribeAttribute : HttpMethodAttribute
+ public HttpUnsubscribeAttribute()
+ : base(_supportedMethods)
{
- private static readonly IEnumerable _supportedMethods = new[] { "UNSUBSCRIBE" };
-
- ///
- /// Initializes a new instance of the class.
- ///
- public HttpUnsubscribeAttribute()
- : base(_supportedMethods)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The route template. May not be null.
- public HttpUnsubscribeAttribute(string template)
- : base(_supportedMethods, template)
- => ArgumentNullException.ThrowIfNull(template);
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The route template. May not be null.
+ public HttpUnsubscribeAttribute(string template)
+ : base(_supportedMethods, template)
+ => ArgumentNullException.ThrowIfNull(template);
}
diff --git a/Jellyfin.Api/Attributes/ParameterObsoleteAttribute.cs b/Jellyfin.Api/Attributes/ParameterObsoleteAttribute.cs
index 514e7ce974..bf64fef5d7 100644
--- a/Jellyfin.Api/Attributes/ParameterObsoleteAttribute.cs
+++ b/Jellyfin.Api/Attributes/ParameterObsoleteAttribute.cs
@@ -1,12 +1,11 @@
using System;
-namespace Jellyfin.Api.Attributes
+namespace Jellyfin.Api.Attributes;
+
+///
+/// Attribute to mark a parameter as obsolete.
+///
+[AttributeUsage(AttributeTargets.Parameter)]
+public sealed class ParameterObsoleteAttribute : Attribute
{
- ///
- /// Attribute to mark a parameter as obsolete.
- ///
- [AttributeUsage(AttributeTargets.Parameter)]
- public sealed class ParameterObsoleteAttribute : Attribute
- {
- }
}
diff --git a/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs
index 9fc25f192e..7ce09c299d 100644
--- a/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs
@@ -1,18 +1,17 @@
-namespace Jellyfin.Api.Attributes
-{
- ///
- /// Produces file attribute of "image/*".
- ///
- public sealed class ProducesAudioFileAttribute : ProducesFileAttribute
- {
- private const string ContentType = "audio/*";
+namespace Jellyfin.Api.Attributes;
- ///
- /// Initializes a new instance of the class.
- ///
- public ProducesAudioFileAttribute()
- : base(ContentType)
- {
- }
+///
+/// Produces file attribute of "image/*".
+///
+public sealed class ProducesAudioFileAttribute : ProducesFileAttribute
+{
+ private const string ContentType = "audio/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesAudioFileAttribute()
+ : base(ContentType)
+ {
}
}
diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs
index d8e4141acb..c728f68e07 100644
--- a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs
@@ -2,29 +2,28 @@
using System;
-namespace Jellyfin.Api.Attributes
+namespace Jellyfin.Api.Attributes;
+
+///
+/// Internal produces image attribute.
+///
+[AttributeUsage(AttributeTargets.Method)]
+public class ProducesFileAttribute : Attribute
{
+ private readonly string[] _contentTypes;
+
///
- /// Internal produces image attribute.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Method)]
- public class ProducesFileAttribute : Attribute
+ /// Content types this endpoint produces.
+ public ProducesFileAttribute(params string[] contentTypes)
{
- private readonly string[] _contentTypes;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Content types this endpoint produces.
- public ProducesFileAttribute(params string[] contentTypes)
- {
- _contentTypes = contentTypes;
- }
-
- ///
- /// Gets the configured content types.
- ///
- /// the configured content types.
- public string[] ContentTypes => _contentTypes;
+ _contentTypes = contentTypes;
}
+
+ ///
+ /// Gets the configured content types.
+ ///
+ /// the configured content types.
+ public string[] ContentTypes => _contentTypes;
}
diff --git a/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs
index 1e5b542e27..f145a061ee 100644
--- a/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs
@@ -1,18 +1,17 @@
-namespace Jellyfin.Api.Attributes
-{
- ///
- /// Produces file attribute of "image/*".
- ///
- public sealed class ProducesImageFileAttribute : ProducesFileAttribute
- {
- private const string ContentType = "image/*";
+namespace Jellyfin.Api.Attributes;
- ///
- /// Initializes a new instance of the class.
- ///
- public ProducesImageFileAttribute()
- : base(ContentType)
- {
- }
+///
+/// Produces file attribute of "image/*".
+///
+public sealed class ProducesImageFileAttribute : ProducesFileAttribute
+{
+ private const string ContentType = "image/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesImageFileAttribute()
+ : base(ContentType)
+ {
}
}
diff --git a/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs
index 5b15cb1a56..c03ed740c0 100644
--- a/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs
@@ -1,18 +1,17 @@
-namespace Jellyfin.Api.Attributes
-{
- ///
- /// Produces file attribute of "image/*".
- ///
- public sealed class ProducesPlaylistFileAttribute : ProducesFileAttribute
- {
- private const string ContentType = "application/x-mpegURL";
+namespace Jellyfin.Api.Attributes;
- ///
- /// Initializes a new instance of the class.
- ///
- public ProducesPlaylistFileAttribute()
- : base(ContentType)
- {
- }
+///
+/// Produces file attribute of "image/*".
+///
+public sealed class ProducesPlaylistFileAttribute : ProducesFileAttribute
+{
+ private const string ContentType = "application/x-mpegURL";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesPlaylistFileAttribute()
+ : base(ContentType)
+ {
}
}
diff --git a/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs
index 6857d45ecc..10dec0c00e 100644
--- a/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs
+++ b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs
@@ -1,18 +1,17 @@
-namespace Jellyfin.Api.Attributes
-{
- ///
- /// Produces file attribute of "video/*".
- ///
- public sealed class ProducesVideoFileAttribute : ProducesFileAttribute
- {
- private const string ContentType = "video/*";
+namespace Jellyfin.Api.Attributes;
- ///
- /// Initializes a new instance of the class.
- ///
- public ProducesVideoFileAttribute()
- : base(ContentType)
- {
- }
+///
+/// Produces file attribute of "video/*".
+///
+public sealed class ProducesVideoFileAttribute : ProducesFileAttribute
+{
+ private const string ContentType = "video/*";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProducesVideoFileAttribute()
+ : base(ContentType)
+ {
}
}
diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs
index e327831fe7..5b4bd0adb0 100644
--- a/Jellyfin.Api/BaseJellyfinApiController.cs
+++ b/Jellyfin.Api/BaseJellyfinApiController.cs
@@ -4,35 +4,34 @@ using Jellyfin.Api.Results;
using Jellyfin.Extensions.Json;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api
+namespace Jellyfin.Api;
+
+///
+/// Base api controller for the API setting a default route.
+///
+[ApiController]
+[Route("[controller]")]
+[Produces(
+ MediaTypeNames.Application.Json,
+ JsonDefaults.CamelCaseMediaType,
+ JsonDefaults.PascalCaseMediaType)]
+public class BaseJellyfinApiController : ControllerBase
{
///
- /// Base api controller for the API setting a default route.
+ /// Create a new .
///
- [ApiController]
- [Route("[controller]")]
- [Produces(
- MediaTypeNames.Application.Json,
- JsonDefaults.CamelCaseMediaType,
- JsonDefaults.PascalCaseMediaType)]
- public class BaseJellyfinApiController : ControllerBase
- {
- ///
- /// Create a new .
- ///
- /// The value to return.
- /// The type to return.
- /// The .
- protected ActionResult> Ok(IEnumerable? value)
- => new OkResult?>(value);
+ /// The value to return.
+ /// The type to return.
+ /// The .
+ protected ActionResult> Ok(IEnumerable? value)
+ => new OkResult?>(value);
- ///
- /// Create a new .
- ///
- /// The value to return.
- /// The type to return.
- /// The .
- protected ActionResult Ok(T value)
- => new OkResult(value);
- }
+ ///
+ /// Create a new .
+ ///
+ /// The value to return.
+ /// The type to return.
+ /// The .
+ protected ActionResult Ok(T value)
+ => new OkResult(value);
}
diff --git a/Jellyfin.Api/Constants/AuthenticationSchemes.cs b/Jellyfin.Api/Constants/AuthenticationSchemes.cs
index bac3379e71..d5c2253e4a 100644
--- a/Jellyfin.Api/Constants/AuthenticationSchemes.cs
+++ b/Jellyfin.Api/Constants/AuthenticationSchemes.cs
@@ -1,13 +1,12 @@
-namespace Jellyfin.Api.Constants
+namespace Jellyfin.Api.Constants;
+
+///
+/// Authentication schemes for user authentication in the API.
+///
+public static class AuthenticationSchemes
{
///
- /// Authentication schemes for user authentication in the API.
+ /// Scheme name for the custom legacy authentication.
///
- public static class AuthenticationSchemes
- {
- ///
- /// Scheme name for the custom legacy authentication.
- ///
- public const string CustomAuthentication = "CustomAuthentication";
- }
+ public const string CustomAuthentication = "CustomAuthentication";
}
diff --git a/Jellyfin.Api/Constants/InternalClaimTypes.cs b/Jellyfin.Api/Constants/InternalClaimTypes.cs
index 8323312e51..73c4acb882 100644
--- a/Jellyfin.Api/Constants/InternalClaimTypes.cs
+++ b/Jellyfin.Api/Constants/InternalClaimTypes.cs
@@ -1,43 +1,42 @@
-namespace Jellyfin.Api.Constants
+namespace Jellyfin.Api.Constants;
+
+///
+/// Internal claim types for authorization.
+///
+public static class InternalClaimTypes
{
///
- /// Internal claim types for authorization.
+ /// User Id.
///
- public static class InternalClaimTypes
- {
- ///
- /// User Id.
- ///
- public const string UserId = "Jellyfin-UserId";
+ public const string UserId = "Jellyfin-UserId";
- ///
- /// Device Id.
- ///
- public const string DeviceId = "Jellyfin-DeviceId";
+ ///
+ /// Device Id.
+ ///
+ public const string DeviceId = "Jellyfin-DeviceId";
- ///
- /// Device.
- ///
- public const string Device = "Jellyfin-Device";
+ ///
+ /// Device.
+ ///
+ public const string Device = "Jellyfin-Device";
- ///
- /// Client.
- ///
- public const string Client = "Jellyfin-Client";
+ ///
+ /// Client.
+ ///
+ public const string Client = "Jellyfin-Client";
- ///
- /// Version.
- ///
- public const string Version = "Jellyfin-Version";
+ ///
+ /// Version.
+ ///
+ public const string Version = "Jellyfin-Version";
- ///
- /// Token.
- ///
- public const string Token = "Jellyfin-Token";
+ ///
+ /// Token.
+ ///
+ public const string Token = "Jellyfin-Token";
- ///
- /// Is Api Key.
- ///
- public const string IsApiKey = "Jellyfin-IsApiKey";
- }
+ ///
+ /// Is Api Key.
+ ///
+ public const string IsApiKey = "Jellyfin-IsApiKey";
}
diff --git a/Jellyfin.Api/Constants/Policies.cs b/Jellyfin.Api/Constants/Policies.cs
index a72eeea284..5a5a2bf466 100644
--- a/Jellyfin.Api/Constants/Policies.cs
+++ b/Jellyfin.Api/Constants/Policies.cs
@@ -1,78 +1,77 @@
-namespace Jellyfin.Api.Constants
+namespace Jellyfin.Api.Constants;
+
+///
+/// Policies for the API authorization.
+///
+public static class Policies
{
///
- /// Policies for the API authorization.
+ /// Policy name for default authorization.
///
- public static class Policies
- {
- ///
- /// Policy name for default authorization.
- ///
- public const string DefaultAuthorization = "DefaultAuthorization";
+ public const string DefaultAuthorization = "DefaultAuthorization";
- ///
- /// Policy name for requiring first time setup or elevated privileges.
- ///
- public const string FirstTimeSetupOrElevated = "FirstTimeSetupOrElevated";
+ ///
+ /// Policy name for requiring first time setup or elevated privileges.
+ ///
+ public const string FirstTimeSetupOrElevated = "FirstTimeSetupOrElevated";
- ///
- /// Policy name for requiring elevated privileges.
- ///
- public const string RequiresElevation = "RequiresElevation";
+ ///
+ /// Policy name for requiring elevated privileges.
+ ///
+ public const string RequiresElevation = "RequiresElevation";
- ///
- /// Policy name for allowing local access only.
- ///
- public const string LocalAccessOnly = "LocalAccessOnly";
+ ///
+ /// Policy name for allowing local access only.
+ ///
+ public const string LocalAccessOnly = "LocalAccessOnly";
- ///
- /// Policy name for escaping schedule controls.
- ///
- public const string IgnoreParentalControl = "IgnoreParentalControl";
+ ///
+ /// Policy name for escaping schedule controls.
+ ///
+ public const string IgnoreParentalControl = "IgnoreParentalControl";
- ///
- /// Policy name for requiring download permission.
- ///
- public const string Download = "Download";
+ ///
+ /// Policy name for requiring download permission.
+ ///
+ public const string Download = "Download";
- ///
- /// Policy name for requiring first time setup or default permissions.
- ///
- public const string FirstTimeSetupOrDefault = "FirstTimeSetupOrDefault";
+ ///
+ /// Policy name for requiring first time setup or default permissions.
+ ///
+ public const string FirstTimeSetupOrDefault = "FirstTimeSetupOrDefault";
- ///
- /// Policy name for requiring local access or elevated privileges.
- ///
- public const string LocalAccessOrRequiresElevation = "LocalAccessOrRequiresElevation";
+ ///
+ /// Policy name for requiring local access or elevated privileges.
+ ///
+ public const string LocalAccessOrRequiresElevation = "LocalAccessOrRequiresElevation";
- ///
- /// Policy name for requiring (anonymous) LAN access.
- ///
- public const string AnonymousLanAccessPolicy = "AnonymousLanAccessPolicy";
+ ///
+ /// Policy name for requiring (anonymous) LAN access.
+ ///
+ public const string AnonymousLanAccessPolicy = "AnonymousLanAccessPolicy";
- ///
- /// Policy name for escaping schedule controls or requiring first time setup.
- ///
- public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl";
+ ///
+ /// Policy name for escaping schedule controls or requiring first time setup.
+ ///
+ public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl";
- ///
- /// Policy name for accessing SyncPlay.
- ///
- public const string SyncPlayHasAccess = "SyncPlayHasAccess";
+ ///
+ /// Policy name for accessing SyncPlay.
+ ///
+ public const string SyncPlayHasAccess = "SyncPlayHasAccess";
- ///
- /// Policy name for creating a SyncPlay group.
- ///
- public const string SyncPlayCreateGroup = "SyncPlayCreateGroup";
+ ///
+ /// Policy name for creating a SyncPlay group.
+ ///
+ public const string SyncPlayCreateGroup = "SyncPlayCreateGroup";
- ///
- /// Policy name for joining a SyncPlay group.
- ///
- public const string SyncPlayJoinGroup = "SyncPlayJoinGroup";
+ ///
+ /// Policy name for joining a SyncPlay group.
+ ///
+ public const string SyncPlayJoinGroup = "SyncPlayJoinGroup";
- ///
- /// Policy name for accessing a SyncPlay group.
- ///
- public const string SyncPlayIsInGroup = "SyncPlayIsInGroup";
- }
+ ///
+ /// Policy name for accessing a SyncPlay group.
+ ///
+ public const string SyncPlayIsInGroup = "SyncPlayIsInGroup";
}
diff --git a/Jellyfin.Api/Constants/UserRoles.cs b/Jellyfin.Api/Constants/UserRoles.cs
index d9a536e7d7..41c7b7cd0f 100644
--- a/Jellyfin.Api/Constants/UserRoles.cs
+++ b/Jellyfin.Api/Constants/UserRoles.cs
@@ -1,23 +1,22 @@
-namespace Jellyfin.Api.Constants
+namespace Jellyfin.Api.Constants;
+
+///
+/// Constants for user roles used in the authentication and authorization for the API.
+///
+public static class UserRoles
{
///
- /// Constants for user roles used in the authentication and authorization for the API.
+ /// Guest user.
///
- public static class UserRoles
- {
- ///
- /// Guest user.
- ///
- public const string Guest = "Guest";
+ public const string Guest = "Guest";
- ///
- /// Regular user with no special privileges.
- ///
- public const string User = "User";
+ ///
+ /// Regular user with no special privileges.
+ ///
+ public const string User = "User";
- ///
- /// Administrator user with elevated privileges.
- ///
- public const string Administrator = "Administrator";
- }
+ ///
+ /// Administrator user with elevated privileges.
+ ///
+ public const string Administrator = "Administrator";
}
diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs
index ae45f647f7..c3d02976eb 100644
--- a/Jellyfin.Api/Controllers/ActivityLogController.cs
+++ b/Jellyfin.Api/Controllers/ActivityLogController.cs
@@ -8,50 +8,49 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Activity log controller.
+///
+[Route("System/ActivityLog")]
+[Authorize(Policy = Policies.RequiresElevation)]
+public class ActivityLogController : BaseJellyfinApiController
{
+ private readonly IActivityManager _activityManager;
+
///
- /// Activity log controller.
+ /// Initializes a new instance of the class.
///
- [Route("System/ActivityLog")]
- [Authorize(Policy = Policies.RequiresElevation)]
- public class ActivityLogController : BaseJellyfinApiController
+ /// Instance of interface.
+ public ActivityLogController(IActivityManager activityManager)
{
- private readonly IActivityManager _activityManager;
+ _activityManager = activityManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of interface.
- public ActivityLogController(IActivityManager activityManager)
+ ///
+ /// Gets activity log entries.
+ ///
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. The minimum date. Format = ISO.
+ /// Optional. Filter log entries if it has user id, or not.
+ /// Activity log returned.
+ /// A containing the log entries.
+ [HttpGet("Entries")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task>> GetLogEntries(
+ [FromQuery] int? startIndex,
+ [FromQuery] int? limit,
+ [FromQuery] DateTime? minDate,
+ [FromQuery] bool? hasUserId)
+ {
+ return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
{
- _activityManager = activityManager;
- }
-
- ///
- /// Gets activity log entries.
- ///
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. The minimum date. Format = ISO.
- /// Optional. Filter log entries if it has user id, or not.
- /// Activity log returned.
- /// A containing the log entries.
- [HttpGet("Entries")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public async Task>> GetLogEntries(
- [FromQuery] int? startIndex,
- [FromQuery] int? limit,
- [FromQuery] DateTime? minDate,
- [FromQuery] bool? hasUserId)
- {
- return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
- {
- Skip = startIndex,
- Limit = limit,
- MinDate = minDate,
- HasUserId = hasUserId
- }).ConfigureAwait(false);
- }
+ Skip = startIndex,
+ Limit = limit,
+ MinDate = minDate,
+ HasUserId = hasUserId
+ }).ConfigureAwait(false);
}
}
diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs
index 024a15349e..991f8cbf20 100644
--- a/Jellyfin.Api/Controllers/ApiKeyController.cs
+++ b/Jellyfin.Api/Controllers/ApiKeyController.cs
@@ -7,70 +7,69 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Authentication controller.
+///
+[Route("Auth")]
+public class ApiKeyController : BaseJellyfinApiController
{
+ private readonly IAuthenticationManager _authenticationManager;
+
///
- /// Authentication controller.
+ /// Initializes a new instance of the class.
///
- [Route("Auth")]
- public class ApiKeyController : BaseJellyfinApiController
+ /// Instance of interface.
+ public ApiKeyController(IAuthenticationManager authenticationManager)
{
- private readonly IAuthenticationManager _authenticationManager;
+ _authenticationManager = authenticationManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of interface.
- public ApiKeyController(IAuthenticationManager authenticationManager)
- {
- _authenticationManager = authenticationManager;
- }
+ ///
+ /// Get all keys.
+ ///
+ /// Api keys retrieved.
+ /// A with all keys.
+ [HttpGet("Keys")]
+ [Authorize(Policy = Policies.RequiresElevation)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task>> GetKeys()
+ {
+ var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false);
- ///
- /// Get all keys.
- ///
- /// Api keys retrieved.
- /// A with all keys.
- [HttpGet("Keys")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public async Task>> GetKeys()
- {
- var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false);
+ return new QueryResult(keys);
+ }
- return new QueryResult(keys);
- }
+ ///
+ /// Create a new api key.
+ ///
+ /// Name of the app using the authentication key.
+ /// Api key created.
+ /// A .
+ [HttpPost("Keys")]
+ [Authorize(Policy = Policies.RequiresElevation)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public async Task CreateKey([FromQuery, Required] string app)
+ {
+ await _authenticationManager.CreateApiKey(app).ConfigureAwait(false);
- ///
- /// Create a new api key.
- ///
- /// Name of the app using the authentication key.
- /// Api key created.
- /// A .
- [HttpPost("Keys")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task CreateKey([FromQuery, Required] string app)
- {
- await _authenticationManager.CreateApiKey(app).ConfigureAwait(false);
+ return NoContent();
+ }
- return NoContent();
- }
+ ///
+ /// Remove an api key.
+ ///
+ /// The access token to delete.
+ /// Api key deleted.
+ /// A .
+ [HttpDelete("Keys/{key}")]
+ [Authorize(Policy = Policies.RequiresElevation)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public async Task RevokeKey([FromRoute, Required] string key)
+ {
+ await _authenticationManager.DeleteApiKey(key).ConfigureAwait(false);
- ///
- /// Remove an api key.
- ///
- /// The access token to delete.
- /// Api key deleted.
- /// A .
- [HttpDelete("Keys/{key}")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task RevokeKey([FromRoute, Required] string key)
- {
- await _authenticationManager.DeleteApiKey(key).ConfigureAwait(false);
-
- return NoContent();
- }
+ return NoContent();
}
}
diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs
index c8ac2ed526..069e7311b8 100644
--- a/Jellyfin.Api/Controllers/ArtistsController.cs
+++ b/Jellyfin.Api/Controllers/ArtistsController.cs
@@ -17,464 +17,463 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// The artists controller.
+///
+[Route("Artists")]
+[Authorize(Policy = Policies.DefaultAuthorization)]
+public class ArtistsController : BaseJellyfinApiController
{
+ private readonly ILibraryManager _libraryManager;
+ private readonly IUserManager _userManager;
+ private readonly IDtoService _dtoService;
+
///
- /// The artists controller.
+ /// Initializes a new instance of the class.
///
- [Route("Artists")]
- [Authorize(Policy = Policies.DefaultAuthorization)]
- public class ArtistsController : BaseJellyfinApiController
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public ArtistsController(
+ ILibraryManager libraryManager,
+ IUserManager userManager,
+ IDtoService dtoService)
{
- private readonly ILibraryManager _libraryManager;
- private readonly IUserManager _userManager;
- private readonly IDtoService _dtoService;
+ _libraryManager = libraryManager;
+ _userManager = userManager;
+ _dtoService = dtoService;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- /// Instance of the interface.
- /// Instance of the interface.
- public ArtistsController(
- ILibraryManager libraryManager,
- IUserManager userManager,
- IDtoService dtoService)
+ ///
+ /// Gets all artists from a given item, folder, or the entire library.
+ ///
+ /// Optional filter by minimum community rating.
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. Search term.
+ /// Specify this to localize the search to a specific item or folder. Omit to use the root.
+ /// Optional. Specify additional fields of information to return in the output.
+ /// Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.
+ /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.
+ /// Optional. Specify additional filters to apply.
+ /// Optional filter by items that are marked as favorite, or not.
+ /// Optional filter by MediaType. Allows multiple, comma delimited.
+ /// Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.
+ /// Optional, include user data.
+ /// Optional, the max number of images to return, per image type.
+ /// Optional. The image types to include in the output.
+ /// Optional. If specified, results will be filtered to include only those containing the specified person.
+ /// Optional. If specified, results will be filtered to include only those containing the specified person ids.
+ /// Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.
+ /// Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.
+ /// User id.
+ /// Optional filter by items whose name is sorted equally or greater than a given input string.
+ /// Optional filter by items whose name is sorted equally than a given input string.
+ /// Optional filter by items whose name is equally or lesser than a given input string.
+ /// Optional. Specify one or more sort orders, comma delimited.
+ /// Sort Order - Ascending,Descending.
+ /// Optional, include image information in output.
+ /// Total record count.
+ /// Artists returned.
+ /// An containing the artists.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetArtists(
+ [FromQuery] double? minCommunityRating,
+ [FromQuery] int? startIndex,
+ [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] bool? isFavorite,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] 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] bool? enableUserData,
+ [FromQuery] int? imageTypeLimit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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] Guid? userId,
+ [FromQuery] string? nameStartsWithOrGreater,
+ [FromQuery] string? nameStartsWith,
+ [FromQuery] string? nameLessThan,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
+ [FromQuery] bool? enableImages = true,
+ [FromQuery] bool enableTotalRecordCount = true)
+ {
+ var dtoOptions = new DtoOptions { Fields = fields }
+ .AddClientFields(User)
+ .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
+
+ User? user = null;
+ BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
+
+ if (userId.HasValue && !userId.Equals(default))
{
- _libraryManager = libraryManager;
- _userManager = userManager;
- _dtoService = dtoService;
+ user = _userManager.GetUserById(userId.Value);
}
- ///
- /// Gets all artists from a given item, folder, or the entire library.
- ///
- /// Optional filter by minimum community rating.
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. Search term.
- /// Specify this to localize the search to a specific item or folder. Omit to use the root.
- /// Optional. Specify additional fields of information to return in the output.
- /// Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.
- /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.
- /// Optional. Specify additional filters to apply.
- /// Optional filter by items that are marked as favorite, or not.
- /// Optional filter by MediaType. Allows multiple, comma delimited.
- /// Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.
- /// Optional, include user data.
- /// Optional, the max number of images to return, per image type.
- /// Optional. The image types to include in the output.
- /// Optional. If specified, results will be filtered to include only those containing the specified person.
- /// Optional. If specified, results will be filtered to include only those containing the specified person ids.
- /// Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.
- /// Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.
- /// User id.
- /// Optional filter by items whose name is sorted equally or greater than a given input string.
- /// Optional filter by items whose name is sorted equally than a given input string.
- /// Optional filter by items whose name is equally or lesser than a given input string.
- /// Optional. Specify one or more sort orders, comma delimited.
- /// Sort Order - Ascending,Descending.
- /// Optional, include image information in output.
- /// Total record count.
- /// Artists returned.
- /// An containing the artists.
- [HttpGet]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetArtists(
- [FromQuery] double? minCommunityRating,
- [FromQuery] int? startIndex,
- [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] bool? isFavorite,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] 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] bool? enableUserData,
- [FromQuery] int? imageTypeLimit,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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] Guid? userId,
- [FromQuery] string? nameStartsWithOrGreater,
- [FromQuery] string? nameStartsWith,
- [FromQuery] string? nameLessThan,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
- [FromQuery] bool? enableImages = true,
- [FromQuery] bool enableTotalRecordCount = true)
+ var query = new InternalItemsQuery(user)
{
- var dtoOptions = new DtoOptions { Fields = fields }
- .AddClientFields(User)
- .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
+ MediaTypes = mediaTypes,
+ StartIndex = startIndex,
+ Limit = limit,
+ IsFavorite = isFavorite,
+ NameLessThan = nameLessThan,
+ NameStartsWith = nameStartsWith,
+ NameStartsWithOrGreater = nameStartsWithOrGreater,
+ Tags = tags,
+ OfficialRatings = officialRatings,
+ Genres = genres,
+ GenreIds = genreIds,
+ StudioIds = studioIds,
+ Person = person,
+ PersonIds = personIds,
+ PersonTypes = personTypes,
+ Years = years,
+ MinCommunityRating = minCommunityRating,
+ DtoOptions = dtoOptions,
+ SearchTerm = searchTerm,
+ EnableTotalRecordCount = enableTotalRecordCount,
+ OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder)
+ };
- User? user = null;
- BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
-
- if (userId.HasValue && !userId.Equals(default))
+ if (parentId.HasValue)
+ {
+ if (parentItem is Folder)
{
- user = _userManager.GetUserById(userId.Value);
+ query.AncestorIds = new[] { parentId.Value };
}
-
- var query = new InternalItemsQuery(user)
+ else
{
- ExcludeItemTypes = excludeItemTypes,
- IncludeItemTypes = includeItemTypes,
- MediaTypes = mediaTypes,
- StartIndex = startIndex,
- Limit = limit,
- IsFavorite = isFavorite,
- NameLessThan = nameLessThan,
- NameStartsWith = nameStartsWith,
- NameStartsWithOrGreater = nameStartsWithOrGreater,
- Tags = tags,
- OfficialRatings = officialRatings,
- Genres = genres,
- GenreIds = genreIds,
- StudioIds = studioIds,
- Person = person,
- PersonIds = personIds,
- PersonTypes = personTypes,
- Years = years,
- MinCommunityRating = minCommunityRating,
- DtoOptions = dtoOptions,
- SearchTerm = searchTerm,
- EnableTotalRecordCount = enableTotalRecordCount,
- OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder)
- };
-
- if (parentId.HasValue)
- {
- if (parentItem is Folder)
- {
- query.AncestorIds = new[] { parentId.Value };
- }
- else
- {
- query.ItemIds = new[] { parentId.Value };
- }
+ query.ItemIds = new[] { parentId.Value };
}
-
- // Studios
- if (studios.Length != 0)
- {
- query.StudioIds = studios.Select(i =>
- {
- try
- {
- return _libraryManager.GetStudio(i);
- }
- catch
- {
- return null;
- }
- }).Where(i => i is not null).Select(i => i!.Id).ToArray();
- }
-
- foreach (var filter in filters)
- {
- switch (filter)
- {
- case ItemFilter.Dislikes:
- query.IsLiked = false;
- break;
- case ItemFilter.IsFavorite:
- query.IsFavorite = true;
- break;
- case ItemFilter.IsFavoriteOrLikes:
- query.IsFavoriteOrLiked = true;
- break;
- case ItemFilter.IsFolder:
- query.IsFolder = true;
- break;
- case ItemFilter.IsNotFolder:
- query.IsFolder = false;
- break;
- case ItemFilter.IsPlayed:
- query.IsPlayed = true;
- break;
- case ItemFilter.IsResumable:
- query.IsResumable = true;
- break;
- case ItemFilter.IsUnplayed:
- query.IsPlayed = false;
- break;
- case ItemFilter.Likes:
- query.IsLiked = true;
- break;
- }
- }
-
- var result = _libraryManager.GetArtists(query);
-
- var dtos = result.Items.Select(i =>
- {
- var (baseItem, itemCounts) = i;
- var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user);
-
- if (includeItemTypes.Length != 0)
- {
- dto.ChildCount = itemCounts.ItemCount;
- dto.ProgramCount = itemCounts.ProgramCount;
- dto.SeriesCount = itemCounts.SeriesCount;
- dto.EpisodeCount = itemCounts.EpisodeCount;
- dto.MovieCount = itemCounts.MovieCount;
- dto.TrailerCount = itemCounts.TrailerCount;
- dto.AlbumCount = itemCounts.AlbumCount;
- dto.SongCount = itemCounts.SongCount;
- dto.ArtistCount = itemCounts.ArtistCount;
- }
-
- return dto;
- });
-
- return new QueryResult(
- query.StartIndex,
- result.TotalRecordCount,
- dtos.ToArray());
}
- ///
- /// Gets all album artists from a given item, folder, or the entire library.
- ///
- /// Optional filter by minimum community rating.
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. Search term.
- /// Specify this to localize the search to a specific item or folder. Omit to use the root.
- /// Optional. Specify additional fields of information to return in the output.
- /// Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.
- /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.
- /// Optional. Specify additional filters to apply.
- /// Optional filter by items that are marked as favorite, or not.
- /// Optional filter by MediaType. Allows multiple, comma delimited.
- /// Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.
- /// Optional, include user data.
- /// Optional, the max number of images to return, per image type.
- /// Optional. The image types to include in the output.
- /// Optional. If specified, results will be filtered to include only those containing the specified person.
- /// Optional. If specified, results will be filtered to include only those containing the specified person ids.
- /// Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.
- /// Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.
- /// Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.
- /// User id.
- /// Optional filter by items whose name is sorted equally or greater than a given input string.
- /// Optional filter by items whose name is sorted equally than a given input string.
- /// Optional filter by items whose name is equally or lesser than a given input string.
- /// Optional. Specify one or more sort orders, comma delimited.
- /// Sort Order - Ascending,Descending.
- /// Optional, include image information in output.
- /// Total record count.
- /// Album artists returned.
- /// An containing the album artists.
- [HttpGet("AlbumArtists")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetAlbumArtists(
- [FromQuery] double? minCommunityRating,
- [FromQuery] int? startIndex,
- [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] bool? isFavorite,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] 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] bool? enableUserData,
- [FromQuery] int? imageTypeLimit,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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] Guid? userId,
- [FromQuery] string? nameStartsWithOrGreater,
- [FromQuery] string? nameStartsWith,
- [FromQuery] string? nameLessThan,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
- [FromQuery] bool? enableImages = true,
- [FromQuery] bool enableTotalRecordCount = true)
+ // Studios
+ if (studios.Length != 0)
{
- var dtoOptions = new DtoOptions { Fields = fields }
- .AddClientFields(User)
- .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
-
- User? user = null;
- BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
-
- if (userId.HasValue && !userId.Equals(default))
+ query.StudioIds = studios.Select(i =>
{
- user = _userManager.GetUserById(userId.Value);
- }
-
- var query = new InternalItemsQuery(user)
- {
- ExcludeItemTypes = excludeItemTypes,
- IncludeItemTypes = includeItemTypes,
- MediaTypes = mediaTypes,
- StartIndex = startIndex,
- Limit = limit,
- IsFavorite = isFavorite,
- NameLessThan = nameLessThan,
- NameStartsWith = nameStartsWith,
- NameStartsWithOrGreater = nameStartsWithOrGreater,
- Tags = tags,
- OfficialRatings = officialRatings,
- Genres = genres,
- GenreIds = genreIds,
- StudioIds = studioIds,
- Person = person,
- PersonIds = personIds,
- PersonTypes = personTypes,
- Years = years,
- MinCommunityRating = minCommunityRating,
- DtoOptions = dtoOptions,
- SearchTerm = searchTerm,
- EnableTotalRecordCount = enableTotalRecordCount,
- OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder)
- };
-
- if (parentId.HasValue)
- {
- if (parentItem is Folder)
+ try
{
- query.AncestorIds = new[] { parentId.Value };
+ return _libraryManager.GetStudio(i);
}
- else
+ catch
{
- query.ItemIds = new[] { parentId.Value };
+ return null;
}
- }
-
- // Studios
- if (studios.Length != 0)
- {
- query.StudioIds = studios.Select(i =>
- {
- try
- {
- return _libraryManager.GetStudio(i);
- }
- catch
- {
- return null;
- }
- }).Where(i => i is not null).Select(i => i!.Id).ToArray();
- }
-
- foreach (var filter in filters)
- {
- switch (filter)
- {
- case ItemFilter.Dislikes:
- query.IsLiked = false;
- break;
- case ItemFilter.IsFavorite:
- query.IsFavorite = true;
- break;
- case ItemFilter.IsFavoriteOrLikes:
- query.IsFavoriteOrLiked = true;
- break;
- case ItemFilter.IsFolder:
- query.IsFolder = true;
- break;
- case ItemFilter.IsNotFolder:
- query.IsFolder = false;
- break;
- case ItemFilter.IsPlayed:
- query.IsPlayed = true;
- break;
- case ItemFilter.IsResumable:
- query.IsResumable = true;
- break;
- case ItemFilter.IsUnplayed:
- query.IsPlayed = false;
- break;
- case ItemFilter.Likes:
- query.IsLiked = true;
- break;
- }
- }
-
- var result = _libraryManager.GetAlbumArtists(query);
-
- var dtos = result.Items.Select(i =>
- {
- var (baseItem, itemCounts) = i;
- var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user);
-
- if (includeItemTypes.Length != 0)
- {
- dto.ChildCount = itemCounts.ItemCount;
- dto.ProgramCount = itemCounts.ProgramCount;
- dto.SeriesCount = itemCounts.SeriesCount;
- dto.EpisodeCount = itemCounts.EpisodeCount;
- dto.MovieCount = itemCounts.MovieCount;
- dto.TrailerCount = itemCounts.TrailerCount;
- dto.AlbumCount = itemCounts.AlbumCount;
- dto.SongCount = itemCounts.SongCount;
- dto.ArtistCount = itemCounts.ArtistCount;
- }
-
- return dto;
- });
-
- return new QueryResult(
- query.StartIndex,
- result.TotalRecordCount,
- dtos.ToArray());
+ }).Where(i => i is not null).Select(i => i!.Id).ToArray();
}
- ///
- /// Gets an artist by name.
- ///
- /// Studio name.
- /// Optional. Filter by user id, and attach user data.
- /// Artist returned.
- /// An containing the artist.
- [HttpGet("{name}")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
+ foreach (var filter in filters)
{
- var dtoOptions = new DtoOptions().AddClientFields(User);
-
- var item = _libraryManager.GetArtist(name, dtoOptions);
-
- if (userId.HasValue && !userId.Value.Equals(default))
+ switch (filter)
{
- var user = _userManager.GetUserById(userId.Value);
+ case ItemFilter.Dislikes:
+ query.IsLiked = false;
+ break;
+ case ItemFilter.IsFavorite:
+ query.IsFavorite = true;
+ break;
+ case ItemFilter.IsFavoriteOrLikes:
+ query.IsFavoriteOrLiked = true;
+ break;
+ case ItemFilter.IsFolder:
+ query.IsFolder = true;
+ break;
+ case ItemFilter.IsNotFolder:
+ query.IsFolder = false;
+ break;
+ case ItemFilter.IsPlayed:
+ query.IsPlayed = true;
+ break;
+ case ItemFilter.IsResumable:
+ query.IsResumable = true;
+ break;
+ case ItemFilter.IsUnplayed:
+ query.IsPlayed = false;
+ break;
+ case ItemFilter.Likes:
+ query.IsLiked = true;
+ break;
+ }
+ }
- return _dtoService.GetBaseItemDto(item, dtoOptions, user);
+ var result = _libraryManager.GetArtists(query);
+
+ var dtos = result.Items.Select(i =>
+ {
+ var (baseItem, itemCounts) = i;
+ var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user);
+
+ if (includeItemTypes.Length != 0)
+ {
+ dto.ChildCount = itemCounts.ItemCount;
+ dto.ProgramCount = itemCounts.ProgramCount;
+ dto.SeriesCount = itemCounts.SeriesCount;
+ dto.EpisodeCount = itemCounts.EpisodeCount;
+ dto.MovieCount = itemCounts.MovieCount;
+ dto.TrailerCount = itemCounts.TrailerCount;
+ dto.AlbumCount = itemCounts.AlbumCount;
+ dto.SongCount = itemCounts.SongCount;
+ dto.ArtistCount = itemCounts.ArtistCount;
}
- return _dtoService.GetBaseItemDto(item, dtoOptions);
+ return dto;
+ });
+
+ return new QueryResult(
+ query.StartIndex,
+ result.TotalRecordCount,
+ dtos.ToArray());
+ }
+
+ ///
+ /// Gets all album artists from a given item, folder, or the entire library.
+ ///
+ /// Optional filter by minimum community rating.
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. Search term.
+ /// Specify this to localize the search to a specific item or folder. Omit to use the root.
+ /// Optional. Specify additional fields of information to return in the output.
+ /// Optional. If specified, results will be filtered out based on item type. This allows multiple, comma delimited.
+ /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.
+ /// Optional. Specify additional filters to apply.
+ /// Optional filter by items that are marked as favorite, or not.
+ /// Optional filter by MediaType. Allows multiple, comma delimited.
+ /// Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimited.
+ /// Optional, include user data.
+ /// Optional, the max number of images to return, per image type.
+ /// Optional. The image types to include in the output.
+ /// Optional. If specified, results will be filtered to include only those containing the specified person.
+ /// Optional. If specified, results will be filtered to include only those containing the specified person ids.
+ /// Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited.
+ /// Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimited.
+ /// Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimited.
+ /// User id.
+ /// Optional filter by items whose name is sorted equally or greater than a given input string.
+ /// Optional filter by items whose name is sorted equally than a given input string.
+ /// Optional filter by items whose name is equally or lesser than a given input string.
+ /// Optional. Specify one or more sort orders, comma delimited.
+ /// Sort Order - Ascending,Descending.
+ /// Optional, include image information in output.
+ /// Total record count.
+ /// Album artists returned.
+ /// An containing the album artists.
+ [HttpGet("AlbumArtists")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetAlbumArtists(
+ [FromQuery] double? minCommunityRating,
+ [FromQuery] int? startIndex,
+ [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] bool? isFavorite,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] 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] bool? enableUserData,
+ [FromQuery] int? imageTypeLimit,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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] Guid? userId,
+ [FromQuery] string? nameStartsWithOrGreater,
+ [FromQuery] string? nameStartsWith,
+ [FromQuery] string? nameLessThan,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
+ [FromQuery] bool? enableImages = true,
+ [FromQuery] bool enableTotalRecordCount = true)
+ {
+ var dtoOptions = new DtoOptions { Fields = fields }
+ .AddClientFields(User)
+ .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
+
+ User? user = null;
+ BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);
+
+ if (userId.HasValue && !userId.Equals(default))
+ {
+ user = _userManager.GetUserById(userId.Value);
}
+
+ var query = new InternalItemsQuery(user)
+ {
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
+ MediaTypes = mediaTypes,
+ StartIndex = startIndex,
+ Limit = limit,
+ IsFavorite = isFavorite,
+ NameLessThan = nameLessThan,
+ NameStartsWith = nameStartsWith,
+ NameStartsWithOrGreater = nameStartsWithOrGreater,
+ Tags = tags,
+ OfficialRatings = officialRatings,
+ Genres = genres,
+ GenreIds = genreIds,
+ StudioIds = studioIds,
+ Person = person,
+ PersonIds = personIds,
+ PersonTypes = personTypes,
+ Years = years,
+ MinCommunityRating = minCommunityRating,
+ DtoOptions = dtoOptions,
+ SearchTerm = searchTerm,
+ EnableTotalRecordCount = enableTotalRecordCount,
+ OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder)
+ };
+
+ if (parentId.HasValue)
+ {
+ if (parentItem is Folder)
+ {
+ query.AncestorIds = new[] { parentId.Value };
+ }
+ else
+ {
+ query.ItemIds = new[] { parentId.Value };
+ }
+ }
+
+ // Studios
+ if (studios.Length != 0)
+ {
+ query.StudioIds = studios.Select(i =>
+ {
+ try
+ {
+ return _libraryManager.GetStudio(i);
+ }
+ catch
+ {
+ return null;
+ }
+ }).Where(i => i is not null).Select(i => i!.Id).ToArray();
+ }
+
+ foreach (var filter in filters)
+ {
+ switch (filter)
+ {
+ case ItemFilter.Dislikes:
+ query.IsLiked = false;
+ break;
+ case ItemFilter.IsFavorite:
+ query.IsFavorite = true;
+ break;
+ case ItemFilter.IsFavoriteOrLikes:
+ query.IsFavoriteOrLiked = true;
+ break;
+ case ItemFilter.IsFolder:
+ query.IsFolder = true;
+ break;
+ case ItemFilter.IsNotFolder:
+ query.IsFolder = false;
+ break;
+ case ItemFilter.IsPlayed:
+ query.IsPlayed = true;
+ break;
+ case ItemFilter.IsResumable:
+ query.IsResumable = true;
+ break;
+ case ItemFilter.IsUnplayed:
+ query.IsPlayed = false;
+ break;
+ case ItemFilter.Likes:
+ query.IsLiked = true;
+ break;
+ }
+ }
+
+ var result = _libraryManager.GetAlbumArtists(query);
+
+ var dtos = result.Items.Select(i =>
+ {
+ var (baseItem, itemCounts) = i;
+ var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user);
+
+ if (includeItemTypes.Length != 0)
+ {
+ dto.ChildCount = itemCounts.ItemCount;
+ dto.ProgramCount = itemCounts.ProgramCount;
+ dto.SeriesCount = itemCounts.SeriesCount;
+ dto.EpisodeCount = itemCounts.EpisodeCount;
+ dto.MovieCount = itemCounts.MovieCount;
+ dto.TrailerCount = itemCounts.TrailerCount;
+ dto.AlbumCount = itemCounts.AlbumCount;
+ dto.SongCount = itemCounts.SongCount;
+ dto.ArtistCount = itemCounts.ArtistCount;
+ }
+
+ return dto;
+ });
+
+ return new QueryResult(
+ query.StartIndex,
+ result.TotalRecordCount,
+ dtos.ToArray());
+ }
+
+ ///
+ /// Gets an artist by name.
+ ///
+ /// Studio name.
+ /// Optional. Filter by user id, and attach user data.
+ /// Artist returned.
+ /// An containing the artist.
+ [HttpGet("{name}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
+ {
+ var dtoOptions = new DtoOptions().AddClientFields(User);
+
+ var item = _libraryManager.GetArtist(name, dtoOptions);
+
+ if (userId.HasValue && !userId.Value.Equals(default))
+ {
+ var user = _userManager.GetUserById(userId.Value);
+
+ return _dtoService.GetBaseItemDto(item, dtoOptions, user);
+ }
+
+ return _dtoService.GetBaseItemDto(item, dtoOptions);
}
}
diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs
index 94f7a7b827..968193a6f8 100644
--- a/Jellyfin.Api/Controllers/AudioController.cs
+++ b/Jellyfin.Api/Controllers/AudioController.cs
@@ -10,355 +10,354 @@ using MediaBrowser.Model.Dlna;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// The audio controller.
+///
+// TODO: In order to authenticate this in the future, Dlna playback will require updating
+public class AudioController : BaseJellyfinApiController
{
+ private readonly AudioHelper _audioHelper;
+
+ private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive;
+
///
- /// The audio controller.
+ /// Initializes a new instance of the class.
///
- // TODO: In order to authenticate this in the future, Dlna playback will require updating
- public class AudioController : BaseJellyfinApiController
+ /// Instance of .
+ public AudioController(AudioHelper audioHelper)
{
- private readonly AudioHelper _audioHelper;
+ _audioHelper = audioHelper;
+ }
- private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of .
- public AudioController(AudioHelper audioHelper)
+ ///
+ /// Gets an audio stream.
+ ///
+ /// The item id.
+ /// The audio container.
+ /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.
+ /// The streaming parameters.
+ /// The tag.
+ /// Optional. The dlna device profile id to utilize.
+ /// The play session id.
+ /// The segment container.
+ /// The segment length.
+ /// The minimum number of segments.
+ /// The media version id, if playing an alternate version.
+ /// The device id of the client requesting. Used to stop encoding processes when needed.
+ /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.
+ /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.
+ /// Whether or not to allow copying of the video stream url.
+ /// Whether or not to allow copying of the audio stream url.
+ /// Optional. Whether to break on non key frames.
+ /// Optional. Specify a specific audio sample rate, e.g. 44100.
+ /// Optional. The maximum audio bit depth.
+ /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.
+ /// Optional. Specify a specific number of audio channels to encode to, e.g. 2.
+ /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2.
+ /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.
+ /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.
+ /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
+ /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
+ /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false.
+ /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.
+ /// Optional. The fixed horizontal resolution of the encoded video.
+ /// Optional. The fixed vertical resolution of the encoded video.
+ /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.
+ /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.
+ /// Optional. Specify the subtitle delivery method.
+ /// Optional.
+ /// Optional. The maximum video bit depth.
+ /// Optional. Whether to require avc.
+ /// Optional. Whether to deinterlace the video.
+ /// Optional. Whether to require a non anamorphic stream.
+ /// Optional. The maximum number of audio channels to transcode.
+ /// Optional. The limit of how many cpu cores to use.
+ /// The live stream id.
+ /// Optional. Whether to enable the MpegtsM2Ts mode.
+ /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.
+ /// Optional. Specify a subtitle codec to encode to.
+ /// Optional. The transcoding reason.
+ /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used.
+ /// Optional. The index of the video stream to use. If omitted the first video stream will be used.
+ /// Optional. The .
+ /// Optional. The streaming options.
+ /// Audio stream returned.
+ /// A containing the audio file.
+ [HttpGet("{itemId}/stream", Name = "GetAudioStream")]
+ [HttpHead("{itemId}/stream", Name = "HeadAudioStream")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesAudioFile]
+ public async Task GetAudioStream(
+ [FromRoute, Required] Guid itemId,
+ [FromQuery] string? container,
+ [FromQuery] bool? @static,
+ [FromQuery] string? @params,
+ [FromQuery] string? tag,
+ [FromQuery] string? deviceProfileId,
+ [FromQuery] string? playSessionId,
+ [FromQuery] string? segmentContainer,
+ [FromQuery] int? segmentLength,
+ [FromQuery] int? minSegments,
+ [FromQuery] string? mediaSourceId,
+ [FromQuery] string? deviceId,
+ [FromQuery] string? audioCodec,
+ [FromQuery] bool? enableAutoStreamCopy,
+ [FromQuery] bool? allowVideoStreamCopy,
+ [FromQuery] bool? allowAudioStreamCopy,
+ [FromQuery] bool? breakOnNonKeyFrames,
+ [FromQuery] int? audioSampleRate,
+ [FromQuery] int? maxAudioBitDepth,
+ [FromQuery] int? audioBitRate,
+ [FromQuery] int? audioChannels,
+ [FromQuery] int? maxAudioChannels,
+ [FromQuery] string? profile,
+ [FromQuery] string? level,
+ [FromQuery] float? framerate,
+ [FromQuery] float? maxFramerate,
+ [FromQuery] bool? copyTimestamps,
+ [FromQuery] long? startTimeTicks,
+ [FromQuery] int? width,
+ [FromQuery] int? height,
+ [FromQuery] int? videoBitRate,
+ [FromQuery] int? subtitleStreamIndex,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
+ [FromQuery] int? maxRefFrames,
+ [FromQuery] int? maxVideoBitDepth,
+ [FromQuery] bool? requireAvc,
+ [FromQuery] bool? deInterlace,
+ [FromQuery] bool? requireNonAnamorphic,
+ [FromQuery] int? transcodingMaxAudioChannels,
+ [FromQuery] int? cpuCoreLimit,
+ [FromQuery] string? liveStreamId,
+ [FromQuery] bool? enableMpegtsM2TsMode,
+ [FromQuery] string? videoCodec,
+ [FromQuery] string? subtitleCodec,
+ [FromQuery] string? transcodeReasons,
+ [FromQuery] int? audioStreamIndex,
+ [FromQuery] int? videoStreamIndex,
+ [FromQuery] EncodingContext? context,
+ [FromQuery] Dictionary? streamOptions)
+ {
+ StreamingRequestDto streamingRequest = new StreamingRequestDto
{
- _audioHelper = audioHelper;
- }
+ Id = itemId,
+ Container = container,
+ Static = @static ?? false,
+ Params = @params,
+ Tag = tag,
+ DeviceProfileId = deviceProfileId,
+ PlaySessionId = playSessionId,
+ SegmentContainer = segmentContainer,
+ SegmentLength = segmentLength,
+ MinSegments = minSegments,
+ MediaSourceId = mediaSourceId,
+ DeviceId = deviceId,
+ AudioCodec = audioCodec,
+ EnableAutoStreamCopy = enableAutoStreamCopy ?? true,
+ AllowAudioStreamCopy = allowAudioStreamCopy ?? true,
+ AllowVideoStreamCopy = allowVideoStreamCopy ?? true,
+ BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false,
+ AudioSampleRate = audioSampleRate,
+ MaxAudioChannels = maxAudioChannels,
+ AudioBitRate = audioBitRate,
+ MaxAudioBitDepth = maxAudioBitDepth,
+ AudioChannels = audioChannels,
+ Profile = profile,
+ Level = level,
+ Framerate = framerate,
+ MaxFramerate = maxFramerate,
+ CopyTimestamps = copyTimestamps ?? false,
+ StartTimeTicks = startTimeTicks,
+ Width = width,
+ Height = height,
+ VideoBitRate = videoBitRate,
+ SubtitleStreamIndex = subtitleStreamIndex,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
+ MaxRefFrames = maxRefFrames,
+ MaxVideoBitDepth = maxVideoBitDepth,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
+ TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
+ CpuCoreLimit = cpuCoreLimit,
+ LiveStreamId = liveStreamId,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
+ VideoCodec = videoCodec,
+ SubtitleCodec = subtitleCodec,
+ TranscodeReasons = transcodeReasons,
+ AudioStreamIndex = audioStreamIndex,
+ VideoStreamIndex = videoStreamIndex,
+ Context = context ?? EncodingContext.Static,
+ StreamOptions = streamOptions
+ };
- ///
- /// Gets an audio stream.
- ///
- /// The item id.
- /// The audio container.
- /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.
- /// The streaming parameters.
- /// The tag.
- /// Optional. The dlna device profile id to utilize.
- /// The play session id.
- /// The segment container.
- /// The segment length.
- /// The minimum number of segments.
- /// The media version id, if playing an alternate version.
- /// The device id of the client requesting. Used to stop encoding processes when needed.
- /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.
- /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.
- /// Whether or not to allow copying of the video stream url.
- /// Whether or not to allow copying of the audio stream url.
- /// Optional. Whether to break on non key frames.
- /// Optional. Specify a specific audio sample rate, e.g. 44100.
- /// Optional. The maximum audio bit depth.
- /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.
- /// Optional. Specify a specific number of audio channels to encode to, e.g. 2.
- /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2.
- /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.
- /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.
- /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
- /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
- /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false.
- /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.
- /// Optional. The fixed horizontal resolution of the encoded video.
- /// Optional. The fixed vertical resolution of the encoded video.
- /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.
- /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.
- /// Optional. Specify the subtitle delivery method.
- /// Optional.
- /// Optional. The maximum video bit depth.
- /// Optional. Whether to require avc.
- /// Optional. Whether to deinterlace the video.
- /// Optional. Whether to require a non anamorphic stream.
- /// Optional. The maximum number of audio channels to transcode.
- /// Optional. The limit of how many cpu cores to use.
- /// The live stream id.
- /// Optional. Whether to enable the MpegtsM2Ts mode.
- /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.
- /// Optional. Specify a subtitle codec to encode to.
- /// Optional. The transcoding reason.
- /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used.
- /// Optional. The index of the video stream to use. If omitted the first video stream will be used.
- /// Optional. The .
- /// Optional. The streaming options.
- /// Audio stream returned.
- /// A containing the audio file.
- [HttpGet("{itemId}/stream", Name = "GetAudioStream")]
- [HttpHead("{itemId}/stream", Name = "HeadAudioStream")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesAudioFile]
- public async Task GetAudioStream(
- [FromRoute, Required] Guid itemId,
- [FromQuery] string? container,
- [FromQuery] bool? @static,
- [FromQuery] string? @params,
- [FromQuery] string? tag,
- [FromQuery] string? deviceProfileId,
- [FromQuery] string? playSessionId,
- [FromQuery] string? segmentContainer,
- [FromQuery] int? segmentLength,
- [FromQuery] int? minSegments,
- [FromQuery] string? mediaSourceId,
- [FromQuery] string? deviceId,
- [FromQuery] string? audioCodec,
- [FromQuery] bool? enableAutoStreamCopy,
- [FromQuery] bool? allowVideoStreamCopy,
- [FromQuery] bool? allowAudioStreamCopy,
- [FromQuery] bool? breakOnNonKeyFrames,
- [FromQuery] int? audioSampleRate,
- [FromQuery] int? maxAudioBitDepth,
- [FromQuery] int? audioBitRate,
- [FromQuery] int? audioChannels,
- [FromQuery] int? maxAudioChannels,
- [FromQuery] string? profile,
- [FromQuery] string? level,
- [FromQuery] float? framerate,
- [FromQuery] float? maxFramerate,
- [FromQuery] bool? copyTimestamps,
- [FromQuery] long? startTimeTicks,
- [FromQuery] int? width,
- [FromQuery] int? height,
- [FromQuery] int? videoBitRate,
- [FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
- [FromQuery] int? maxRefFrames,
- [FromQuery] int? maxVideoBitDepth,
- [FromQuery] bool? requireAvc,
- [FromQuery] bool? deInterlace,
- [FromQuery] bool? requireNonAnamorphic,
- [FromQuery] int? transcodingMaxAudioChannels,
- [FromQuery] int? cpuCoreLimit,
- [FromQuery] string? liveStreamId,
- [FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] string? videoCodec,
- [FromQuery] string? subtitleCodec,
- [FromQuery] string? transcodeReasons,
- [FromQuery] int? audioStreamIndex,
- [FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext? context,
- [FromQuery] Dictionary? streamOptions)
+ return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
+ }
+
+ ///
+ /// Gets an audio stream.
+ ///
+ /// The item id.
+ /// The audio container.
+ /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.
+ /// The streaming parameters.
+ /// The tag.
+ /// Optional. The dlna device profile id to utilize.
+ /// The play session id.
+ /// The segment container.
+ /// The segment length.
+ /// The minimum number of segments.
+ /// The media version id, if playing an alternate version.
+ /// The device id of the client requesting. Used to stop encoding processes when needed.
+ /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.
+ /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.
+ /// Whether or not to allow copying of the video stream url.
+ /// Whether or not to allow copying of the audio stream url.
+ /// Optional. Whether to break on non key frames.
+ /// Optional. Specify a specific audio sample rate, e.g. 44100.
+ /// Optional. The maximum audio bit depth.
+ /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.
+ /// Optional. Specify a specific number of audio channels to encode to, e.g. 2.
+ /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2.
+ /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.
+ /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.
+ /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
+ /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
+ /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false.
+ /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.
+ /// Optional. The fixed horizontal resolution of the encoded video.
+ /// Optional. The fixed vertical resolution of the encoded video.
+ /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.
+ /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.
+ /// Optional. Specify the subtitle delivery method.
+ /// Optional.
+ /// Optional. The maximum video bit depth.
+ /// Optional. Whether to require avc.
+ /// Optional. Whether to deinterlace the video.
+ /// Optional. Whether to require a non anamporphic stream.
+ /// Optional. The maximum number of audio channels to transcode.
+ /// Optional. The limit of how many cpu cores to use.
+ /// The live stream id.
+ /// Optional. Whether to enable the MpegtsM2Ts mode.
+ /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.
+ /// Optional. Specify a subtitle codec to encode to.
+ /// Optional. The transcoding reason.
+ /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used.
+ /// Optional. The index of the video stream to use. If omitted the first video stream will be used.
+ /// Optional. The .
+ /// Optional. The streaming options.
+ /// Audio stream returned.
+ /// A containing the audio file.
+ [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")]
+ [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesAudioFile]
+ public async Task GetAudioStreamByContainer(
+ [FromRoute, Required] Guid itemId,
+ [FromRoute, Required] string container,
+ [FromQuery] bool? @static,
+ [FromQuery] string? @params,
+ [FromQuery] string? tag,
+ [FromQuery] string? deviceProfileId,
+ [FromQuery] string? playSessionId,
+ [FromQuery] string? segmentContainer,
+ [FromQuery] int? segmentLength,
+ [FromQuery] int? minSegments,
+ [FromQuery] string? mediaSourceId,
+ [FromQuery] string? deviceId,
+ [FromQuery] string? audioCodec,
+ [FromQuery] bool? enableAutoStreamCopy,
+ [FromQuery] bool? allowVideoStreamCopy,
+ [FromQuery] bool? allowAudioStreamCopy,
+ [FromQuery] bool? breakOnNonKeyFrames,
+ [FromQuery] int? audioSampleRate,
+ [FromQuery] int? maxAudioBitDepth,
+ [FromQuery] int? audioBitRate,
+ [FromQuery] int? audioChannels,
+ [FromQuery] int? maxAudioChannels,
+ [FromQuery] string? profile,
+ [FromQuery] string? level,
+ [FromQuery] float? framerate,
+ [FromQuery] float? maxFramerate,
+ [FromQuery] bool? copyTimestamps,
+ [FromQuery] long? startTimeTicks,
+ [FromQuery] int? width,
+ [FromQuery] int? height,
+ [FromQuery] int? videoBitRate,
+ [FromQuery] int? subtitleStreamIndex,
+ [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
+ [FromQuery] int? maxRefFrames,
+ [FromQuery] int? maxVideoBitDepth,
+ [FromQuery] bool? requireAvc,
+ [FromQuery] bool? deInterlace,
+ [FromQuery] bool? requireNonAnamorphic,
+ [FromQuery] int? transcodingMaxAudioChannels,
+ [FromQuery] int? cpuCoreLimit,
+ [FromQuery] string? liveStreamId,
+ [FromQuery] bool? enableMpegtsM2TsMode,
+ [FromQuery] string? videoCodec,
+ [FromQuery] string? subtitleCodec,
+ [FromQuery] string? transcodeReasons,
+ [FromQuery] int? audioStreamIndex,
+ [FromQuery] int? videoStreamIndex,
+ [FromQuery] EncodingContext? context,
+ [FromQuery] Dictionary? streamOptions)
+ {
+ StreamingRequestDto streamingRequest = new StreamingRequestDto
{
- StreamingRequestDto streamingRequest = new StreamingRequestDto
- {
- Id = itemId,
- Container = container,
- Static = @static ?? false,
- Params = @params,
- Tag = tag,
- DeviceProfileId = deviceProfileId,
- PlaySessionId = playSessionId,
- SegmentContainer = segmentContainer,
- SegmentLength = segmentLength,
- MinSegments = minSegments,
- MediaSourceId = mediaSourceId,
- DeviceId = deviceId,
- AudioCodec = audioCodec,
- EnableAutoStreamCopy = enableAutoStreamCopy ?? true,
- AllowAudioStreamCopy = allowAudioStreamCopy ?? true,
- AllowVideoStreamCopy = allowVideoStreamCopy ?? true,
- BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false,
- AudioSampleRate = audioSampleRate,
- MaxAudioChannels = maxAudioChannels,
- AudioBitRate = audioBitRate,
- MaxAudioBitDepth = maxAudioBitDepth,
- AudioChannels = audioChannels,
- Profile = profile,
- Level = level,
- Framerate = framerate,
- MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? false,
- StartTimeTicks = startTimeTicks,
- Width = width,
- Height = height,
- VideoBitRate = videoBitRate,
- SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
- MaxRefFrames = maxRefFrames,
- MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? false,
- DeInterlace = deInterlace ?? false,
- RequireNonAnamorphic = requireNonAnamorphic ?? false,
- TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
- CpuCoreLimit = cpuCoreLimit,
- LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
- VideoCodec = videoCodec,
- SubtitleCodec = subtitleCodec,
- TranscodeReasons = transcodeReasons,
- AudioStreamIndex = audioStreamIndex,
- VideoStreamIndex = videoStreamIndex,
- Context = context ?? EncodingContext.Static,
- StreamOptions = streamOptions
- };
+ Id = itemId,
+ Container = container,
+ Static = @static ?? false,
+ Params = @params,
+ Tag = tag,
+ DeviceProfileId = deviceProfileId,
+ PlaySessionId = playSessionId,
+ SegmentContainer = segmentContainer,
+ SegmentLength = segmentLength,
+ MinSegments = minSegments,
+ MediaSourceId = mediaSourceId,
+ DeviceId = deviceId,
+ AudioCodec = audioCodec,
+ EnableAutoStreamCopy = enableAutoStreamCopy ?? true,
+ AllowAudioStreamCopy = allowAudioStreamCopy ?? true,
+ AllowVideoStreamCopy = allowVideoStreamCopy ?? true,
+ BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false,
+ AudioSampleRate = audioSampleRate,
+ MaxAudioChannels = maxAudioChannels,
+ AudioBitRate = audioBitRate,
+ MaxAudioBitDepth = maxAudioBitDepth,
+ AudioChannels = audioChannels,
+ Profile = profile,
+ Level = level,
+ Framerate = framerate,
+ MaxFramerate = maxFramerate,
+ CopyTimestamps = copyTimestamps ?? false,
+ StartTimeTicks = startTimeTicks,
+ Width = width,
+ Height = height,
+ VideoBitRate = videoBitRate,
+ SubtitleStreamIndex = subtitleStreamIndex,
+ SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
+ MaxRefFrames = maxRefFrames,
+ MaxVideoBitDepth = maxVideoBitDepth,
+ RequireAvc = requireAvc ?? false,
+ DeInterlace = deInterlace ?? false,
+ RequireNonAnamorphic = requireNonAnamorphic ?? false,
+ TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
+ CpuCoreLimit = cpuCoreLimit,
+ LiveStreamId = liveStreamId,
+ EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
+ VideoCodec = videoCodec,
+ SubtitleCodec = subtitleCodec,
+ TranscodeReasons = transcodeReasons,
+ AudioStreamIndex = audioStreamIndex,
+ VideoStreamIndex = videoStreamIndex,
+ Context = context ?? EncodingContext.Static,
+ StreamOptions = streamOptions
+ };
- return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
- }
-
- ///
- /// Gets an audio stream.
- ///
- /// The item id.
- /// The audio container.
- /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.
- /// The streaming parameters.
- /// The tag.
- /// Optional. The dlna device profile id to utilize.
- /// The play session id.
- /// The segment container.
- /// The segment length.
- /// The minimum number of segments.
- /// The media version id, if playing an alternate version.
- /// The device id of the client requesting. Used to stop encoding processes when needed.
- /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.
- /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.
- /// Whether or not to allow copying of the video stream url.
- /// Whether or not to allow copying of the audio stream url.
- /// Optional. Whether to break on non key frames.
- /// Optional. Specify a specific audio sample rate, e.g. 44100.
- /// Optional. The maximum audio bit depth.
- /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.
- /// Optional. Specify a specific number of audio channels to encode to, e.g. 2.
- /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2.
- /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.
- /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.
- /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
- /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.
- /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false.
- /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.
- /// Optional. The fixed horizontal resolution of the encoded video.
- /// Optional. The fixed vertical resolution of the encoded video.
- /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.
- /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.
- /// Optional. Specify the subtitle delivery method.
- /// Optional.
- /// Optional. The maximum video bit depth.
- /// Optional. Whether to require avc.
- /// Optional. Whether to deinterlace the video.
- /// Optional. Whether to require a non anamporphic stream.
- /// Optional. The maximum number of audio channels to transcode.
- /// Optional. The limit of how many cpu cores to use.
- /// The live stream id.
- /// Optional. Whether to enable the MpegtsM2Ts mode.
- /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vp8, vp9, vpx (deprecated), wmv.
- /// Optional. Specify a subtitle codec to encode to.
- /// Optional. The transcoding reason.
- /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used.
- /// Optional. The index of the video stream to use. If omitted the first video stream will be used.
- /// Optional. The .
- /// Optional. The streaming options.
- /// Audio stream returned.
- /// A containing the audio file.
- [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")]
- [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesAudioFile]
- public async Task GetAudioStreamByContainer(
- [FromRoute, Required] Guid itemId,
- [FromRoute, Required] string container,
- [FromQuery] bool? @static,
- [FromQuery] string? @params,
- [FromQuery] string? tag,
- [FromQuery] string? deviceProfileId,
- [FromQuery] string? playSessionId,
- [FromQuery] string? segmentContainer,
- [FromQuery] int? segmentLength,
- [FromQuery] int? minSegments,
- [FromQuery] string? mediaSourceId,
- [FromQuery] string? deviceId,
- [FromQuery] string? audioCodec,
- [FromQuery] bool? enableAutoStreamCopy,
- [FromQuery] bool? allowVideoStreamCopy,
- [FromQuery] bool? allowAudioStreamCopy,
- [FromQuery] bool? breakOnNonKeyFrames,
- [FromQuery] int? audioSampleRate,
- [FromQuery] int? maxAudioBitDepth,
- [FromQuery] int? audioBitRate,
- [FromQuery] int? audioChannels,
- [FromQuery] int? maxAudioChannels,
- [FromQuery] string? profile,
- [FromQuery] string? level,
- [FromQuery] float? framerate,
- [FromQuery] float? maxFramerate,
- [FromQuery] bool? copyTimestamps,
- [FromQuery] long? startTimeTicks,
- [FromQuery] int? width,
- [FromQuery] int? height,
- [FromQuery] int? videoBitRate,
- [FromQuery] int? subtitleStreamIndex,
- [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
- [FromQuery] int? maxRefFrames,
- [FromQuery] int? maxVideoBitDepth,
- [FromQuery] bool? requireAvc,
- [FromQuery] bool? deInterlace,
- [FromQuery] bool? requireNonAnamorphic,
- [FromQuery] int? transcodingMaxAudioChannels,
- [FromQuery] int? cpuCoreLimit,
- [FromQuery] string? liveStreamId,
- [FromQuery] bool? enableMpegtsM2TsMode,
- [FromQuery] string? videoCodec,
- [FromQuery] string? subtitleCodec,
- [FromQuery] string? transcodeReasons,
- [FromQuery] int? audioStreamIndex,
- [FromQuery] int? videoStreamIndex,
- [FromQuery] EncodingContext? context,
- [FromQuery] Dictionary? streamOptions)
- {
- StreamingRequestDto streamingRequest = new StreamingRequestDto
- {
- Id = itemId,
- Container = container,
- Static = @static ?? false,
- Params = @params,
- Tag = tag,
- DeviceProfileId = deviceProfileId,
- PlaySessionId = playSessionId,
- SegmentContainer = segmentContainer,
- SegmentLength = segmentLength,
- MinSegments = minSegments,
- MediaSourceId = mediaSourceId,
- DeviceId = deviceId,
- AudioCodec = audioCodec,
- EnableAutoStreamCopy = enableAutoStreamCopy ?? true,
- AllowAudioStreamCopy = allowAudioStreamCopy ?? true,
- AllowVideoStreamCopy = allowVideoStreamCopy ?? true,
- BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false,
- AudioSampleRate = audioSampleRate,
- MaxAudioChannels = maxAudioChannels,
- AudioBitRate = audioBitRate,
- MaxAudioBitDepth = maxAudioBitDepth,
- AudioChannels = audioChannels,
- Profile = profile,
- Level = level,
- Framerate = framerate,
- MaxFramerate = maxFramerate,
- CopyTimestamps = copyTimestamps ?? false,
- StartTimeTicks = startTimeTicks,
- Width = width,
- Height = height,
- VideoBitRate = videoBitRate,
- SubtitleStreamIndex = subtitleStreamIndex,
- SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
- MaxRefFrames = maxRefFrames,
- MaxVideoBitDepth = maxVideoBitDepth,
- RequireAvc = requireAvc ?? false,
- DeInterlace = deInterlace ?? false,
- RequireNonAnamorphic = requireNonAnamorphic ?? false,
- TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
- CpuCoreLimit = cpuCoreLimit,
- LiveStreamId = liveStreamId,
- EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
- VideoCodec = videoCodec,
- SubtitleCodec = subtitleCodec,
- TranscodeReasons = transcodeReasons,
- AudioStreamIndex = audioStreamIndex,
- VideoStreamIndex = videoStreamIndex,
- Context = context ?? EncodingContext.Static,
- StreamOptions = streamOptions
- };
-
- return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
- }
+ return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false);
}
}
diff --git a/Jellyfin.Api/Controllers/BrandingController.cs b/Jellyfin.Api/Controllers/BrandingController.cs
index d3ea412015..3c2c4b4dbd 100644
--- a/Jellyfin.Api/Controllers/BrandingController.cs
+++ b/Jellyfin.Api/Controllers/BrandingController.cs
@@ -4,54 +4,53 @@ using MediaBrowser.Model.Branding;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Branding controller.
+///
+public class BrandingController : BaseJellyfinApiController
{
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
///
- /// Branding controller.
+ /// Initializes a new instance of the class.
///
- public class BrandingController : BaseJellyfinApiController
+ /// Instance of the interface.
+ public BrandingController(IServerConfigurationManager serverConfigurationManager)
{
- private readonly IServerConfigurationManager _serverConfigurationManager;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- public BrandingController(IServerConfigurationManager serverConfigurationManager)
- {
- _serverConfigurationManager = serverConfigurationManager;
- }
+ ///
+ /// Gets branding configuration.
+ ///
+ /// Branding configuration returned.
+ /// An containing the branding configuration.
+ [HttpGet("Configuration")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult GetBrandingOptions()
+ {
+ return _serverConfigurationManager.GetConfiguration("branding");
+ }
- ///
- /// Gets branding configuration.
- ///
- /// Branding configuration returned.
- /// An containing the branding configuration.
- [HttpGet("Configuration")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult GetBrandingOptions()
- {
- return _serverConfigurationManager.GetConfiguration("branding");
- }
-
- ///
- /// Gets branding css.
- ///
- /// Branding css returned.
- /// No branding css configured.
- ///
- /// An containing the branding css if exist,
- /// or a if the css is not configured.
- ///
- [HttpGet("Css")]
- [HttpGet("Css.css", Name = "GetBrandingCss_2")]
- [Produces("text/css")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult GetBrandingCss()
- {
- var options = _serverConfigurationManager.GetConfiguration("branding");
- return options.CustomCss ?? string.Empty;
- }
+ ///
+ /// Gets branding css.
+ ///
+ /// Branding css returned.
+ /// No branding css configured.
+ ///
+ /// An containing the branding css if exist,
+ /// or a if the css is not configured.
+ ///
+ [HttpGet("Css")]
+ [HttpGet("Css.css", Name = "GetBrandingCss_2")]
+ [Produces("text/css")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult GetBrandingCss()
+ {
+ var options = _serverConfigurationManager.GetConfiguration("branding");
+ return options.CustomCss ?? string.Empty;
}
}
diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs
index d5b589a3fa..573b7069c5 100644
--- a/Jellyfin.Api/Controllers/ChannelsController.cs
+++ b/Jellyfin.Api/Controllers/ChannelsController.cs
@@ -18,234 +18,233 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Channels Controller.
+///
+[Authorize(Policy = Policies.DefaultAuthorization)]
+public class ChannelsController : BaseJellyfinApiController
{
+ private readonly IChannelManager _channelManager;
+ private readonly IUserManager _userManager;
+
///
- /// Channels Controller.
+ /// Initializes a new instance of the class.
///
- [Authorize(Policy = Policies.DefaultAuthorization)]
- public class ChannelsController : BaseJellyfinApiController
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public ChannelsController(IChannelManager channelManager, IUserManager userManager)
{
- private readonly IChannelManager _channelManager;
- private readonly IUserManager _userManager;
+ _channelManager = channelManager;
+ _userManager = userManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- /// Instance of the interface.
- public ChannelsController(IChannelManager channelManager, IUserManager userManager)
+ ///
+ /// Gets available channels.
+ ///
+ /// User Id to filter by. Use to not filter by user.
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. Filter by channels that support getting latest items.
+ /// Optional. Filter by channels that support media deletion.
+ /// Optional. Filter by channels that are favorite.
+ /// Channels returned.
+ /// An containing the channels.
+ [HttpGet]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetChannels(
+ [FromQuery] Guid? userId,
+ [FromQuery] int? startIndex,
+ [FromQuery] int? limit,
+ [FromQuery] bool? supportsLatestItems,
+ [FromQuery] bool? supportsMediaDeletion,
+ [FromQuery] bool? isFavorite)
+ {
+ return _channelManager.GetChannels(new ChannelQuery
{
- _channelManager = channelManager;
- _userManager = userManager;
- }
+ Limit = limit,
+ StartIndex = startIndex,
+ UserId = userId ?? Guid.Empty,
+ SupportsLatestItems = supportsLatestItems,
+ SupportsMediaDeletion = supportsMediaDeletion,
+ IsFavorite = isFavorite
+ });
+ }
- ///
- /// Gets available channels.
- ///
- /// User Id to filter by. Use to not filter by user.
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. Filter by channels that support getting latest items.
- /// Optional. Filter by channels that support media deletion.
- /// Optional. Filter by channels that are favorite.
- /// Channels returned.
- /// An containing the channels.
- [HttpGet]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetChannels(
- [FromQuery] Guid? userId,
- [FromQuery] int? startIndex,
- [FromQuery] int? limit,
- [FromQuery] bool? supportsLatestItems,
- [FromQuery] bool? supportsMediaDeletion,
- [FromQuery] bool? isFavorite)
+ ///
+ /// Get all channel features.
+ ///
+ /// All channel features returned.
+ /// An containing the channel features.
+ [HttpGet("Features")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetAllChannelFeatures()
+ {
+ return _channelManager.GetAllChannelFeatures();
+ }
+
+ ///
+ /// Get channel features.
+ ///
+ /// Channel id.
+ /// Channel features returned.
+ /// An containing the channel features.
+ [HttpGet("{channelId}/Features")]
+ public ActionResult GetChannelFeatures([FromRoute, Required] Guid channelId)
+ {
+ return _channelManager.GetChannelFeatures(channelId);
+ }
+
+ ///
+ /// Get channel items.
+ ///
+ /// Channel Id.
+ /// Optional. Folder Id.
+ /// Optional. User Id.
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. Sort Order - Ascending,Descending.
+ /// Optional. Specify additional filters to apply.
+ /// Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.
+ /// Optional. Specify additional fields of information to return in the output.
+ /// Channel items returned.
+ ///
+ /// A representing the request to get the channel items.
+ /// The task result contains an containing the channel items.
+ ///
+ [HttpGet("{channelId}/Items")]
+ public async Task>> GetChannelItems(
+ [FromRoute, Required] Guid channelId,
+ [FromQuery] Guid? folderId,
+ [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))] string[] sortBy,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
+ {
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+
+ var query = new InternalItemsQuery(user)
{
- return _channelManager.GetChannels(new ChannelQuery
+ Limit = limit,
+ StartIndex = startIndex,
+ ChannelIds = new[] { channelId },
+ ParentId = folderId ?? Guid.Empty,
+ OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
+ DtoOptions = new DtoOptions { Fields = fields }
+ };
+
+ foreach (var filter in filters)
+ {
+ switch (filter)
{
- Limit = limit,
- StartIndex = startIndex,
- UserId = userId ?? Guid.Empty,
- SupportsLatestItems = supportsLatestItems,
- SupportsMediaDeletion = supportsMediaDeletion,
- IsFavorite = isFavorite
- });
- }
-
- ///
- /// Get all channel features.
- ///
- /// All channel features returned.
- /// An containing the channel features.
- [HttpGet("Features")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult> GetAllChannelFeatures()
- {
- return _channelManager.GetAllChannelFeatures();
- }
-
- ///
- /// Get channel features.
- ///
- /// Channel id.
- /// Channel features returned.
- /// An containing the channel features.
- [HttpGet("{channelId}/Features")]
- public ActionResult GetChannelFeatures([FromRoute, Required] Guid channelId)
- {
- return _channelManager.GetChannelFeatures(channelId);
- }
-
- ///
- /// Get channel items.
- ///
- /// Channel Id.
- /// Optional. Folder Id.
- /// Optional. User Id.
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. Sort Order - Ascending,Descending.
- /// Optional. Specify additional filters to apply.
- /// Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime.
- /// Optional. Specify additional fields of information to return in the output.
- /// Channel items returned.
- ///
- /// A representing the request to get the channel items.
- /// The task result contains an containing the channel items.
- ///
- [HttpGet("{channelId}/Items")]
- public async Task>> GetChannelItems(
- [FromRoute, Required] Guid channelId,
- [FromQuery] Guid? folderId,
- [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))] string[] sortBy,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
- {
- var user = userId is null || userId.Value.Equals(default)
- ? null
- : _userManager.GetUserById(userId.Value);
-
- var query = new InternalItemsQuery(user)
- {
- Limit = limit,
- StartIndex = startIndex,
- ChannelIds = new[] { channelId },
- ParentId = folderId ?? Guid.Empty,
- OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
- DtoOptions = new DtoOptions { Fields = fields }
- };
-
- foreach (var filter in filters)
- {
- switch (filter)
- {
- case ItemFilter.IsFolder:
- query.IsFolder = true;
- break;
- case ItemFilter.IsNotFolder:
- query.IsFolder = false;
- break;
- case ItemFilter.IsUnplayed:
- query.IsPlayed = false;
- break;
- case ItemFilter.IsPlayed:
- query.IsPlayed = true;
- break;
- case ItemFilter.IsFavorite:
- query.IsFavorite = true;
- break;
- case ItemFilter.IsResumable:
- query.IsResumable = true;
- break;
- case ItemFilter.Likes:
- query.IsLiked = true;
- break;
- case ItemFilter.Dislikes:
- query.IsLiked = false;
- break;
- case ItemFilter.IsFavoriteOrLikes:
- query.IsFavoriteOrLiked = true;
- break;
- }
+ case ItemFilter.IsFolder:
+ query.IsFolder = true;
+ break;
+ case ItemFilter.IsNotFolder:
+ query.IsFolder = false;
+ break;
+ case ItemFilter.IsUnplayed:
+ query.IsPlayed = false;
+ break;
+ case ItemFilter.IsPlayed:
+ query.IsPlayed = true;
+ break;
+ case ItemFilter.IsFavorite:
+ query.IsFavorite = true;
+ break;
+ case ItemFilter.IsResumable:
+ query.IsResumable = true;
+ break;
+ case ItemFilter.Likes:
+ query.IsLiked = true;
+ break;
+ case ItemFilter.Dislikes:
+ query.IsLiked = false;
+ break;
+ case ItemFilter.IsFavoriteOrLikes:
+ query.IsFavoriteOrLiked = true;
+ break;
}
-
- return await _channelManager.GetChannelItems(query, CancellationToken.None).ConfigureAwait(false);
}
- ///
- /// Gets latest channel items.
- ///
- /// Optional. User Id.
- /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
- /// Optional. The maximum number of records to return.
- /// Optional. Specify additional filters to apply.
- /// Optional. Specify additional fields of information to return in the output.
- /// Optional. Specify one or more channel id's, comma delimited.
- /// Latest channel items returned.
- ///
- /// A representing the request to get the latest channel items.
- /// The task result contains an containing the latest channel items.
- ///
- [HttpGet("Items/Latest")]
- public async Task>> GetLatestChannelItems(
- [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)
+ return await _channelManager.GetChannelItems(query, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Gets latest channel items.
+ ///
+ /// Optional. User Id.
+ /// Optional. The record index to start at. All items with a lower index will be dropped from the results.
+ /// Optional. The maximum number of records to return.
+ /// Optional. Specify additional filters to apply.
+ /// Optional. Specify additional fields of information to return in the output.
+ /// Optional. Specify one or more channel id's, comma delimited.
+ /// Latest channel items returned.
+ ///
+ /// A representing the request to get the latest channel items.
+ /// The task result contains an containing the latest channel items.
+ ///
+ [HttpGet("Items/Latest")]
+ public async Task>> GetLatestChannelItems(
+ [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)
+ {
+ var user = userId is null || userId.Value.Equals(default)
+ ? null
+ : _userManager.GetUserById(userId.Value);
+
+ var query = new InternalItemsQuery(user)
{
- var user = userId is null || userId.Value.Equals(default)
- ? null
- : _userManager.GetUserById(userId.Value);
+ Limit = limit,
+ StartIndex = startIndex,
+ ChannelIds = channelIds,
+ DtoOptions = new DtoOptions { Fields = fields }
+ };
- var query = new InternalItemsQuery(user)
+ foreach (var filter in filters)
+ {
+ switch (filter)
{
- Limit = limit,
- StartIndex = startIndex,
- ChannelIds = channelIds,
- DtoOptions = new DtoOptions { Fields = fields }
- };
-
- foreach (var filter in filters)
- {
- switch (filter)
- {
- case ItemFilter.IsFolder:
- query.IsFolder = true;
- break;
- case ItemFilter.IsNotFolder:
- query.IsFolder = false;
- break;
- case ItemFilter.IsUnplayed:
- query.IsPlayed = false;
- break;
- case ItemFilter.IsPlayed:
- query.IsPlayed = true;
- break;
- case ItemFilter.IsFavorite:
- query.IsFavorite = true;
- break;
- case ItemFilter.IsResumable:
- query.IsResumable = true;
- break;
- case ItemFilter.Likes:
- query.IsLiked = true;
- break;
- case ItemFilter.Dislikes:
- query.IsLiked = false;
- break;
- case ItemFilter.IsFavoriteOrLikes:
- query.IsFavoriteOrLiked = true;
- break;
- }
+ case ItemFilter.IsFolder:
+ query.IsFolder = true;
+ break;
+ case ItemFilter.IsNotFolder:
+ query.IsFolder = false;
+ break;
+ case ItemFilter.IsUnplayed:
+ query.IsPlayed = false;
+ break;
+ case ItemFilter.IsPlayed:
+ query.IsPlayed = true;
+ break;
+ case ItemFilter.IsFavorite:
+ query.IsFavorite = true;
+ break;
+ case ItemFilter.IsResumable:
+ query.IsResumable = true;
+ break;
+ case ItemFilter.Likes:
+ query.IsLiked = true;
+ break;
+ case ItemFilter.Dislikes:
+ query.IsLiked = false;
+ break;
+ case ItemFilter.IsFavoriteOrLikes:
+ query.IsFavoriteOrLiked = true;
+ break;
}
-
- return await _channelManager.GetLatestChannelItems(query, CancellationToken.None).ConfigureAwait(false);
}
+
+ return await _channelManager.GetLatestChannelItems(query, CancellationToken.None).ConfigureAwait(false);
}
}
diff --git a/Jellyfin.Api/Controllers/ClientLogController.cs b/Jellyfin.Api/Controllers/ClientLogController.cs
index ed073a687e..57c2071b88 100644
--- a/Jellyfin.Api/Controllers/ClientLogController.cs
+++ b/Jellyfin.Api/Controllers/ClientLogController.cs
@@ -11,71 +11,70 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Client log controller.
+///
+[Authorize(Policy = Policies.DefaultAuthorization)]
+public class ClientLogController : BaseJellyfinApiController
{
+ private const int MaxDocumentSize = 1_000_000;
+ private readonly IClientEventLogger _clientEventLogger;
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
///
- /// Client log controller.
+ /// Initializes a new instance of the class.
///
- [Authorize(Policy = Policies.DefaultAuthorization)]
- public class ClientLogController : BaseJellyfinApiController
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public ClientLogController(
+ IClientEventLogger clientEventLogger,
+ IServerConfigurationManager serverConfigurationManager)
{
- private const int MaxDocumentSize = 1_000_000;
- private readonly IClientEventLogger _clientEventLogger;
- private readonly IServerConfigurationManager _serverConfigurationManager;
+ _clientEventLogger = clientEventLogger;
+ _serverConfigurationManager = serverConfigurationManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- /// Instance of the interface.
- public ClientLogController(
- IClientEventLogger clientEventLogger,
- IServerConfigurationManager serverConfigurationManager)
+ ///
+ /// Upload a document.
+ ///
+ /// Document saved.
+ /// Event logging disabled.
+ /// Upload size too large.
+ /// Create response.
+ [HttpPost("Document")]
+ [ProducesResponseType(typeof(ClientLogDocumentResponseDto), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
+ [AcceptsFile(MediaTypeNames.Text.Plain)]
+ [RequestSizeLimit(MaxDocumentSize)]
+ public async Task> LogFile()
+ {
+ if (!_serverConfigurationManager.Configuration.AllowClientLogUpload)
{
- _clientEventLogger = clientEventLogger;
- _serverConfigurationManager = serverConfigurationManager;
+ return Forbid();
}
- ///
- /// Upload a document.
- ///
- /// Document saved.
- /// Event logging disabled.
- /// Upload size too large.
- /// Create response.
- [HttpPost("Document")]
- [ProducesResponseType(typeof(ClientLogDocumentResponseDto), StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- [ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
- [AcceptsFile(MediaTypeNames.Text.Plain)]
- [RequestSizeLimit(MaxDocumentSize)]
- public async Task> LogFile()
+ if (Request.ContentLength > MaxDocumentSize)
{
- if (!_serverConfigurationManager.Configuration.AllowClientLogUpload)
- {
- return Forbid();
- }
-
- if (Request.ContentLength > MaxDocumentSize)
- {
- // Manually validate to return proper status code.
- return StatusCode(StatusCodes.Status413PayloadTooLarge, $"Payload must be less than {MaxDocumentSize:N0} bytes");
- }
-
- var (clientName, clientVersion) = GetRequestInformation();
- var fileName = await _clientEventLogger.WriteDocumentAsync(clientName, clientVersion, Request.Body)
- .ConfigureAwait(false);
- return Ok(new ClientLogDocumentResponseDto(fileName));
+ // Manually validate to return proper status code.
+ return StatusCode(StatusCodes.Status413PayloadTooLarge, $"Payload must be less than {MaxDocumentSize:N0} bytes");
}
- private (string ClientName, string ClientVersion) GetRequestInformation()
- {
- var clientName = HttpContext.User.GetClient() ?? "unknown-client";
- var clientVersion = HttpContext.User.GetIsApiKey()
- ? "apikey"
- : HttpContext.User.GetVersion() ?? "unknown-version";
+ var (clientName, clientVersion) = GetRequestInformation();
+ var fileName = await _clientEventLogger.WriteDocumentAsync(clientName, clientVersion, Request.Body)
+ .ConfigureAwait(false);
+ return Ok(new ClientLogDocumentResponseDto(fileName));
+ }
- return (clientName, clientVersion);
- }
+ private (string ClientName, string ClientVersion) GetRequestInformation()
+ {
+ var clientName = HttpContext.User.GetClient() ?? "unknown-client";
+ var clientVersion = HttpContext.User.GetIsApiKey()
+ ? "apikey"
+ : HttpContext.User.GetVersion() ?? "unknown-version";
+
+ return (clientName, clientVersion);
}
}
diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs
index effc9ed7aa..5a4a9bf079 100644
--- a/Jellyfin.Api/Controllers/CollectionController.cs
+++ b/Jellyfin.Api/Controllers/CollectionController.cs
@@ -11,101 +11,100 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// The collection controller.
+///
+[Route("Collections")]
+[Authorize(Policy = Policies.DefaultAuthorization)]
+public class CollectionController : BaseJellyfinApiController
{
+ private readonly ICollectionManager _collectionManager;
+ private readonly IDtoService _dtoService;
+
///
- /// The collection controller.
+ /// Initializes a new instance of the class.
///
- [Route("Collections")]
- [Authorize(Policy = Policies.DefaultAuthorization)]
- public class CollectionController : BaseJellyfinApiController
+ /// Instance of interface.
+ /// Instance of interface.
+ public CollectionController(
+ ICollectionManager collectionManager,
+ IDtoService dtoService)
{
- private readonly ICollectionManager _collectionManager;
- private readonly IDtoService _dtoService;
+ _collectionManager = collectionManager;
+ _dtoService = dtoService;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of interface.
- /// Instance of interface.
- public CollectionController(
- ICollectionManager collectionManager,
- IDtoService dtoService)
+ ///
+ /// Creates a new collection.
+ ///
+ /// The name of the collection.
+ /// Item Ids to add to the collection.
+ /// Optional. Create the collection within a specific folder.
+ /// Whether or not to lock the new collection.
+ /// Collection created.
+ /// A with information about the new collection.
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task> CreateCollection(
+ [FromQuery] string? name,
+ [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] ids,
+ [FromQuery] Guid? parentId,
+ [FromQuery] bool isLocked = false)
+ {
+ var userId = User.GetUserId();
+
+ var item = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
{
- _collectionManager = collectionManager;
- _dtoService = dtoService;
- }
+ IsLocked = isLocked,
+ Name = name,
+ ParentId = parentId,
+ ItemIdList = ids,
+ UserIds = new[] { userId }
+ }).ConfigureAwait(false);
- ///
- /// Creates a new collection.
- ///
- /// The name of the collection.
- /// Item Ids to add to the collection.
- /// Optional. Create the collection within a specific folder.
- /// Whether or not to lock the new collection.
- /// Collection created.
- /// A with information about the new collection.
- [HttpPost]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public async Task> CreateCollection(
- [FromQuery] string? name,
- [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] ids,
- [FromQuery] Guid? parentId,
- [FromQuery] bool isLocked = false)
+ var dtoOptions = new DtoOptions().AddClientFields(User);
+
+ var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
+
+ return new CollectionCreationResult
{
- var userId = User.GetUserId();
+ Id = dto.Id
+ };
+ }
- var item = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
- {
- IsLocked = isLocked,
- Name = name,
- ParentId = parentId,
- ItemIdList = ids,
- UserIds = new[] { userId }
- }).ConfigureAwait(false);
+ ///
+ /// Adds items to a collection.
+ ///
+ /// The collection id.
+ /// Item ids, comma delimited.
+ /// Items added to collection.
+ /// A indicating success.
+ [HttpPost("{collectionId}/Items")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public async Task AddToCollection(
+ [FromRoute, Required] Guid collectionId,
+ [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
+ {
+ await _collectionManager.AddToCollectionAsync(collectionId, ids).ConfigureAwait(true);
+ return NoContent();
+ }
- var dtoOptions = new DtoOptions().AddClientFields(User);
-
- var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
-
- return new CollectionCreationResult
- {
- Id = dto.Id
- };
- }
-
- ///
- /// Adds items to a collection.
- ///
- /// The collection id.
- /// Item ids, comma delimited.
- /// Items added to collection.
- /// A indicating success.
- [HttpPost("{collectionId}/Items")]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task AddToCollection(
- [FromRoute, Required] Guid collectionId,
- [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
- {
- await _collectionManager.AddToCollectionAsync(collectionId, ids).ConfigureAwait(true);
- return NoContent();
- }
-
- ///
- /// Removes items from a collection.
- ///
- /// The collection id.
- /// Item ids, comma delimited.
- /// Items removed from collection.
- /// A indicating success.
- [HttpDelete("{collectionId}/Items")]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public async Task RemoveFromCollection(
- [FromRoute, Required] Guid collectionId,
- [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
- {
- await _collectionManager.RemoveFromCollectionAsync(collectionId, ids).ConfigureAwait(false);
- return NoContent();
- }
+ ///
+ /// Removes items from a collection.
+ ///
+ /// The collection id.
+ /// Item ids, comma delimited.
+ /// Items removed from collection.
+ /// A indicating success.
+ [HttpDelete("{collectionId}/Items")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public async Task RemoveFromCollection(
+ [FromRoute, Required] Guid collectionId,
+ [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids)
+ {
+ await _collectionManager.RemoveFromCollectionAsync(collectionId, ids).ConfigureAwait(false);
+ return NoContent();
}
}
diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs
index a00ac1b0af..d53d7cefd0 100644
--- a/Jellyfin.Api/Controllers/ConfigurationController.cs
+++ b/Jellyfin.Api/Controllers/ConfigurationController.cs
@@ -13,124 +13,123 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace Jellyfin.Api.Controllers
+namespace Jellyfin.Api.Controllers;
+
+///
+/// Configuration Controller.
+///
+[Route("System")]
+[Authorize(Policy = Policies.DefaultAuthorization)]
+public class ConfigurationController : BaseJellyfinApiController
{
+ private readonly IServerConfigurationManager _configurationManager;
+ private readonly IMediaEncoder _mediaEncoder;
+
+ private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.Options;
+
///
- /// Configuration Controller.
+ /// Initializes a new instance of the class.
///
- [Route("System")]
- [Authorize(Policy = Policies.DefaultAuthorization)]
- public class ConfigurationController : BaseJellyfinApiController
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public ConfigurationController(
+ IServerConfigurationManager configurationManager,
+ IMediaEncoder mediaEncoder)
{
- private readonly IServerConfigurationManager _configurationManager;
- private readonly IMediaEncoder _mediaEncoder;
+ _configurationManager = configurationManager;
+ _mediaEncoder = mediaEncoder;
+ }
- private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.Options;
+ ///
+ /// Gets application configuration.
+ ///
+ /// Application configuration returned.
+ /// Application configuration.
+ [HttpGet("Configuration")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult GetConfiguration()
+ {
+ return _configurationManager.Configuration;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- /// Instance of the interface.
- public ConfigurationController(
- IServerConfigurationManager configurationManager,
- IMediaEncoder mediaEncoder)
+ ///
+ /// Updates application configuration.
+ ///
+ /// Configuration.
+ /// Configuration updated.
+ /// Update status.
+ [HttpPost("Configuration")]
+ [Authorize(Policy = Policies.RequiresElevation)]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult UpdateConfiguration([FromBody, Required] ServerConfiguration configuration)
+ {
+ _configurationManager.ReplaceConfiguration(configuration);
+ return NoContent();
+ }
+
+ ///
+ /// Gets a named configuration.
+ ///
+ /// Configuration key.
+ /// Configuration returned.
+ /// Configuration.
+ [HttpGet("Configuration/{key}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesFile(MediaTypeNames.Application.Json)]
+ public ActionResult