mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Merge pull request #4069 from crobibero/api-route-required
Make all FromRoute required
This commit is contained in:
		
						commit
						99bbbea9e2
					
				@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
using Jellyfin.Api.Helpers;
 | 
			
		||||
@ -52,7 +53,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Albums/{albumId}/Similar")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetSimilarAlbums(
 | 
			
		||||
            [FromRoute] string albumId,
 | 
			
		||||
            [FromRoute, Required] string albumId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] string? excludeArtistIds,
 | 
			
		||||
            [FromQuery] int? limit)
 | 
			
		||||
@ -84,7 +85,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Artists/{artistId}/Similar")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetSimilarArtists(
 | 
			
		||||
            [FromRoute] string artistId,
 | 
			
		||||
            [FromRoute, Required] string artistId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] string? excludeArtistIds,
 | 
			
		||||
            [FromQuery] int? limit)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
@ -469,7 +470,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the artist.</returns>
 | 
			
		||||
        [HttpGet("{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetArtistByName([FromRoute] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var dtoOptions = new DtoOptions().AddClientFields(Request);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Api.Helpers;
 | 
			
		||||
using Jellyfin.Api.Models.StreamingDtos;
 | 
			
		||||
@ -89,8 +90,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpHead("{itemId}/stream", Name = "HeadAudioStream")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetAudioStream(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@ -90,7 +91,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <response code="200">Channel features returned.</response>
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the channel features.</returns>
 | 
			
		||||
        [HttpGet("{channelId}/Features")]
 | 
			
		||||
        public ActionResult<ChannelFeatures> GetChannelFeatures([FromRoute] string channelId)
 | 
			
		||||
        public ActionResult<ChannelFeatures> GetChannelFeatures([FromRoute, Required] string channelId)
 | 
			
		||||
        {
 | 
			
		||||
            return _channelManager.GetChannelFeatures(channelId);
 | 
			
		||||
        }
 | 
			
		||||
@ -114,7 +115,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// </returns>
 | 
			
		||||
        [HttpGet("{channelId}/Items")]
 | 
			
		||||
        public async Task<ActionResult<QueryResult<BaseItemDto>>> GetChannelItems(
 | 
			
		||||
            [FromRoute] Guid channelId,
 | 
			
		||||
            [FromRoute, Required] Guid channelId,
 | 
			
		||||
            [FromQuery] Guid? folderId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? startIndex,
 | 
			
		||||
 | 
			
		||||
@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 | 
			
		||||
        [HttpPost("{collectionId}/Items")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> AddToCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds)
 | 
			
		||||
        public async Task<ActionResult> AddToCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string? itemIds)
 | 
			
		||||
        {
 | 
			
		||||
            await _collectionManager.AddToCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(true);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
@ -103,7 +103,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 | 
			
		||||
        [HttpDelete("{collectionId}/Items")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds)
 | 
			
		||||
        public async Task<ActionResult> RemoveFromCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string? itemIds)
 | 
			
		||||
        {
 | 
			
		||||
            await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(false);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
 | 
			
		||||
@ -73,7 +73,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>Configuration.</returns>
 | 
			
		||||
        [HttpGet("Configuration/{key}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<object> GetNamedConfiguration([FromRoute] string? key)
 | 
			
		||||
        public ActionResult<object> GetNamedConfiguration([FromRoute, Required] string? key)
 | 
			
		||||
        {
 | 
			
		||||
            return _configurationManager.GetConfiguration(key);
 | 
			
		||||
        }
 | 
			
		||||
@ -87,7 +87,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Configuration/{key}")]
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> UpdateNamedConfiguration([FromRoute] string? key)
 | 
			
		||||
        public async Task<ActionResult> UpdateNamedConfiguration([FromRoute, Required] string? key)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationType = _configurationManager.GetConfigurationType(key);
 | 
			
		||||
            var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public ActionResult<DisplayPreferencesDto> GetDisplayPreferences(
 | 
			
		||||
            [FromRoute] string? displayPreferencesId,
 | 
			
		||||
            [FromRoute, Required] string? displayPreferencesId,
 | 
			
		||||
            [FromQuery] [Required] Guid userId,
 | 
			
		||||
            [FromQuery] [Required] string? client)
 | 
			
		||||
        {
 | 
			
		||||
@ -97,7 +97,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public ActionResult UpdateDisplayPreferences(
 | 
			
		||||
            [FromRoute] string? displayPreferencesId,
 | 
			
		||||
            [FromRoute, Required] string? displayPreferencesId,
 | 
			
		||||
            [FromQuery, Required] Guid userId,
 | 
			
		||||
            [FromQuery, Required] string? client,
 | 
			
		||||
            [FromBody, Required] DisplayPreferencesDto displayPreferences)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
using MediaBrowser.Controller.Dlna;
 | 
			
		||||
using MediaBrowser.Model.Dlna;
 | 
			
		||||
@ -59,7 +60,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Profiles/{profileId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<DeviceProfile> GetProfile([FromRoute] string profileId)
 | 
			
		||||
        public ActionResult<DeviceProfile> GetProfile([FromRoute, Required] string profileId)
 | 
			
		||||
        {
 | 
			
		||||
            var profile = _dlnaManager.GetProfile(profileId);
 | 
			
		||||
            if (profile == null)
 | 
			
		||||
@ -80,7 +81,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpDelete("Profiles/{profileId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult DeleteProfile([FromRoute] string profileId)
 | 
			
		||||
        public ActionResult DeleteProfile([FromRoute, Required] string profileId)
 | 
			
		||||
        {
 | 
			
		||||
            var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
 | 
			
		||||
            if (existingDeviceProfile == null)
 | 
			
		||||
@ -117,7 +118,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Profiles/{profileId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult UpdateProfile([FromRoute] string profileId, [FromBody] DeviceProfile deviceProfile)
 | 
			
		||||
        public ActionResult UpdateProfile([FromRoute, Required] string profileId, [FromBody] DeviceProfile deviceProfile)
 | 
			
		||||
        {
 | 
			
		||||
            var existingDeviceProfile = _dlnaManager.GetProfile(profileId);
 | 
			
		||||
            if (existingDeviceProfile == null)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net.Mime;
 | 
			
		||||
@ -45,7 +46,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("{serverId}/description.xml", Name = "GetDescriptionXml_2")]
 | 
			
		||||
        [Produces(MediaTypeNames.Text.Xml)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult GetDescriptionXml([FromRoute] string serverId)
 | 
			
		||||
        public ActionResult GetDescriptionXml([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            var url = GetAbsoluteUri();
 | 
			
		||||
            var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
 | 
			
		||||
@ -65,7 +66,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Produces(MediaTypeNames.Text.Xml)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
 | 
			
		||||
        public ActionResult GetContentDirectory([FromRoute] string serverId)
 | 
			
		||||
        public ActionResult GetContentDirectory([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return Ok(_contentDirectory.GetServiceXml());
 | 
			
		||||
        }
 | 
			
		||||
@ -81,7 +82,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Produces(MediaTypeNames.Text.Xml)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
 | 
			
		||||
        public ActionResult GetMediaReceiverRegistrar([FromRoute] string serverId)
 | 
			
		||||
        public ActionResult GetMediaReceiverRegistrar([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return Ok(_mediaReceiverRegistrar.GetServiceXml());
 | 
			
		||||
        }
 | 
			
		||||
@ -97,7 +98,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Produces(MediaTypeNames.Text.Xml)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
 | 
			
		||||
        public ActionResult GetConnectionManager([FromRoute] string serverId)
 | 
			
		||||
        public ActionResult GetConnectionManager([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return Ok(_connectionManager.GetServiceXml());
 | 
			
		||||
        }
 | 
			
		||||
@ -108,7 +109,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <param name="serverId">Server UUID.</param>
 | 
			
		||||
        /// <returns>Control response.</returns>
 | 
			
		||||
        [HttpPost("{serverId}/ContentDirectory/Control")]
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessContentDirectoryControlRequest([FromRoute] string serverId)
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessContentDirectoryControlRequest([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return await ProcessControlRequestInternalAsync(serverId, Request.Body, _contentDirectory).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@ -119,7 +120,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <param name="serverId">Server UUID.</param>
 | 
			
		||||
        /// <returns>Control response.</returns>
 | 
			
		||||
        [HttpPost("{serverId}/ConnectionManager/Control")]
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessConnectionManagerControlRequest([FromRoute] string serverId)
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessConnectionManagerControlRequest([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return await ProcessControlRequestInternalAsync(serverId, Request.Body, _connectionManager).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@ -130,7 +131,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <param name="serverId">Server UUID.</param>
 | 
			
		||||
        /// <returns>Control response.</returns>
 | 
			
		||||
        [HttpPost("{serverId}/MediaReceiverRegistrar/Control")]
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessMediaReceiverRegistrarControlRequest([FromRoute] string serverId)
 | 
			
		||||
        public async Task<ActionResult<ControlResponse>> ProcessMediaReceiverRegistrarControlRequest([FromRoute, Required] string serverId)
 | 
			
		||||
        {
 | 
			
		||||
            return await ProcessControlRequestInternalAsync(serverId, Request.Body, _mediaReceiverRegistrar).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@ -185,7 +186,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>Icon stream.</returns>
 | 
			
		||||
        [HttpGet("{serverId}/icons/{fileName}")]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
 | 
			
		||||
        public ActionResult GetIconId([FromRoute] string serverId, [FromRoute] string fileName)
 | 
			
		||||
        public ActionResult GetIconId([FromRoute, Required] string serverId, [FromRoute, Required] string fileName)
 | 
			
		||||
        {
 | 
			
		||||
            return GetIconInternal(fileName);
 | 
			
		||||
        }
 | 
			
		||||
@ -196,7 +197,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <param name="fileName">The icon filename.</param>
 | 
			
		||||
        /// <returns>Icon stream.</returns>
 | 
			
		||||
        [HttpGet("icons/{fileName}")]
 | 
			
		||||
        public ActionResult GetIcon([FromRoute] string fileName)
 | 
			
		||||
        public ActionResult GetIcon([FromRoute, Required] string fileName)
 | 
			
		||||
        {
 | 
			
		||||
            return GetIconInternal(fileName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -167,8 +167,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpHead("Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetMasterHlsVideoPlaylist(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
@ -334,8 +334,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpHead("Audio/{itemId}/master.m3u8", Name = "HeadMasterHlsAudioPlaylist")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetMasterHlsAudioPlaylist(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
@ -499,8 +499,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Videos/{itemId}/main.m3u8")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetVariantHlsVideoPlaylist(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
@ -664,8 +664,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Audio/{itemId}/main.m3u8")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetVariantHlsAudioPlaylist(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
@ -832,10 +832,10 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> GetHlsVideoSegment(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string playlistId,
 | 
			
		||||
            [FromRoute] int segmentId,
 | 
			
		||||
            [FromRoute] string container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string playlistId,
 | 
			
		||||
            [FromRoute, Required] int segmentId,
 | 
			
		||||
            [FromRoute, Required] string container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
@ -1001,10 +1001,10 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> GetHlsAudioSegment(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string playlistId,
 | 
			
		||||
            [FromRoute] int segmentId,
 | 
			
		||||
            [FromRoute] string container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string playlistId,
 | 
			
		||||
            [FromRoute, Required] int segmentId,
 | 
			
		||||
            [FromRoute, Required] string container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
@ -260,7 +261,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the genre.</returns>
 | 
			
		||||
        [HttpGet("{genreName}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetGenre([FromRoute] string genreName, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var dtoOptions = new DtoOptions()
 | 
			
		||||
                .AddClientFields(Request);
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
@ -55,7 +56,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public ActionResult GetHlsAudioSegmentLegacy([FromRoute] string itemId, [FromRoute] string segmentId)
 | 
			
		||||
        public ActionResult GetHlsAudioSegmentLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string segmentId)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO: Deprecate with new iOS app
 | 
			
		||||
            var file = segmentId + Path.GetExtension(Request.Path);
 | 
			
		||||
@ -75,7 +76,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public ActionResult GetHlsPlaylistLegacy([FromRoute] string itemId, [FromRoute] string playlistId)
 | 
			
		||||
        public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
 | 
			
		||||
        {
 | 
			
		||||
            var file = playlistId + Path.GetExtension(Request.Path);
 | 
			
		||||
            file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
 | 
			
		||||
@ -114,10 +115,10 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public ActionResult GetHlsVideoSegmentLegacy(
 | 
			
		||||
            [FromRoute] string itemId,
 | 
			
		||||
            [FromRoute] string playlistId,
 | 
			
		||||
            [FromRoute] string segmentId,
 | 
			
		||||
            [FromRoute] string segmentContainer)
 | 
			
		||||
            [FromRoute, Required] string itemId,
 | 
			
		||||
            [FromRoute, Required] string playlistId,
 | 
			
		||||
            [FromRoute, Required] string segmentId,
 | 
			
		||||
            [FromRoute, Required] string segmentContainer)
 | 
			
		||||
        {
 | 
			
		||||
            var file = segmentId + Path.GetExtension(Request.Path);
 | 
			
		||||
            var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
@ -90,9 +91,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> PostUserImage(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? index = null)
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? index = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
 | 
			
		||||
            {
 | 
			
		||||
@ -137,9 +138,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        public ActionResult DeleteUserImage(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? index = null)
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? index = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
 | 
			
		||||
            {
 | 
			
		||||
@ -175,9 +176,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> DeleteItemImage(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -205,9 +206,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> SetItemImage(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -238,9 +239,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> UpdateItemImageIndex(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int imageIndex,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int imageIndex,
 | 
			
		||||
            [FromQuery] int newIndex)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
@ -264,7 +265,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult<IEnumerable<ImageInfo>>> GetItemImageInfos([FromRoute] Guid itemId)
 | 
			
		||||
        public async Task<ActionResult<IEnumerable<ImageInfo>>> GetItemImageInfos([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -352,10 +353,10 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetItemImage(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -368,7 +369,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -430,23 +431,23 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetItemImage2(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromQuery] bool? cropWhitespace,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromQuery] bool? addPlayedIndicator,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -508,14 +509,14 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetArtistImage(
 | 
			
		||||
            [FromRoute] string name,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] string name,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -524,7 +525,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetArtist(name);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -586,14 +587,14 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetGenreImage(
 | 
			
		||||
            [FromRoute] string name,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] string name,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -602,7 +603,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetGenre(name);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -664,14 +665,14 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetMusicGenreImage(
 | 
			
		||||
            [FromRoute] string name,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] string name,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -680,7 +681,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetMusicGenre(name);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -742,14 +743,14 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetPersonImage(
 | 
			
		||||
            [FromRoute] string name,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] string name,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -758,7 +759,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetPerson(name);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -820,14 +821,14 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetStudioImage(
 | 
			
		||||
            [FromRoute] string name,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute] string tag,
 | 
			
		||||
            [FromRoute] string format,
 | 
			
		||||
            [FromRoute] int? maxWidth,
 | 
			
		||||
            [FromRoute] int? maxHeight,
 | 
			
		||||
            [FromRoute] double? percentPlayed,
 | 
			
		||||
            [FromRoute] int? unplayedCount,
 | 
			
		||||
            [FromRoute, Required] string name,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] string tag,
 | 
			
		||||
            [FromRoute, Required] string format,
 | 
			
		||||
            [FromRoute, Required] int? maxWidth,
 | 
			
		||||
            [FromRoute, Required] int? maxHeight,
 | 
			
		||||
            [FromRoute, Required] double? percentPlayed,
 | 
			
		||||
            [FromRoute, Required] int? unplayedCount,
 | 
			
		||||
            [FromQuery] int? width,
 | 
			
		||||
            [FromQuery] int? height,
 | 
			
		||||
            [FromQuery] int? quality,
 | 
			
		||||
@ -836,7 +837,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetStudio(name);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -898,8 +899,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetUserImage(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] ImageType imageType,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] ImageType imageType,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
            [FromQuery] string? format,
 | 
			
		||||
            [FromQuery] int? maxWidth,
 | 
			
		||||
@ -914,7 +915,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] int? blur,
 | 
			
		||||
            [FromQuery] string? backgroundColor,
 | 
			
		||||
            [FromQuery] string? foregroundLayer,
 | 
			
		||||
            [FromRoute] int? imageIndex = null)
 | 
			
		||||
            [FromRoute, Required] int? imageIndex = null)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
            if (user == null)
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Songs/{id}/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromSong(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Albums/{id}/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromAlbum(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
@ -138,7 +138,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Playlists/{id}/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromPlaylist(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Artists/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
@ -248,7 +248,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("MusicGenres/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
@ -285,7 +285,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Items/{id}/InstantMix")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromItem(
 | 
			
		||||
            [FromRoute] Guid id,
 | 
			
		||||
            [FromRoute, Required] Guid id,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<IEnumerable<ExternalIdInfo>> GetExternalIdInfos([FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<IEnumerable<ExternalIdInfo>> GetExternalIdInfos([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -294,7 +294,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Items/RemoteSearch/Apply/{id}")]
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        public async Task<ActionResult> ApplySearchCriteria(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromBody, Required] RemoteSearchResult searchResult,
 | 
			
		||||
            [FromQuery] bool replaceAllImages = true)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
using MediaBrowser.Controller.Library;
 | 
			
		||||
using MediaBrowser.Controller.Providers;
 | 
			
		||||
@ -53,7 +54,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult Post(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] MetadataRefreshMode metadataRefreshMode = MetadataRefreshMode.None,
 | 
			
		||||
            [FromQuery] MetadataRefreshMode imageRefreshMode = MetadataRefreshMode.None,
 | 
			
		||||
            [FromQuery] bool replaceAllMetadata = false,
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Items/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> UpdateItem([FromRoute] Guid itemId, [FromBody, Required] BaseItemDto request)
 | 
			
		||||
        public async Task<ActionResult> UpdateItem([FromRoute, Required] Guid itemId, [FromBody, Required] BaseItemDto request)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -141,7 +141,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Items/{itemId}/MetadataEditor")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<MetadataEditorInfo> GetMetadataEditorInfo([FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<MetadataEditorInfo> GetMetadataEditorInfo([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
 | 
			
		||||
@ -195,7 +195,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Items/{itemId}/ContentType")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult UpdateItemContentType([FromRoute] Guid itemId, [FromQuery, Required] string? contentType)
 | 
			
		||||
        public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery, Required] string? contentType)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
@ -144,7 +145,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{uId}/Items", Name = "GetItems_2")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetItems(
 | 
			
		||||
            [FromRoute] Guid? uId,
 | 
			
		||||
            [FromRoute, Required] Guid? uId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] string? maxOfficialRating,
 | 
			
		||||
            [FromQuery] bool? hasThemeSong,
 | 
			
		||||
@ -529,7 +530,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/Resume")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetResumeItems(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromQuery] int? startIndex,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
            [FromQuery] string? searchTerm,
 | 
			
		||||
 | 
			
		||||
@ -104,7 +104,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult GetFile([FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult GetFile([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -144,7 +144,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<ThemeMediaResult> GetThemeSongs(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] bool inheritFromParent = false)
 | 
			
		||||
        {
 | 
			
		||||
@ -210,7 +210,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<ThemeMediaResult> GetThemeVideos(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] bool inheritFromParent = false)
 | 
			
		||||
        {
 | 
			
		||||
@ -275,7 +275,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<AllThemeMediaResult> GetThemeMedia(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] bool inheritFromParent = false)
 | 
			
		||||
        {
 | 
			
		||||
@ -438,7 +438,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute] Guid itemId, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
 | 
			
		||||
@ -555,7 +555,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Library/Movies/Updated")]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public ActionResult PostUpdatedMovies([FromRoute] string? tmdbId, [FromRoute] string? imdbId)
 | 
			
		||||
        public ActionResult PostUpdatedMovies([FromRoute, Required] string? tmdbId, [FromRoute, Required] string? imdbId)
 | 
			
		||||
        {
 | 
			
		||||
            var movies = _libraryManager.GetItemList(new InternalItemsQuery
 | 
			
		||||
            {
 | 
			
		||||
@ -618,7 +618,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.Download)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetDownload([FromRoute] Guid itemId)
 | 
			
		||||
        public async Task<ActionResult> GetDownload([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -687,7 +687,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetSimilarItems(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] string? excludeArtistIds,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
@ -209,7 +210,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Channels/{channelId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetChannel([FromRoute] Guid channelId, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
 | 
			
		||||
                ? _userManager.GetUserById(userId.Value)
 | 
			
		||||
@ -406,7 +407,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Recordings/{recordingId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRecording([FromRoute] Guid recordingId, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
 | 
			
		||||
                ? _userManager.GetUserById(userId.Value)
 | 
			
		||||
@ -428,7 +429,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Tuners/{tunerId}/Reset")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        public ActionResult ResetTuner([FromRoute] string tunerId)
 | 
			
		||||
        public ActionResult ResetTuner([FromRoute, Required] string tunerId)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
            _liveTvManager.ResetTuner(tunerId, CancellationToken.None);
 | 
			
		||||
@ -744,7 +745,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<BaseItemDto>> GetProgram(
 | 
			
		||||
            [FromRoute] string programId,
 | 
			
		||||
            [FromRoute, Required] string programId,
 | 
			
		||||
            [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
 | 
			
		||||
@ -765,7 +766,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult DeleteRecording([FromRoute] Guid recordingId)
 | 
			
		||||
        public ActionResult DeleteRecording([FromRoute, Required] Guid recordingId)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
 | 
			
		||||
@ -792,7 +793,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpDelete("Timers/{timerId}")]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> CancelTimer([FromRoute] string timerId)
 | 
			
		||||
        public async Task<ActionResult> CancelTimer([FromRoute, Required] string timerId)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
            await _liveTvManager.CancelTimer(timerId).ConfigureAwait(false);
 | 
			
		||||
@ -810,7 +811,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "timerId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> UpdateTimer([FromRoute] string timerId, [FromBody] TimerInfoDto timerInfo)
 | 
			
		||||
        public async Task<ActionResult> UpdateTimer([FromRoute, Required] string timerId, [FromBody] TimerInfoDto timerInfo)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
            await _liveTvManager.UpdateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false);
 | 
			
		||||
@ -844,7 +845,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult<SeriesTimerInfoDto>> GetSeriesTimer([FromRoute] string timerId)
 | 
			
		||||
        public async Task<ActionResult<SeriesTimerInfoDto>> GetSeriesTimer([FromRoute, Required] string timerId)
 | 
			
		||||
        {
 | 
			
		||||
            var timer = await _liveTvManager.GetSeriesTimer(timerId, CancellationToken.None).ConfigureAwait(false);
 | 
			
		||||
            if (timer == null)
 | 
			
		||||
@ -884,7 +885,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpDelete("SeriesTimers/{timerId}")]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> CancelSeriesTimer([FromRoute] string timerId)
 | 
			
		||||
        public async Task<ActionResult> CancelSeriesTimer([FromRoute, Required] string timerId)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
            await _liveTvManager.CancelSeriesTimer(timerId).ConfigureAwait(false);
 | 
			
		||||
@ -902,7 +903,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "timerId", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> UpdateSeriesTimer([FromRoute] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo)
 | 
			
		||||
        public async Task<ActionResult> UpdateSeriesTimer([FromRoute, Required] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo)
 | 
			
		||||
        {
 | 
			
		||||
            AssertUserCanManageLiveTv();
 | 
			
		||||
            await _liveTvManager.UpdateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false);
 | 
			
		||||
@ -934,7 +935,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        [Obsolete("This endpoint is obsolete.")]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRecordingGroup([FromRoute] Guid? groupId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRecordingGroup([FromRoute, Required] Guid? groupId)
 | 
			
		||||
        {
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        }
 | 
			
		||||
@ -1176,7 +1177,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("LiveRecordings/{recordingId}/stream")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetLiveRecordingFile([FromRoute] string recordingId)
 | 
			
		||||
        public async Task<ActionResult> GetLiveRecordingFile([FromRoute, Required] string recordingId)
 | 
			
		||||
        {
 | 
			
		||||
            var path = _liveTvManager.GetEmbyTvActiveRecordingPath(recordingId);
 | 
			
		||||
 | 
			
		||||
@ -1206,7 +1207,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("LiveStreamFiles/{streamId}/stream.{container}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> GetLiveStreamFile([FromRoute] string streamId, [FromRoute] string container)
 | 
			
		||||
        public async Task<ActionResult> GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container)
 | 
			
		||||
        {
 | 
			
		||||
            var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false);
 | 
			
		||||
            if (liveStreamInfo == null)
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>A <see cref="Task"/> containing a <see cref="PlaybackInfoResponse"/> with the playback information.</returns>
 | 
			
		||||
        [HttpGet("Items/{itemId}/PlaybackInfo")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery, Required] Guid? userId)
 | 
			
		||||
        public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute, Required] Guid itemId, [FromQuery, Required] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            return await _mediaInfoHelper.GetPlaybackInfo(
 | 
			
		||||
                    itemId,
 | 
			
		||||
@ -100,7 +100,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Items/{itemId}/PlaybackInfo")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<PlaybackInfoResponse>> GetPostedPlaybackInfo(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
            [FromQuery] long? maxStreamingBitrate,
 | 
			
		||||
            [FromQuery] long? startTimeTicks,
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
@ -258,7 +259,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns>
 | 
			
		||||
        [HttpGet("{genreName}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetMusicGenre([FromRoute] string genreName, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var dtoOptions = new DtoOptions().AddClientFields(Request);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Packages/{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<PackageInfo>> GetPackageInfo(
 | 
			
		||||
            [FromRoute] [Required] string? name,
 | 
			
		||||
            [FromRoute, Required] string? name,
 | 
			
		||||
            [FromQuery] string? assemblyGuid)
 | 
			
		||||
        {
 | 
			
		||||
            var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
 | 
			
		||||
@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        public async Task<ActionResult> InstallPackage(
 | 
			
		||||
            [FromRoute] [Required] string? name,
 | 
			
		||||
            [FromRoute, Required] string? name,
 | 
			
		||||
            [FromQuery] string? assemblyGuid,
 | 
			
		||||
            [FromQuery] string? version)
 | 
			
		||||
        {
 | 
			
		||||
@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public ActionResult CancelPackageInstallation(
 | 
			
		||||
            [FromRoute] [Required] Guid packageId)
 | 
			
		||||
            [FromRoute, Required] Guid packageId)
 | 
			
		||||
        {
 | 
			
		||||
            _installationManager.CancelInstallation(packageId);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
@ -262,7 +263,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetPerson([FromRoute] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var dtoOptions = new DtoOptions()
 | 
			
		||||
                .AddClientFields(Request);
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("{playlistId}/Items")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> AddToPlaylist(
 | 
			
		||||
            [FromRoute] Guid playlistId,
 | 
			
		||||
            [FromRoute, Required] Guid playlistId,
 | 
			
		||||
            [FromQuery] string? ids,
 | 
			
		||||
            [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
@ -103,9 +103,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> MoveItem(
 | 
			
		||||
            [FromRoute] string? playlistId,
 | 
			
		||||
            [FromRoute] string? itemId,
 | 
			
		||||
            [FromRoute] int newIndex)
 | 
			
		||||
            [FromRoute, Required] string? playlistId,
 | 
			
		||||
            [FromRoute, Required] string? itemId,
 | 
			
		||||
            [FromRoute, Required] int newIndex)
 | 
			
		||||
        {
 | 
			
		||||
            await _playlistManager.MoveItemAsync(playlistId, itemId, newIndex).ConfigureAwait(false);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="NoContentResult"/> on success.</returns>
 | 
			
		||||
        [HttpDelete("{playlistId}/Items")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds)
 | 
			
		||||
        public async Task<ActionResult> RemoveFromPlaylist([FromRoute, Required] string? playlistId, [FromQuery] string? entryIds)
 | 
			
		||||
        {
 | 
			
		||||
            await _playlistManager.RemoveFromPlaylistAsync(playlistId, RequestHelpers.Split(entryIds, ',', true)).ConfigureAwait(false);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
@ -143,15 +143,15 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>The original playlist items.</returns>
 | 
			
		||||
        [HttpGet("{playlistId}/Items")]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetPlaylistItems(
 | 
			
		||||
            [FromRoute] Guid playlistId,
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] int? startIndex,
 | 
			
		||||
            [FromRoute] int? limit,
 | 
			
		||||
            [FromRoute] string? fields,
 | 
			
		||||
            [FromRoute] bool? enableImages,
 | 
			
		||||
            [FromRoute] bool? enableUserData,
 | 
			
		||||
            [FromRoute] int? imageTypeLimit,
 | 
			
		||||
            [FromRoute] string? enableImageTypes)
 | 
			
		||||
            [FromRoute, Required] Guid playlistId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] int? startIndex,
 | 
			
		||||
            [FromRoute, Required] int? limit,
 | 
			
		||||
            [FromRoute, Required] string? fields,
 | 
			
		||||
            [FromRoute, Required] bool? enableImages,
 | 
			
		||||
            [FromRoute, Required] bool? enableUserData,
 | 
			
		||||
            [FromRoute, Required] int? imageTypeLimit,
 | 
			
		||||
            [FromRoute, Required] string? enableImageTypes)
 | 
			
		||||
        {
 | 
			
		||||
            var playlist = (Playlist)_libraryManager.GetItemById(playlistId);
 | 
			
		||||
            if (playlist == null)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
@ -71,8 +72,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Users/{userId}/PlayedItems/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> MarkPlayedItem(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] DateTime? datePlayed)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
@ -96,7 +97,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>A <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
 | 
			
		||||
        [HttpDelete("Users/{userId}/PlayedItems/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> MarkUnplayedItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<UserItemDataDto> MarkUnplayedItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
            var session = RequestHelpers.GetSession(_sessionManager, _authContext, Request);
 | 
			
		||||
@ -195,8 +196,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> OnPlaybackStart(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] string? mediaSourceId,
 | 
			
		||||
            [FromQuery] int? audioStreamIndex,
 | 
			
		||||
            [FromQuery] int? subtitleStreamIndex,
 | 
			
		||||
@ -245,8 +246,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> OnPlaybackProgress(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] string? mediaSourceId,
 | 
			
		||||
            [FromQuery] long? positionTicks,
 | 
			
		||||
            [FromQuery] int? audioStreamIndex,
 | 
			
		||||
@ -297,8 +298,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> OnPlaybackStopped(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] string? mediaSourceId,
 | 
			
		||||
            [FromQuery] string? nextMediaType,
 | 
			
		||||
            [FromQuery] long? positionTicks,
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult UninstallPlugin([FromRoute] Guid pluginId)
 | 
			
		||||
        public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId)
 | 
			
		||||
        {
 | 
			
		||||
            var plugin = _appHost.Plugins.FirstOrDefault(p => p.Id == pluginId);
 | 
			
		||||
            if (plugin == null)
 | 
			
		||||
@ -86,7 +86,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("{pluginId}/Configuration")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute] Guid pluginId)
 | 
			
		||||
        public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute, Required] Guid pluginId)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
 | 
			
		||||
            {
 | 
			
		||||
@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("{pluginId}/Configuration")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> UpdatePluginConfiguration([FromRoute] Guid pluginId)
 | 
			
		||||
        public async Task<ActionResult> UpdatePluginConfiguration([FromRoute, Required] Guid pluginId)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
 | 
			
		||||
            {
 | 
			
		||||
@ -172,7 +172,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Obsolete("This endpoint should not be used.")]
 | 
			
		||||
        [HttpPost("RegistrationRecords/{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute] string? name)
 | 
			
		||||
        public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute, Required] string? name)
 | 
			
		||||
        {
 | 
			
		||||
            return new MBRegistrationRecord
 | 
			
		||||
            {
 | 
			
		||||
@ -194,7 +194,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Obsolete("Paid plugins are not supported")]
 | 
			
		||||
        [HttpGet("Registrations/{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status501NotImplemented)]
 | 
			
		||||
        public ActionResult GetRegistration([FromRoute] string? name)
 | 
			
		||||
        public ActionResult GetRegistration([FromRoute, Required] string? name)
 | 
			
		||||
        {
 | 
			
		||||
            // TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,
 | 
			
		||||
            // delete all these registration endpoints. They are only kept for compatibility.
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult<RemoteImageResult>> GetRemoteImages(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] ImageType? type,
 | 
			
		||||
            [FromQuery] int? startIndex,
 | 
			
		||||
            [FromQuery] int? limit,
 | 
			
		||||
@ -133,7 +133,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
@ -209,7 +209,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> DownloadRemoteImage(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery, Required] ImageType type,
 | 
			
		||||
            [FromQuery] string? imageUrl)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpPost("Running/{taskId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult StartTask([FromRoute] string? taskId)
 | 
			
		||||
        public ActionResult StartTask([FromRoute, Required] string? taskId)
 | 
			
		||||
        {
 | 
			
		||||
            var task = _taskManager.ScheduledTasks.FirstOrDefault(o =>
 | 
			
		||||
                o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase));
 | 
			
		||||
 | 
			
		||||
@ -336,7 +336,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public ActionResult AddUserToSession(
 | 
			
		||||
            [FromRoute, Required] string? sessionId,
 | 
			
		||||
            [FromRoute] Guid userId)
 | 
			
		||||
            [FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            _sessionManager.AddAdditionalUser(sessionId, userId);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
@ -353,8 +353,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public ActionResult RemoveUserFromSession(
 | 
			
		||||
            [FromRoute] string? sessionId,
 | 
			
		||||
            [FromRoute] Guid userId)
 | 
			
		||||
            [FromRoute, Required] string? sessionId,
 | 
			
		||||
            [FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            _sessionManager.RemoveAdditionalUser(sessionId, userId);
 | 
			
		||||
            return NoContent();
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
@ -259,7 +260,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the studio.</returns>
 | 
			
		||||
        [HttpGet("{name}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetStudio([FromRoute] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var dtoOptions = new DtoOptions().AddClientFields(Request);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -86,8 +86,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<Task> DeleteSubtitle(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] int index)
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] int index)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetItemById(itemId);
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<IEnumerable<RemoteSubtitleInfo>>> SearchRemoteSubtitles(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? language,
 | 
			
		||||
            [FromQuery] bool? isPerfectMatch)
 | 
			
		||||
        {
 | 
			
		||||
@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        public async Task<ActionResult> DownloadRemoteSubtitles(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? subtitleId)
 | 
			
		||||
        {
 | 
			
		||||
            var video = (Video)_libraryManager.GetItemById(itemId);
 | 
			
		||||
@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
            [FromQuery] long? endPositionTicks,
 | 
			
		||||
            [FromQuery] bool copyTimestamps = false,
 | 
			
		||||
            [FromQuery] bool addVttTimeMap = false,
 | 
			
		||||
            [FromRoute] long startPositionTicks = 0)
 | 
			
		||||
            [FromRoute, Required] long startPositionTicks = 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
@ -253,9 +253,9 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
 | 
			
		||||
        public async Task<ActionResult> GetSubtitlePlaylist(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] int index,
 | 
			
		||||
            [FromRoute] string? mediaSourceId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] int index,
 | 
			
		||||
            [FromRoute, Required] string? mediaSourceId,
 | 
			
		||||
            [FromQuery, Required] int segmentLength)
 | 
			
		||||
        {
 | 
			
		||||
            var item = (Video)_libraryManager.GetItemById(itemId);
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
using Jellyfin.Api.Helpers;
 | 
			
		||||
@ -53,7 +54,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{userId}/Suggestions")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetSuggestions(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromQuery] string? mediaType,
 | 
			
		||||
            [FromQuery] string? type,
 | 
			
		||||
            [FromQuery] int? startIndex,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@ -92,8 +93,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status302Found)]
 | 
			
		||||
        public async Task<ActionResult> GetUniversalAudioStream(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] string? mediaSourceId,
 | 
			
		||||
            [FromQuery] string? deviceId,
 | 
			
		||||
            [FromQuery] Guid? userId,
 | 
			
		||||
 | 
			
		||||
@ -108,7 +108,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.IgnoreParentalControl)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<UserDto> GetUserById([FromRoute] Guid userId)
 | 
			
		||||
        public ActionResult<UserDto> GetUserById([FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
 | 
			
		||||
@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult DeleteUser([FromRoute] Guid userId)
 | 
			
		||||
        public ActionResult DeleteUser([FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
            _sessionManager.RevokeUserTokens(user.Id, null);
 | 
			
		||||
@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> UpdateUserPassword(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromBody] UpdateUserPassword request)
 | 
			
		||||
        {
 | 
			
		||||
            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
 | 
			
		||||
@ -323,7 +323,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult UpdateUserEasyPassword(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromBody] UpdateUserEasyPassword request)
 | 
			
		||||
        {
 | 
			
		||||
            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
 | 
			
		||||
@ -365,7 +365,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        public async Task<ActionResult> UpdateUser(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromBody] UserDto updateUser)
 | 
			
		||||
        {
 | 
			
		||||
            if (updateUser == null)
 | 
			
		||||
@ -409,7 +409,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        public ActionResult UpdateUserPolicy(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromBody] UserPolicy newPolicy)
 | 
			
		||||
        {
 | 
			
		||||
            if (newPolicy == null)
 | 
			
		||||
@ -464,7 +464,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status204NoContent)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
 | 
			
		||||
        public ActionResult UpdateUserConfiguration(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromBody] UserConfiguration userConfig)
 | 
			
		||||
        {
 | 
			
		||||
            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false))
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@ -70,7 +71,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the d item.</returns>
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public async Task<ActionResult<BaseItemDto>> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
 | 
			
		||||
@ -93,7 +94,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the user's root folder.</returns>
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/Root")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRootFolder([FromRoute] Guid userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetRootFolder([FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
            var item = _libraryManager.GetUserRootFolder();
 | 
			
		||||
@ -110,7 +111,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the intros to play.</returns>
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/{itemId}/Intros")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult<QueryResult<BaseItemDto>>> GetIntros([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public async Task<ActionResult<QueryResult<BaseItemDto>>> GetIntros([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
 | 
			
		||||
@ -138,7 +139,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
 | 
			
		||||
        [HttpPost("Users/{userId}/FavoriteItems/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<UserItemDataDto> MarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            return MarkFavorite(userId, itemId, true);
 | 
			
		||||
        }
 | 
			
		||||
@ -152,7 +153,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
 | 
			
		||||
        [HttpDelete("Users/{userId}/FavoriteItems/{itemId}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<UserItemDataDto> UnmarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            return MarkFavorite(userId, itemId, false);
 | 
			
		||||
        }
 | 
			
		||||
@ -166,7 +167,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
 | 
			
		||||
        [HttpDelete("Users/{userId}/Items/{itemId}/Rating")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<UserItemDataDto> DeleteUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            return UpdateUserItemRatingInternal(userId, itemId, null);
 | 
			
		||||
        }
 | 
			
		||||
@ -181,7 +182,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
 | 
			
		||||
        [HttpPost("Users/{userId}/Items/{itemId}/Rating")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool? likes)
 | 
			
		||||
        public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] bool? likes)
 | 
			
		||||
        {
 | 
			
		||||
            return UpdateUserItemRatingInternal(userId, itemId, likes);
 | 
			
		||||
        }
 | 
			
		||||
@ -195,7 +196,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>The items local trailers.</returns>
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/{itemId}/LocalTrailers")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetLocalTrailers([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetLocalTrailers([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
 | 
			
		||||
@ -230,7 +231,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        /// <returns>An <see cref="OkResult"/> containing the special features.</returns>
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/{itemId}/SpecialFeatures")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetSpecialFeatures([FromRoute] Guid userId, [FromRoute] Guid itemId)
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetSpecialFeatures([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
 | 
			
		||||
@ -264,7 +265,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{userId}/Items/Latest")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<IEnumerable<BaseItemDto>> GetLatestMedia(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromQuery] Guid? parentId,
 | 
			
		||||
            [FromQuery] string? fields,
 | 
			
		||||
            [FromQuery] string? includeItemTypes,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
@ -64,7 +65,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{userId}/Views")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetUserViews(
 | 
			
		||||
            [FromRoute] Guid userId,
 | 
			
		||||
            [FromRoute, Required] Guid userId,
 | 
			
		||||
            [FromQuery] bool? includeExternalContent,
 | 
			
		||||
            [FromQuery] string? presetViews,
 | 
			
		||||
            [FromQuery] bool includeHidden = false)
 | 
			
		||||
@ -126,7 +127,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Users/{userId}/GroupingOptions")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptions([FromRoute] Guid userId)
 | 
			
		||||
        public ActionResult<IEnumerable<SpecialViewOptionDto>> GetGroupingOptions([FromRoute, Required] Guid userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = _userManager.GetUserById(userId);
 | 
			
		||||
            if (user == null)
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
@ -162,7 +163,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("Videos/{itemId}/live.m3u8")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetLiveHlsStream(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromQuery] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
 | 
			
		||||
@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("{itemId}/AdditionalParts")]
 | 
			
		||||
        [Authorize(Policy = Policies.DefaultAuthorization)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
 | 
			
		||||
                ? _userManager.GetUserById(userId.Value)
 | 
			
		||||
@ -162,7 +162,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [Authorize(Policy = Policies.RequiresElevation)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public async Task<ActionResult> DeleteAlternateSources([FromRoute] Guid itemId)
 | 
			
		||||
        public async Task<ActionResult> DeleteAlternateSources([FromRoute, Required] Guid itemId)
 | 
			
		||||
        {
 | 
			
		||||
            var video = (Video)_libraryManager.GetItemById(itemId);
 | 
			
		||||
 | 
			
		||||
@ -331,8 +331,8 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpHead("{itemId}/stream", Name = "HeadVideoStream")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        public async Task<ActionResult> GetVideoStream(
 | 
			
		||||
            [FromRoute] Guid itemId,
 | 
			
		||||
            [FromRoute] string? container,
 | 
			
		||||
            [FromRoute, Required] Guid itemId,
 | 
			
		||||
            [FromRoute, Required] string? container,
 | 
			
		||||
            [FromQuery] bool? @static,
 | 
			
		||||
            [FromQuery] string? @params,
 | 
			
		||||
            [FromQuery] string? tag,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Jellyfin.Api.Constants;
 | 
			
		||||
using Jellyfin.Api.Extensions;
 | 
			
		||||
@ -179,7 +180,7 @@ namespace Jellyfin.Api.Controllers
 | 
			
		||||
        [HttpGet("{year}")]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status200OK)]
 | 
			
		||||
        [ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
			
		||||
        public ActionResult<BaseItemDto> GetYear([FromRoute] int year, [FromQuery] Guid? userId)
 | 
			
		||||
        public ActionResult<BaseItemDto> GetYear([FromRoute, Required] int year, [FromQuery] Guid? userId)
 | 
			
		||||
        {
 | 
			
		||||
            var item = _libraryManager.GetYear(year);
 | 
			
		||||
            if (item == null)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user