From 460c3dd35166c9a48db83db62a3f0a8742956408 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 9 Aug 2020 17:20:14 -0600 Subject: convert dependent controller functions to di helper class --- .../Controllers/UniversalAudioController.cs | 280 +++++++++++---------- 1 file changed, 141 insertions(+), 139 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 75df16aa7..2ea462488 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -2,17 +2,20 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net.Http; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; -using Jellyfin.Api.Models.VideoDtos; +using Jellyfin.Api.Models.StreamingDtos; +using MediaBrowser.Controller.Devices; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.MediaInfo; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers { @@ -23,27 +26,39 @@ namespace Jellyfin.Api.Controllers public class UniversalAudioController : BaseJellyfinApiController { private readonly IAuthorizationContext _authorizationContext; - private readonly MediaInfoController _mediaInfoController; - private readonly DynamicHlsController _dynamicHlsController; - private readonly AudioController _audioController; + private readonly IDeviceManager _deviceManager; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly MediaInfoHelper _mediaInfoHelper; + private readonly AudioHelper _audioHelper; + private readonly DynamicHlsHelper _dynamicHlsHelper; /// /// Initializes a new instance of the class. /// /// Instance of the interface. - /// Instance of the . - /// Instance of the . - /// Instance of the . + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of . + /// Instance of . + /// Instance of . public UniversalAudioController( IAuthorizationContext authorizationContext, - MediaInfoController mediaInfoController, - DynamicHlsController dynamicHlsController, - AudioController audioController) + IDeviceManager deviceManager, + ILibraryManager libraryManager, + ILogger logger, + MediaInfoHelper mediaInfoHelper, + AudioHelper audioHelper, + DynamicHlsHelper dynamicHlsHelper) { _authorizationContext = authorizationContext; - _mediaInfoController = mediaInfoController; - _dynamicHlsController = dynamicHlsController; - _audioController = audioController; + _deviceManager = deviceManager; + _libraryManager = libraryManager; + _logger = logger; + _mediaInfoHelper = mediaInfoHelper; + _audioHelper = audioHelper; + _dynamicHlsHelper = dynamicHlsHelper; } /// @@ -99,20 +114,65 @@ namespace Jellyfin.Api.Controllers var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels); _authorizationContext.GetAuthorizationInfo(Request).DeviceId = deviceId; - var playbackInfoResult = await _mediaInfoController.GetPostedPlaybackInfo( - itemId, - userId, - maxStreamingBitrate, - startTimeTicks, - null, - null, - maxAudioChannels, - mediaSourceId, - null, - new DeviceProfileDto { DeviceProfile = deviceProfile }) + var authInfo = _authorizationContext.GetAuthorizationInfo(Request); + + _logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", deviceProfile); + + if (deviceProfile == null) + { + var caps = _deviceManager.GetCapabilities(authInfo.DeviceId); + if (caps != null) + { + deviceProfile = caps.DeviceProfile; + } + } + + var info = await _mediaInfoHelper.GetPlaybackInfo( + itemId, + userId, + mediaSourceId) .ConfigureAwait(false); - var mediaSource = playbackInfoResult.Value.MediaSources[0]; + if (deviceProfile != null) + { + // set device specific data + var item = _libraryManager.GetItemById(itemId); + + foreach (var sourceInfo in info.MediaSources) + { + _mediaInfoHelper.SetDeviceSpecificData( + item, + sourceInfo, + deviceProfile, + authInfo, + maxStreamingBitrate ?? deviceProfile.MaxStreamingBitrate, + startTimeTicks ?? 0, + mediaSourceId ?? string.Empty, + null, + null, + maxAudioChannels, + info!.PlaySessionId!, + userId ?? Guid.Empty, + true, + true, + true, + true, + true, + Request.HttpContext.Connection.RemoteIpAddress.ToString()); + } + + _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); + } + + if (info.MediaSources != null) + { + foreach (var source in info.MediaSources) + { + _mediaInfoHelper.NormalizeMediaSourceContainer(source, deviceProfile!, DlnaProfileType.Video); + } + } + + var mediaSource = info.MediaSources![0]; if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http) { if (enableRedirection) @@ -127,129 +187,71 @@ namespace Jellyfin.Api.Controllers var isStatic = mediaSource.SupportsDirectStream; if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)) { - var transcodingProfile = deviceProfile.TranscodingProfiles[0]; - // hls segment container can only be mpegts or fmp4 per ffmpeg documentation // TODO: remove this when we switch back to the segment muxer var supportedHlsContainers = new[] { "mpegts", "fmp4" }; - if (isHeadRequest) + var dynamicHlsRequestDto = new HlsAudioRequestDto { - _dynamicHlsController.Request.Method = HttpMethod.Head.Method; - } - - return await _dynamicHlsController.GetMasterHlsAudioPlaylist( - itemId, - ".m3u8", - isStatic, - null, - null, - null, - playbackInfoResult.Value.PlaySessionId, + Id = itemId, + Container = ".m3u8", + Static = isStatic, + PlaySessionId = info.PlaySessionId, // fallback to mpegts if device reports some weird value unsupported by hls - Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "mpegts", - null, - null, - mediaSource.Id, - deviceId, - transcodingProfile.AudioCodec, - null, - null, - null, - transcodingProfile.BreakOnNonKeyFrames, - maxAudioSampleRate, - maxAudioBitDepth, - null, - isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), - maxAudioChannels, - null, - null, - null, - null, - null, - startTimeTicks, - null, - null, - null, - null, - SubtitleDeliveryMethod.Hls, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()), - null, - null, - EncodingContext.Static, - new Dictionary()) + SegmentContainer = Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "mpegts", + MediaSourceId = mediaSourceId, + DeviceId = deviceId, + AudioCodec = audioCodec, + EnableAutoStreamCopy = true, + AllowAudioStreamCopy = true, + AllowVideoStreamCopy = true, + BreakOnNonKeyFrames = breakOnNonKeyFrames, + AudioSampleRate = maxAudioSampleRate, + MaxAudioChannels = maxAudioChannels, + MaxAudioBitDepth = maxAudioBitDepth, + AudioChannels = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), + StartTimeTicks = startTimeTicks, + SubtitleMethod = SubtitleDeliveryMethod.Hls, + RequireAvc = true, + DeInterlace = true, + RequireNonAnamorphic = true, + EnableMpegtsM2TsMode = true, + TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()), + Context = EncodingContext.Static, + StreamOptions = new Dictionary(), + EnableAdaptiveBitrateStreaming = true + }; + + return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, TranscodingJobType.Hls, dynamicHlsRequestDto, true) .ConfigureAwait(false); } - else + + var audioStreamingDto = new StreamingRequestDto { - if (isHeadRequest) - { - _audioController.Request.Method = HttpMethod.Head.Method; - } + Id = itemId, + Container = isStatic ? null : ("." + mediaSource.TranscodingContainer), + Static = isStatic, + PlaySessionId = info.PlaySessionId, + MediaSourceId = mediaSourceId, + DeviceId = deviceId, + AudioCodec = audioCodec, + EnableAutoStreamCopy = true, + AllowAudioStreamCopy = true, + AllowVideoStreamCopy = true, + BreakOnNonKeyFrames = breakOnNonKeyFrames, + AudioSampleRate = maxAudioSampleRate, + MaxAudioChannels = maxAudioChannels, + AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), + MaxAudioBitDepth = maxAudioBitDepth, + AudioChannels = maxAudioChannels, + CopyTimestamps = true, + StartTimeTicks = startTimeTicks, + SubtitleMethod = SubtitleDeliveryMethod.Embed, + TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()), + Context = EncodingContext.Static + }; - return await _audioController.GetAudioStream( - itemId, - isStatic ? null : ("." + mediaSource.TranscodingContainer), - isStatic, - null, - null, - null, - playbackInfoResult.Value.PlaySessionId, - null, - null, - null, - mediaSource.Id, - deviceId, - audioCodec, - null, - null, - null, - breakOnNonKeyFrames, - maxAudioSampleRate, - maxAudioBitDepth, - isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), - null, - maxAudioChannels, - null, - null, - null, - null, - null, - startTimeTicks, - null, - null, - null, - null, - SubtitleDeliveryMethod.Embed, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()), - null, - null, - null, - null) - .ConfigureAwait(false); - } + return await _audioHelper.GetAudioStream(this, TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false); } private DeviceProfile GetDeviceProfile( -- cgit v1.2.3 From c5e9cf15f6476d96eadc1d32e38687c3a5a98a17 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 10 Aug 2020 07:53:32 -0600 Subject: Use proper IHttpContextAccessor --- Jellyfin.Api/Controllers/AudioController.cs | 2 +- Jellyfin.Api/Controllers/DynamicHlsController.cs | 6 ++-- Jellyfin.Api/Controllers/HlsSegmentController.cs | 4 +-- .../Controllers/UniversalAudioController.cs | 5 ++- Jellyfin.Api/Controllers/VideosController.cs | 7 ++--- Jellyfin.Api/Helpers/AudioHelper.cs | 36 ++++++++++++---------- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 23 +++++++------- Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs | 36 ++++++++++------------ 8 files changed, 59 insertions(+), 60 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 107db9571..d300b4891 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -192,7 +192,7 @@ namespace Jellyfin.Api.Controllers StreamOptions = streamOptions }; - return await _audioHelper.GetAudioStream(this, _transcodingJobType, streamingRequest).ConfigureAwait(false); + return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false); } } } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 1a85a07b8..b4fe3bc8f 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -272,7 +272,7 @@ namespace Jellyfin.Api.Controllers EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming }; - return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, _transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); + return await _dynamicHlsHelper.GetMasterHlsPlaylist(_transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); } /// @@ -439,7 +439,7 @@ namespace Jellyfin.Api.Controllers EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming }; - return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, _transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); + return await _dynamicHlsHelper.GetMasterHlsPlaylist(_transcodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false); } /// @@ -1657,7 +1657,7 @@ namespace Jellyfin.Api.Controllers return Task.CompletedTask; }); - return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath)!, false, this); + return FileStreamResponseHelpers.GetStaticFileResult(segmentPath, MimeTypes.GetMimeType(segmentPath)!, false, HttpContext); } private long GetEndPositionTicks(StreamState state, int requestedIndex) diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index e4a6842bc..816252f80 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -61,7 +61,7 @@ namespace Jellyfin.Api.Controllers var file = segmentId + Path.GetExtension(Request.Path); file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file); - return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, this); + return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext); } /// @@ -148,7 +148,7 @@ namespace Jellyfin.Api.Controllers return Task.CompletedTask; }); - return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path)!, false, this); + return FileStreamResponseHelpers.GetStaticFileResult(path, MimeTypes.GetMimeType(path)!, false, HttpContext); } } } diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 2ea462488..2a788e03a 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -110,7 +110,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool breakOnNonKeyFrames, [FromQuery] bool enableRedirection = true) { - bool isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head; var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels); _authorizationContext.GetAuthorizationInfo(Request).DeviceId = deviceId; @@ -222,7 +221,7 @@ namespace Jellyfin.Api.Controllers EnableAdaptiveBitrateStreaming = true }; - return await _dynamicHlsHelper.GetMasterHlsPlaylist(this, TranscodingJobType.Hls, dynamicHlsRequestDto, true) + return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType.Hls, dynamicHlsRequestDto, true) .ConfigureAwait(false); } @@ -251,7 +250,7 @@ namespace Jellyfin.Api.Controllers Context = EncodingContext.Static }; - return await _audioHelper.GetAudioStream(this, TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false); + return await _audioHelper.GetAudioStream(TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false); } private DeviceProfile GetDeviceProfile( diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index fafa722c5..8eee51c2c 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -471,7 +471,7 @@ namespace Jellyfin.Api.Controllers StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); using var httpClient = _httpClientFactory.CreateClient(); - return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, httpClient).ConfigureAwait(false); + return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, HttpContext).ConfigureAwait(false); } if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File) @@ -507,7 +507,7 @@ namespace Jellyfin.Api.Controllers state.MediaPath, contentType, isHeadRequest, - this); + HttpContext); } // Need to start ffmpeg (because media can't be returned directly) @@ -517,10 +517,9 @@ namespace Jellyfin.Api.Controllers return await FileStreamResponseHelpers.GetTranscodedFile( state, isHeadRequest, - this, + HttpContext, _transcodingJobHelper, ffmpegCommandLineArguments, - Request, _transcodingJobType, cancellationTokenSource).ConfigureAwait(false); } diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index 001028432..694e1f0dd 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -12,6 +12,7 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -35,6 +36,7 @@ namespace Jellyfin.Api.Helpers private readonly IDeviceManager _deviceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private readonly IHttpClientFactory _httpClientFactory; + private readonly IHttpContextAccessor _httpContextAccessor; /// /// Initializes a new instance of the class. @@ -52,6 +54,7 @@ namespace Jellyfin.Api.Helpers /// Instance of the interface. /// Instance of . /// Instance of the interface. + /// Instance of the interface. public AudioHelper( IDlnaManager dlnaManager, IAuthorizationContext authContext, @@ -65,7 +68,8 @@ namespace Jellyfin.Api.Helpers IConfiguration configuration, IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, - IHttpClientFactory httpClientFactory) + IHttpClientFactory httpClientFactory, + IHttpContextAccessor httpContextAccessor) { _dlnaManager = dlnaManager; _authContext = authContext; @@ -80,26 +84,25 @@ namespace Jellyfin.Api.Helpers _deviceManager = deviceManager; _transcodingJobHelper = transcodingJobHelper; _httpClientFactory = httpClientFactory; + _httpContextAccessor = httpContextAccessor; } /// /// Get audio stream. /// - /// Requesting controller. /// Transcoding job type. /// Streaming controller.Request dto. /// A containing the resulting . public async Task GetAudioStream( - BaseJellyfinApiController controller, TranscodingJobType transcodingJobType, StreamingRequestDto streamingRequest) { - bool isHeadRequest = controller.Request.Method == System.Net.WebRequestMethods.Http.Head; + bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head; var cancellationTokenSource = new CancellationTokenSource(); using var state = await StreamingHelpers.GetStreamingState( streamingRequest, - controller.Request, + _httpContextAccessor.HttpContext.Request, _authContext, _mediaSourceManager, _userManager, @@ -118,30 +121,30 @@ namespace Jellyfin.Api.Helpers if (streamingRequest.Static && state.DirectStreamProvider != null) { - StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, true, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) { AllowEndOfFile = false - }.WriteToAsync(controller.Response.Body, CancellationToken.None) + }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) .ConfigureAwait(false); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return controller.File(controller.Response.Body, MimeTypes.GetMimeType("file.ts")!); + return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, MimeTypes.GetMimeType("file.ts")!); } // Static remote stream if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http) { - StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, true, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); using var httpClient = _httpClientFactory.CreateClient(); - return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, controller, httpClient).ConfigureAwait(false); + return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false); } if (streamingRequest.Static && state.InputProtocol != MediaProtocol.File) { - return controller.BadRequest($"Input protocol {state.InputProtocol} cannot be streamed statically"); + return new BadRequestObjectResult($"Input protocol {state.InputProtocol} cannot be streamed statically"); } var outputPath = state.OutputFilePath; @@ -150,7 +153,7 @@ namespace Jellyfin.Api.Helpers var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); var isTranscodeCached = outputPathExists && transcodingJob != null; - StreamingHelpers.AddDlnaHeaders(state, controller.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, controller.Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); // Static stream if (streamingRequest.Static) @@ -162,17 +165,17 @@ namespace Jellyfin.Api.Helpers await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) { AllowEndOfFile = false - }.WriteToAsync(controller.Response.Body, CancellationToken.None) + }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) .ConfigureAwait(false); - return controller.File(controller.Response.Body, contentType); + return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, contentType); } return FileStreamResponseHelpers.GetStaticFileResult( state.MediaPath, contentType, isHeadRequest, - controller); + _httpContextAccessor.HttpContext); } // Need to start ffmpeg (because media can't be returned directly) @@ -182,10 +185,9 @@ namespace Jellyfin.Api.Helpers return await FileStreamResponseHelpers.GetTranscodedFile( state, isHeadRequest, - controller, + _httpContextAccessor.HttpContext, _transcodingJobHelper, ffmpegCommandLineArguments, - controller.Request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false); } diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 127d91430..6a8829d46 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -19,6 +19,7 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -45,6 +46,7 @@ namespace Jellyfin.Api.Helpers private readonly TranscodingJobHelper _transcodingJobHelper; private readonly INetworkManager _networkManager; private readonly ILogger _logger; + private readonly IHttpContextAccessor _httpContextAccessor; /// /// Initializes a new instance of the class. @@ -63,6 +65,7 @@ namespace Jellyfin.Api.Helpers /// Instance of . /// Instance of the interface. /// Instance of the interface. + /// Instance of the interface. public DynamicHlsHelper( ILibraryManager libraryManager, IUserManager userManager, @@ -77,7 +80,8 @@ namespace Jellyfin.Api.Helpers IDeviceManager deviceManager, TranscodingJobHelper transcodingJobHelper, INetworkManager networkManager, - ILogger logger) + ILogger logger, + IHttpContextAccessor httpContextAccessor) { _libraryManager = libraryManager; _userManager = userManager; @@ -93,26 +97,24 @@ namespace Jellyfin.Api.Helpers _transcodingJobHelper = transcodingJobHelper; _networkManager = networkManager; _logger = logger; + _httpContextAccessor = httpContextAccessor; } /// /// Get master hls playlist. /// - /// Requesting controller. /// Transcoding job type. /// Streaming request dto. /// Enable adaptive bitrate streaming. /// A containing the resulting . public async Task GetMasterHlsPlaylist( - BaseJellyfinApiController controller, TranscodingJobType transcodingJobType, StreamingRequestDto streamingRequest, bool enableAdaptiveBitrateStreaming) { - var isHeadRequest = controller.Request.Method == WebRequestMethods.Http.Head; + var isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == WebRequestMethods.Http.Head; var cancellationTokenSource = new CancellationTokenSource(); return await GetMasterPlaylistInternal( - controller, streamingRequest, isHeadRequest, enableAdaptiveBitrateStreaming, @@ -121,7 +123,6 @@ namespace Jellyfin.Api.Helpers } private async Task GetMasterPlaylistInternal( - BaseJellyfinApiController controller, StreamingRequestDto streamingRequest, bool isHeadRequest, bool enableAdaptiveBitrateStreaming, @@ -130,7 +131,7 @@ namespace Jellyfin.Api.Helpers { using var state = await StreamingHelpers.GetStreamingState( streamingRequest, - controller.Request, + _httpContextAccessor.HttpContext.Request, _authContext, _mediaSourceManager, _userManager, @@ -147,7 +148,7 @@ namespace Jellyfin.Api.Helpers cancellationTokenSource.Token) .ConfigureAwait(false); - controller.Response.Headers.Add(HeaderNames.Expires, "0"); + _httpContextAccessor.HttpContext.Response.Headers.Add(HeaderNames.Expires, "0"); if (isHeadRequest) { return new FileContentResult(Array.Empty(), MimeTypes.GetMimeType("playlist.m3u8")); @@ -161,7 +162,7 @@ namespace Jellyfin.Api.Helpers var isLiveStream = state.IsSegmentedLiveStream; - var queryString = controller.Request.QueryString.ToString(); + var queryString = _httpContextAccessor.HttpContext.Request.QueryString.ToString(); // from universal audio service if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer)) @@ -197,12 +198,12 @@ namespace Jellyfin.Api.Helpers if (!string.IsNullOrWhiteSpace(subtitleGroup)) { - AddSubtitles(state, subtitleStreams, builder, controller.Request.HttpContext.User); + AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.Request.HttpContext.User); } AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup); - if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, controller.Request.HttpContext.Connection.RemoteIpAddress)) + if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress)) { var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0; diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs index a463783e0..e2f82b2de 100644 --- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs +++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs @@ -22,14 +22,14 @@ namespace Jellyfin.Api.Helpers /// /// The current . /// Whether the current request is a HTTP HEAD request so only the headers get returned. - /// The managing the response. /// The making the remote request. + /// The current http context. /// A containing the API response. public static async Task GetStaticRemoteStreamResult( StreamState state, bool isHeadRequest, - ControllerBase controller, - HttpClient httpClient) + HttpClient httpClient, + HttpContext httpContext) { if (state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent)) { @@ -39,14 +39,14 @@ namespace Jellyfin.Api.Helpers using var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false); var contentType = response.Content.Headers.ContentType.ToString(); - controller.Response.Headers[HeaderNames.AcceptRanges] = "none"; + httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none"; if (isHeadRequest) { - return controller.File(Array.Empty(), contentType); + return new FileContentResult(Array.Empty(), contentType); } - return controller.File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType); + return new FileStreamResult(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType); } /// @@ -55,23 +55,23 @@ namespace Jellyfin.Api.Helpers /// The path to the file. /// The content type of the file. /// Whether the current request is a HTTP HEAD request so only the headers get returned. - /// The managing the response. + /// The current http context. /// An the file. public static ActionResult GetStaticFileResult( string path, string contentType, bool isHeadRequest, - ControllerBase controller) + HttpContext httpContext) { - controller.Response.ContentType = contentType; + httpContext.Response.ContentType = contentType; // if the request is a head request, return a NoContent result with the same headers as it would with a GET request if (isHeadRequest) { - return controller.NoContent(); + return new NoContentResult(); } - return controller.PhysicalFile(path, contentType); + return new PhysicalFileResult(path, contentType); } /// @@ -79,34 +79,32 @@ namespace Jellyfin.Api.Helpers /// /// The current . /// Whether the current request is a HTTP HEAD request so only the headers get returned. - /// The managing the response. + /// The current http context. /// The singleton. /// The command line arguments to start ffmpeg. - /// The starting the transcoding. /// The . /// The . /// A containing the transcoded file. public static async Task GetTranscodedFile( StreamState state, bool isHeadRequest, - ControllerBase controller, + HttpContext httpContext, TranscodingJobHelper transcodingJobHelper, string ffmpegCommandLineArguments, - HttpRequest request, TranscodingJobType transcodingJobType, CancellationTokenSource cancellationTokenSource) { // Use the command line args with a dummy playlist path var outputPath = state.OutputFilePath; - controller.Response.Headers[HeaderNames.AcceptRanges] = "none"; + httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none"; var contentType = state.GetMimeType(outputPath); // Headers only if (isHeadRequest) { - return controller.File(Array.Empty(), contentType); + return new FileContentResult(Array.Empty(), contentType); } var transcodingLock = transcodingJobHelper.GetTranscodingLock(outputPath); @@ -116,7 +114,7 @@ namespace Jellyfin.Api.Helpers TranscodingJobDto? job; if (!File.Exists(outputPath)) { - job = await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false); + job = await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, httpContext.Request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false); } else { @@ -127,7 +125,7 @@ namespace Jellyfin.Api.Helpers var memoryStream = new MemoryStream(); await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false); memoryStream.Position = 0; - return controller.File(memoryStream, contentType); + return new FileStreamResult(memoryStream, contentType); } finally { -- cgit v1.2.3 From 0c50015400c63d68513184c58b25fb19d5b600fe Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 16 Aug 2020 11:34:41 -0600 Subject: Fix audio stream routes --- Jellyfin.Api/Controllers/AudioController.cs | 4 ++-- Jellyfin.Api/Controllers/UniversalAudioController.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index d300b4891..802cd026e 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -83,9 +83,9 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Audio stream returned. /// A containing the audio file. - [HttpGet("{itemId}/{stream=stream}.{container?}", Name = "GetAudioStreamByContainer")] + [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")] [HttpGet("{itemId}/stream", Name = "GetAudioStream")] - [HttpHead("{itemId}/{stream=stream}.{container?}", Name = "HeadAudioStreamByContainer")] + [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")] [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetAudioStream( diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 2a788e03a..8f576d412 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -85,9 +85,9 @@ namespace Jellyfin.Api.Controllers /// Redirected to remote audio stream. /// A containing the audio file. [HttpGet("Audio/{itemId}/universal")] - [HttpGet("Audio/{itemId}/{universal=universal}.{container?}", Name = "GetUniversalAudioStream_2")] + [HttpGet("Audio/{itemId}/universal.{container}", Name = "GetUniversalAudioStream_2")] [HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] - [HttpHead("Audio/{itemId}/{universal=universal}.{container?}", Name = "HeadUniversalAudioStream_2")] + [HttpHead("Audio/{itemId}/universal.{container}", Name = "HeadUniversalAudioStream_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] -- cgit v1.2.3 From 7861c72754172a1d2ebaffdde861fd614fa65488 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 16 Aug 2020 11:47:26 -0600 Subject: Revert "Fix audio stream routes" This reverts commit 0c50015400c63d68513184c58b25fb19d5b600fe. --- Jellyfin.Api/Controllers/AudioController.cs | 4 ++-- Jellyfin.Api/Controllers/UniversalAudioController.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 802cd026e..d300b4891 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -83,9 +83,9 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Audio stream returned. /// A containing the audio file. - [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")] + [HttpGet("{itemId}/{stream=stream}.{container?}", Name = "GetAudioStreamByContainer")] [HttpGet("{itemId}/stream", Name = "GetAudioStream")] - [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")] + [HttpHead("{itemId}/{stream=stream}.{container?}", Name = "HeadAudioStreamByContainer")] [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetAudioStream( diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 8f576d412..2a788e03a 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -85,9 +85,9 @@ namespace Jellyfin.Api.Controllers /// Redirected to remote audio stream. /// A containing the audio file. [HttpGet("Audio/{itemId}/universal")] - [HttpGet("Audio/{itemId}/universal.{container}", Name = "GetUniversalAudioStream_2")] + [HttpGet("Audio/{itemId}/{universal=universal}.{container?}", Name = "GetUniversalAudioStream_2")] [HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] - [HttpHead("Audio/{itemId}/universal.{container}", Name = "HeadUniversalAudioStream_2")] + [HttpHead("Audio/{itemId}/{universal=universal}.{container?}", Name = "HeadUniversalAudioStream_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] -- cgit v1.2.3 From b90e240af649b1cf2ad72318e985755514b893c3 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 18 Aug 2020 07:29:39 -0600 Subject: rename clientCapabilities --- Jellyfin.Api/Controllers/UniversalAudioController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 2a788e03a..3994fb995 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -119,10 +119,10 @@ namespace Jellyfin.Api.Controllers if (deviceProfile == null) { - var caps = _deviceManager.GetCapabilities(authInfo.DeviceId); - if (caps != null) + var clientCapabilities = _deviceManager.GetCapabilities(authInfo.DeviceId); + if (clientCapabilities != null) { - deviceProfile = caps.DeviceProfile; + deviceProfile = clientCapabilities.DeviceProfile; } } -- cgit v1.2.3 From 11e3cdb3cba8932ee2aca39fec9275329c6f5c59 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 19 Aug 2020 15:08:28 -0600 Subject: Fix conflicting audio routes --- Jellyfin.Api/Controllers/AudioController.cs | 4 ++-- Jellyfin.Api/Controllers/UniversalAudioController.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index d300b4891..802cd026e 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -83,9 +83,9 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Audio stream returned. /// A containing the audio file. - [HttpGet("{itemId}/{stream=stream}.{container?}", Name = "GetAudioStreamByContainer")] + [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")] [HttpGet("{itemId}/stream", Name = "GetAudioStream")] - [HttpHead("{itemId}/{stream=stream}.{container?}", Name = "HeadAudioStreamByContainer")] + [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")] [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetAudioStream( diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 3994fb995..b13cf9fa5 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -85,9 +85,9 @@ namespace Jellyfin.Api.Controllers /// Redirected to remote audio stream. /// A containing the audio file. [HttpGet("Audio/{itemId}/universal")] - [HttpGet("Audio/{itemId}/{universal=universal}.{container?}", Name = "GetUniversalAudioStream_2")] + [HttpGet("Audio/{itemId}/universal.{container}", Name = "GetUniversalAudioStream_2")] [HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] - [HttpHead("Audio/{itemId}/{universal=universal}.{container?}", Name = "HeadUniversalAudioStream_2")] + [HttpHead("Audio/{itemId}/universal.{container}", Name = "HeadUniversalAudioStream_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] -- cgit v1.2.3 From 2f33bee2a94f7175050f83d568f8bd65a01a86f8 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 1 Sep 2020 17:26:49 -0600 Subject: Set openapi schema type to file where possible --- .../Attributes/ProducesAudioFileAttribute.cs | 18 ++++++++ Jellyfin.Api/Attributes/ProducesFileAttribute.cs | 28 ++++++++++++ .../Attributes/ProducesImageFileAttribute.cs | 18 ++++++++ .../Attributes/ProducesPlaylistFileAttribute.cs | 18 ++++++++ .../Attributes/ProducesVideoFileAttribute.cs | 18 ++++++++ Jellyfin.Api/Controllers/AudioController.cs | 2 + .../Controllers/ConfigurationController.cs | 3 ++ Jellyfin.Api/Controllers/DashboardController.cs | 3 ++ Jellyfin.Api/Controllers/DlnaServerController.cs | 25 +++++++---- Jellyfin.Api/Controllers/DynamicHlsController.cs | 7 +++ Jellyfin.Api/Controllers/HlsSegmentController.cs | 4 ++ Jellyfin.Api/Controllers/ImageController.cs | 11 ++++- Jellyfin.Api/Controllers/ItemLookupController.cs | 10 +++-- Jellyfin.Api/Controllers/LibraryController.cs | 3 ++ Jellyfin.Api/Controllers/LiveTvController.cs | 4 ++ Jellyfin.Api/Controllers/MediaInfoController.cs | 2 + Jellyfin.Api/Controllers/SubtitleController.cs | 4 ++ Jellyfin.Api/Controllers/SystemController.cs | 9 ++-- .../Controllers/UniversalAudioController.cs | 2 + Jellyfin.Api/Controllers/UserController.cs | 6 +-- Jellyfin.Api/Controllers/VideoHlsController.cs | 2 + Jellyfin.Api/Controllers/VideosController.cs | 4 +- .../Extensions/ApiServiceCollectionExtensions.cs | 3 ++ Jellyfin.Server/Filters/FileResponseFilter.cs | 52 ++++++++++++++++++++++ 24 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs create mode 100644 Jellyfin.Api/Attributes/ProducesFileAttribute.cs create mode 100644 Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs create mode 100644 Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs create mode 100644 Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs create mode 100644 Jellyfin.Server/Filters/FileResponseFilter.cs (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs new file mode 100644 index 000000000..3adb700eb --- /dev/null +++ b/Jellyfin.Api/Attributes/ProducesAudioFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// + /// Produces file attribute of "image/*". + /// + public class ProducesAudioFileAttribute : ProducesFileAttribute + { + private const string ContentType = "audio/*"; + + /// + /// Initializes a new instance of the class. + /// + public ProducesAudioFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs new file mode 100644 index 000000000..62a576ede --- /dev/null +++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Jellyfin.Api.Attributes +{ + /// + /// Internal produces image attribute. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ProducesFileAttribute : Attribute + { + private readonly string[] _contentTypes; + + /// + /// Initializes a new instance of the class. + /// + /// Content types this endpoint produces. + public ProducesFileAttribute(params string[] contentTypes) + { + _contentTypes = contentTypes; + } + + /// + /// Gets the configured content types. + /// + /// the configured content types. + public string[] GetContentTypes() => _contentTypes; + } +} diff --git a/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs new file mode 100644 index 000000000..e15813676 --- /dev/null +++ b/Jellyfin.Api/Attributes/ProducesImageFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// + /// Produces file attribute of "image/*". + /// + public class ProducesImageFileAttribute : ProducesFileAttribute + { + private const string ContentType = "image/*"; + + /// + /// Initializes a new instance of the class. + /// + public ProducesImageFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs new file mode 100644 index 000000000..5d928ab91 --- /dev/null +++ b/Jellyfin.Api/Attributes/ProducesPlaylistFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// + /// Produces file attribute of "image/*". + /// + public class ProducesPlaylistFileAttribute : ProducesFileAttribute + { + private const string ContentType = "application/x-mpegURL"; + + /// + /// Initializes a new instance of the class. + /// + public ProducesPlaylistFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs new file mode 100644 index 000000000..d8b2856dc --- /dev/null +++ b/Jellyfin.Api/Attributes/ProducesVideoFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// + /// Produces file attribute of "video/*". + /// + public class ProducesVideoFileAttribute : ProducesFileAttribute + { + private const string ContentType = "video/*"; + + /// + /// Initializes a new instance of the class. + /// + public ProducesVideoFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 802cd026e..48fd198b5 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Controller.MediaEncoding; @@ -88,6 +89,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")] [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesAudioFile] public async Task GetAudioStream( [FromRoute] Guid itemId, [FromRoute] string? container, diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index 20fb0ec87..606e27970 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -1,6 +1,8 @@ using System.ComponentModel.DataAnnotations; +using System.Net.Mime; using System.Text.Json; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Models.ConfigurationDtos; using MediaBrowser.Common.Json; @@ -73,6 +75,7 @@ namespace Jellyfin.Api.Controllers /// Configuration. [HttpGet("Configuration/{key}")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile(MediaTypeNames.Application.Json)] public ActionResult GetNamedConfiguration([FromRoute] string? key) { return _configurationManager.GetConfiguration(key); diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index 33abe3ccd..c1bcc71e3 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.Mime; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Models; using MediaBrowser.Common.Plugins; using MediaBrowser.Controller; @@ -123,6 +125,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("web/ConfigurationPage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesFile(MediaTypeNames.Text.Html, "application/x-javascript")] public ActionResult GetDashboardConfigurationPage([FromQuery] string? name) { IPlugin? plugin = null; diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs index ee87d917b..dd91c7058 100644 --- a/Jellyfin.Api/Controllers/DlnaServerController.cs +++ b/Jellyfin.Api/Controllers/DlnaServerController.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Net.Mime; using System.Threading.Tasks; using Emby.Dlna; using Emby.Dlna.Main; @@ -17,8 +19,6 @@ namespace Jellyfin.Api.Controllers [Route("Dlna")] public class DlnaServerController : BaseJellyfinApiController { - private const string XMLContentType = "text/xml; charset=UTF-8"; - private readonly IDlnaManager _dlnaManager; private readonly IContentDirectory _contentDirectory; private readonly IConnectionManager _connectionManager; @@ -44,7 +44,8 @@ namespace Jellyfin.Api.Controllers /// An containing the description xml. [HttpGet("{serverId}/description")] [HttpGet("{serverId}/description.xml", Name = "GetDescriptionXml_2")] - [Produces(XMLContentType)] + [Produces(MediaTypeNames.Text.Xml)] + [ProducesFile(MediaTypeNames.Text.Xml)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetDescriptionXml([FromRoute] string serverId) { @@ -62,7 +63,8 @@ namespace Jellyfin.Api.Controllers /// An containing the dlna content directory xml. [HttpGet("{serverId}/ContentDirectory")] [HttpGet("{serverId}/ContentDirectory.xml", Name = "GetContentDirectory_2")] - [Produces(XMLContentType)] + [Produces(MediaTypeNames.Text.Xml)] + [ProducesFile(MediaTypeNames.Text.Xml)] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")] public ActionResult GetContentDirectory([FromRoute] string serverId) @@ -77,7 +79,8 @@ namespace Jellyfin.Api.Controllers /// Dlna media receiver registrar xml. [HttpGet("{serverId}/MediaReceiverRegistrar")] [HttpGet("{serverId}/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_2")] - [Produces(XMLContentType)] + [Produces(MediaTypeNames.Text.Xml)] + [ProducesFile(MediaTypeNames.Text.Xml)] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")] public ActionResult GetMediaReceiverRegistrar([FromRoute] string serverId) @@ -92,7 +95,8 @@ namespace Jellyfin.Api.Controllers /// Dlna media receiver registrar xml. [HttpGet("{serverId}/ConnectionManager")] [HttpGet("{serverId}/ConnectionManager.xml", Name = "GetConnectionManager_2")] - [Produces(XMLContentType)] + [Produces(MediaTypeNames.Text.Xml)] + [ProducesFile(MediaTypeNames.Text.Xml)] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")] public ActionResult GetConnectionManager([FromRoute] string serverId) @@ -183,7 +187,9 @@ namespace Jellyfin.Api.Controllers /// Icon stream. [HttpGet("{serverId}/icons/{fileName}")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")] - public ActionResult GetIconId([FromRoute] string serverId, [FromRoute] string fileName) + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesImageFile] + public ActionResult GetIconId([FromRoute] string serverId, [FromRoute] string fileName) { return GetIconInternal(fileName); } @@ -194,12 +200,13 @@ namespace Jellyfin.Api.Controllers /// The icon filename. /// Icon stream. [HttpGet("icons/{fileName}")] - public ActionResult GetIcon([FromRoute] string fileName) + [ProducesImageFile] + public ActionResult GetIcon([FromRoute] string fileName) { return GetIconInternal(fileName); } - private ActionResult GetIconInternal(string fileName) + private ActionResult GetIconInternal(string fileName) { var icon = _dlnaManager.GetIcon(fileName); if (icon == null) diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index b115ac6cd..230bb8295 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.PlaybackDtos; @@ -166,6 +167,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/master.m3u8")] [HttpHead("Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] public async Task GetMasterHlsVideoPlaylist( [FromRoute] Guid itemId, [FromRoute] string? container, @@ -333,6 +335,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Audio/{itemId}/master.m3u8")] [HttpHead("Audio/{itemId}/master.m3u8", Name = "HeadMasterHlsAudioPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] public async Task GetMasterHlsAudioPlaylist( [FromRoute] Guid itemId, [FromRoute] string? container, @@ -498,6 +501,7 @@ namespace Jellyfin.Api.Controllers /// A containing the audio file. [HttpGet("Videos/{itemId}/main.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] public async Task GetVariantHlsVideoPlaylist( [FromRoute] Guid itemId, [FromRoute] string? container, @@ -663,6 +667,7 @@ namespace Jellyfin.Api.Controllers /// A containing the audio file. [HttpGet("Audio/{itemId}/main.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] public async Task GetVariantHlsAudioPlaylist( [FromRoute] Guid itemId, [FromRoute] string? container, @@ -830,6 +835,7 @@ namespace Jellyfin.Api.Controllers /// A containing the audio file. [HttpGet("Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesVideoFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")] public async Task GetHlsVideoSegment( [FromRoute] Guid itemId, @@ -999,6 +1005,7 @@ namespace Jellyfin.Api.Controllers /// A containing the audio file. [HttpGet("Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesAudioFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")] public async Task GetHlsAudioSegment( [FromRoute] Guid itemId, diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 816252f80..e534be50a 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Configuration; @@ -54,6 +55,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.mp3", Name = "GetHlsAudioSegmentLegacyMp3")] [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesAudioFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsAudioSegmentLegacy([FromRoute] string itemId, [FromRoute] string segmentId) { @@ -74,6 +76,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/hls/{playlistId}/stream.m3u8")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsPlaylistLegacy([FromRoute] string itemId, [FromRoute] string playlistId) { @@ -112,6 +115,7 @@ namespace Jellyfin.Api.Controllers // [Authenticated] [HttpGet("Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesVideoFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsVideoSegmentLegacy( [FromRoute] string itemId, diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index a204fe35c..dbd569e07 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Configuration; @@ -351,6 +352,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "HeadItemImage_2")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetItemImage( [FromRoute] Guid itemId, [FromRoute] ImageType imageType, @@ -507,6 +509,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Artists/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadArtistImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetArtistImage( [FromRoute] string name, [FromRoute] ImageType imageType, @@ -585,6 +588,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Genres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetGenreImage( [FromRoute] string name, [FromRoute] ImageType imageType, @@ -663,6 +667,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("MusicGenres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadMusicGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetMusicGenreImage( [FromRoute] string name, [FromRoute] ImageType imageType, @@ -741,6 +746,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Persons/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadPersonImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetPersonImage( [FromRoute] string name, [FromRoute] ImageType imageType, @@ -819,6 +825,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Studios/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadStudioImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetStudioImage( [FromRoute] string name, [FromRoute] ImageType imageType, @@ -897,6 +904,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex?}", Name = "HeadUserImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetUserImage( [FromRoute] Guid userId, [FromRoute] ImageType imageType, @@ -1297,8 +1305,7 @@ namespace Jellyfin.Api.Controllers return NoContent(); } - var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read); - return File(stream, imageContentType); + return PhysicalFile(imagePath, imageContentType); } } } diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index afde4a433..2bde3443a 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -7,6 +7,7 @@ using System.Net.Mime; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; @@ -18,6 +19,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -248,6 +250,8 @@ namespace Jellyfin.Api.Controllers /// The task result contains an containing the images file stream. /// [HttpGet("Items/RemoteSearch/Image")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesImageFile] public async Task GetRemoteSearchImage( [FromQuery, Required] string imageUrl, [FromQuery, Required] string providerName) @@ -274,10 +278,7 @@ namespace Jellyfin.Api.Controllers } await DownloadImage(providerName, imageUrl, urlHash, pointerCachePath).ConfigureAwait(false); - - // Read the pointer file again - await using var fileStream = System.IO.File.OpenRead(pointerCachePath); - return new FileStreamResult(fileStream, MediaTypeNames.Application.Octet); + return PhysicalFile(pointerCachePath, MimeTypes.GetMimeType(pointerCachePath)); } /// @@ -293,6 +294,7 @@ namespace Jellyfin.Api.Controllers /// [HttpPost("Items/RemoteSearch/Apply/{id}")] [Authorize(Policy = Policies.RequiresElevation)] + [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ApplySearchCriteria( [FromRoute] Guid itemId, [FromBody, Required] RemoteSearchResult searchResult, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index a30873e9e..8c727cc59 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -8,6 +8,7 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; @@ -104,6 +105,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesFile("video/*", "audio/*")] public ActionResult GetFile([FromRoute] Guid itemId) { var item = _libraryManager.GetItemById(itemId); @@ -618,6 +620,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.Download)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesFile("video/*", "audio/*")] public async Task GetDownload([FromRoute] Guid itemId) { var item = _libraryManager.GetItemById(itemId); diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 3ccfc826d..07a176edd 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -9,6 +9,7 @@ using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; @@ -1067,6 +1068,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("ListingProviders/SchedulesDirect/Countries")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile(MediaTypeNames.Application.Json)] public async Task GetSchedulesDirectCountries() { var client = _httpClientFactory.CreateClient(); @@ -1175,6 +1177,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveRecordings/{recordingId}/stream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesVideoFile] public async Task GetLiveRecordingFile([FromRoute] string recordingId) { var path = _liveTvManager.GetEmbyTvActiveRecordingPath(recordingId); @@ -1205,6 +1208,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveStreamFiles/{streamId}/stream.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesVideoFile] public async Task GetLiveStreamFile([FromRoute] string streamId, [FromRoute] string container) { var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 1e154a039..2a204e650 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Net.Mime; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.MediaInfoDtos; @@ -286,6 +287,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [Produces(MediaTypeNames.Application.Octet)] + [ProducesFile(MediaTypeNames.Application.Octet)] public ActionResult GetBitrateTestBytes([FromQuery] int size = 102400) { const int MaxSize = 10_000_000; diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 988acccc3..a82431623 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -9,6 +9,7 @@ using System.Net.Mime; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -162,6 +163,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [Produces(MediaTypeNames.Application.Octet)] + [ProducesFile("text/*")] public async Task GetRemoteSubtitles([FromRoute, Required] string? id) { var result = await _subtitleManager.GetRemoteSubtitles(id, CancellationToken.None).ConfigureAwait(false); @@ -185,6 +187,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")] [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks?}/Stream.{format}", Name = "GetSubtitle_2")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile("text/*")] public async Task GetSubtitle( [FromRoute, Required] Guid itemId, [FromRoute, Required] string? mediaSourceId, @@ -251,6 +254,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] public async Task GetSubtitlePlaylist( [FromRoute] Guid itemId, diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index bbfd163de..256f39d0c 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; @@ -190,16 +192,13 @@ namespace Jellyfin.Api.Controllers [HttpGet("Logs/Log")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile(MediaTypeNames.Text.Plain)] public ActionResult GetLogFile([FromQuery, Required] string? name) { var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) .First(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); - // For older files, assume fully static - var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite; - - FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare); - return File(stream, "text/plain"); + return File(file.FullName, MediaTypeNames.Text.Plain); } /// diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index b13cf9fa5..b00653d9b 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.StreamingDtos; @@ -91,6 +92,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] + [ProducesAudioFile] public async Task GetUniversalAudioStream( [FromRoute] Guid itemId, [FromRoute] string? container, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index d67f82219..746710475 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -125,7 +125,7 @@ namespace Jellyfin.Api.Controllers /// Deletes a user. /// /// The user id. - /// User deleted. + /// User deleted. /// User not found. /// A indicating success or a if the user was not found. [HttpDelete("{userId}")] @@ -255,7 +255,7 @@ namespace Jellyfin.Api.Controllers /// /// The user id. /// The request. - /// Password successfully reset. + /// Password successfully reset. /// User is not allowed to update the password. /// User not found. /// A indicating success or a or a on failure. @@ -313,7 +313,7 @@ namespace Jellyfin.Api.Controllers /// /// The user id. /// The request. - /// Password successfully reset. + /// Password successfully reset. /// User is not allowed to update the password. /// User not found. /// A indicating success or a or a on failure. diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 76188f46d..92e82727e 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.PlaybackDtos; @@ -161,6 +162,7 @@ namespace Jellyfin.Api.Controllers /// A containing the hls file. [HttpGet("Videos/{itemId}/live.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesPlaylistFile] public async Task GetLiveHlsStream( [FromRoute] Guid itemId, [FromQuery] string? container, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index f42810c94..18023664b 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; @@ -159,7 +160,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success, or a if the video doesn't exist. [HttpDelete("{itemId}/AlternateSources")] [Authorize(Policy = Policies.RequiresElevation)] - [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteAlternateSources([FromRoute] Guid itemId) { @@ -326,6 +327,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("{itemId}/{stream=stream}.{container?}", Name = "HeadVideoStream_2")] [HttpHead("{itemId}/stream", Name = "HeadVideoStream")] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesVideoFile] public async Task GetVideoStream( [FromRoute] Guid itemId, [FromRoute] string? container, diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 0160a05f9..04b611123 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -16,6 +16,7 @@ using Jellyfin.Api.Auth.LocalAccessPolicy; using Jellyfin.Api.Auth.RequiresElevationPolicy; using Jellyfin.Api.Constants; using Jellyfin.Api.Controllers; +using Jellyfin.Server.Filters; using Jellyfin.Server.Formatters; using Jellyfin.Server.Models; using MediaBrowser.Common; @@ -249,6 +250,8 @@ namespace Jellyfin.Server.Extensions // TODO - remove when all types are supported in System.Text.Json c.AddSwaggerTypeMappings(); + + c.OperationFilter(); }); } diff --git a/Jellyfin.Server/Filters/FileResponseFilter.cs b/Jellyfin.Server/Filters/FileResponseFilter.cs new file mode 100644 index 000000000..8ea35c281 --- /dev/null +++ b/Jellyfin.Server/Filters/FileResponseFilter.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using Jellyfin.Api.Attributes; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Jellyfin.Server.Filters +{ + /// + public class FileResponseFilter : IOperationFilter + { + private const string SuccessCode = "200"; + private static readonly OpenApiMediaType _openApiMediaType = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "file" + } + }; + + /// + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + foreach (var attribute in context.ApiDescription.ActionDescriptor.EndpointMetadata) + { + if (attribute is ProducesFileAttribute producesFileAttribute) + { + // Get operation response values. + var (_, value) = operation.Responses + .FirstOrDefault(o => o.Key.Equals(SuccessCode, StringComparison.Ordinal)); + + // Operation doesn't have a response. + if (value == null) + { + continue; + } + + // Clear existing responses. + value.Content.Clear(); + + // Add all content-types as file. + foreach (var contentType in producesFileAttribute.GetContentTypes()) + { + value.Content.Add(contentType, _openApiMediaType); + } + + break; + } + } + } + } +} -- cgit v1.2.3 From 59d47ec3f52d8592f6a2aac405ee214cfda10081 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 5 Sep 2020 17:07:25 -0600 Subject: Make all FromRoute required --- Jellyfin.Api/Controllers/AlbumsController.cs | 5 +- Jellyfin.Api/Controllers/ArtistsController.cs | 3 +- Jellyfin.Api/Controllers/AudioController.cs | 5 +- Jellyfin.Api/Controllers/ChannelsController.cs | 4 +- Jellyfin.Api/Controllers/CollectionController.cs | 4 +- .../Controllers/ConfigurationController.cs | 4 +- .../Controllers/DisplayPreferencesController.cs | 4 +- Jellyfin.Api/Controllers/DlnaController.cs | 6 +- Jellyfin.Api/Controllers/DlnaServerController.cs | 18 +-- Jellyfin.Api/Controllers/DynamicHlsController.cs | 32 ++--- Jellyfin.Api/Controllers/GenresController.cs | 2 +- Jellyfin.Api/Controllers/HlsSegmentController.cs | 12 +- Jellyfin.Api/Controllers/ImageController.cs | 156 ++++++++++----------- Jellyfin.Api/Controllers/InstantMixController.cs | 12 +- Jellyfin.Api/Controllers/ItemLookupController.cs | 4 +- Jellyfin.Api/Controllers/ItemRefreshController.cs | 2 +- Jellyfin.Api/Controllers/ItemUpdateController.cs | 6 +- Jellyfin.Api/Controllers/ItemsController.cs | 4 +- Jellyfin.Api/Controllers/LibraryController.cs | 16 +-- Jellyfin.Api/Controllers/LiveTvController.cs | 26 ++-- Jellyfin.Api/Controllers/MediaInfoController.cs | 4 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 2 +- Jellyfin.Api/Controllers/PackageController.cs | 6 +- Jellyfin.Api/Controllers/PersonsController.cs | 3 +- Jellyfin.Api/Controllers/PlaylistsController.cs | 28 ++-- Jellyfin.Api/Controllers/PlaystateController.cs | 18 +-- Jellyfin.Api/Controllers/PluginsController.cs | 10 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 6 +- .../Controllers/ScheduledTasksController.cs | 2 +- Jellyfin.Api/Controllers/SessionController.cs | 6 +- Jellyfin.Api/Controllers/StudiosController.cs | 2 +- Jellyfin.Api/Controllers/SubtitleController.cs | 16 +-- Jellyfin.Api/Controllers/SuggestionsController.cs | 2 +- .../Controllers/UniversalAudioController.cs | 4 +- Jellyfin.Api/Controllers/UserController.cs | 14 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 20 +-- Jellyfin.Api/Controllers/UserViewsController.cs | 4 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 8 +- Jellyfin.Api/Controllers/YearsController.cs | 2 +- 40 files changed, 244 insertions(+), 240 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs index 190d4bd07..9b68d056f 100644 --- a/Jellyfin.Api/Controllers/AlbumsController.cs +++ b/Jellyfin.Api/Controllers/AlbumsController.cs @@ -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> 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> GetSimilarArtists( - [FromRoute] string artistId, + [FromRoute][Required] string artistId, [FromQuery] Guid? userId, [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 3f72830cd..b3dad14f3 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -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 /// An containing the artist. [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetArtistByName([FromRoute] string name, [FromQuery] Guid? userId) + public ActionResult GetArtistByName([FromRoute][Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 802cd026e..a81efe966 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -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 GetAudioStream( - [FromRoute] Guid itemId, - [FromRoute] string? container, + [FromRoute][Required] Guid itemId, + [FromRoute][Required] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index bdd7dfd96..93d9a9d00 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -90,7 +90,7 @@ namespace Jellyfin.Api.Controllers /// Channel features returned. /// An containing the channel features. [HttpGet("{channelId}/Features")] - public ActionResult GetChannelFeatures([FromRoute] string channelId) + public ActionResult GetChannelFeatures([FromRoute][Required] string channelId) { return _channelManager.GetChannelFeatures(channelId); } @@ -114,7 +114,7 @@ namespace Jellyfin.Api.Controllers /// [HttpGet("{channelId}/Items")] public async Task>> GetChannelItems( - [FromRoute] Guid channelId, + [FromRoute][Required] Guid channelId, [FromQuery] Guid? folderId, [FromQuery] Guid? userId, [FromQuery] int? startIndex, diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index c5910d6e8..0b1f655da 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task AddToCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task 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 /// A indicating success. [HttpDelete("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task RemoveFromCollection([FromRoute][Required] Guid collectionId, [FromQuery, Required] string? itemIds) { await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(false); return NoContent(); diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index 20fb0ec87..f13b6d38d 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -73,7 +73,7 @@ namespace Jellyfin.Api.Controllers /// Configuration. [HttpGet("Configuration/{key}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetNamedConfiguration([FromRoute] string? key) + public ActionResult 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 UpdateNamedConfiguration([FromRoute] string? key) + public async Task UpdateNamedConfiguration([FromRoute][Required] string? key) { var configurationType = _configurationManager.GetConfigurationType(key); var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index c3b67eec3..6422a45fd 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -43,7 +43,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] public ActionResult 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) diff --git a/Jellyfin.Api/Controllers/DlnaController.cs b/Jellyfin.Api/Controllers/DlnaController.cs index 397299a73..69c948174 100644 --- a/Jellyfin.Api/Controllers/DlnaController.cs +++ b/Jellyfin.Api/Controllers/DlnaController.cs @@ -59,7 +59,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Profiles/{profileId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetProfile([FromRoute] string profileId) + public ActionResult GetProfile([FromRoute][Required] string profileId) { var profile = _dlnaManager.GetProfile(profileId); if (profile == null) @@ -80,7 +80,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 +117,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) diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs index 9ebd89819..832fcc8c6 100644 --- a/Jellyfin.Api/Controllers/DlnaServerController.cs +++ b/Jellyfin.Api/Controllers/DlnaServerController.cs @@ -45,7 +45,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 +65,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 +81,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 +97,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 +108,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/ContentDirectory/Control")] - public async Task> ProcessContentDirectoryControlRequest([FromRoute] string serverId) + public async Task> ProcessContentDirectoryControlRequest([FromRoute][Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _contentDirectory).ConfigureAwait(false); } @@ -119,7 +119,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/ConnectionManager/Control")] - public async Task> ProcessConnectionManagerControlRequest([FromRoute] string serverId) + public async Task> ProcessConnectionManagerControlRequest([FromRoute][Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _connectionManager).ConfigureAwait(false); } @@ -130,7 +130,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/MediaReceiverRegistrar/Control")] - public async Task> ProcessMediaReceiverRegistrarControlRequest([FromRoute] string serverId) + public async Task> ProcessMediaReceiverRegistrarControlRequest([FromRoute][Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _mediaReceiverRegistrar).ConfigureAwait(false); } @@ -185,7 +185,7 @@ namespace Jellyfin.Api.Controllers /// Icon stream. [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 +196,7 @@ namespace Jellyfin.Api.Controllers /// The icon filename. /// Icon stream. [HttpGet("icons/{fileName}")] - public ActionResult GetIcon([FromRoute] string fileName) + public ActionResult GetIcon([FromRoute][Required] string fileName) { return GetIconInternal(fileName); } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 0c884d58d..ec711ce34 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -167,8 +167,8 @@ namespace Jellyfin.Api.Controllers [HttpHead("Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task 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 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 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 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 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 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, diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 55ad71200..230aff417 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers /// An containing the genre. [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetGenre([FromRoute] string genreName, [FromQuery] Guid? userId) + public ActionResult GetGenre([FromRoute][Required] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 816252f80..304b5ce82 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -55,7 +55,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 +75,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 +114,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(); diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index a204fe35c..3cde4062d 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -90,9 +90,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 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 +137,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 +175,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +205,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] public async Task 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 +238,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +264,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetItemImageInfos([FromRoute] Guid itemId) + public async Task>> GetItemImageInfos([FromRoute][Required] Guid itemId) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -352,10 +352,10 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +368,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 +430,23 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +508,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +524,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 +586,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +602,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 +664,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +680,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 +742,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +758,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 +820,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +836,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 +898,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task 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 +914,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) diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 73bd30c4d..11f2b2495 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Songs/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> 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> 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> 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> 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> 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> GetInstantMixFromItem( - [FromRoute] Guid id, + [FromRoute][Required] Guid id, [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index afde4a433..f1169f3d2 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -72,7 +72,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult> GetExternalIdInfos([FromRoute] Guid itemId) + public ActionResult> 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 ApplySearchCriteria( - [FromRoute] Guid itemId, + [FromRoute][Required] Guid itemId, [FromBody, Required] RemoteSearchResult searchResult, [FromQuery] bool replaceAllImages = true) { diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs index 3f5d305c1..0d1e02a78 100644 --- a/Jellyfin.Api/Controllers/ItemRefreshController.cs +++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs @@ -53,7 +53,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, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index ec52f4996..0d064fffb 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Items/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task UpdateItem([FromRoute] Guid itemId, [FromBody, Required] BaseItemDto request) + public async Task 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 GetMetadataEditorInfo([FromRoute] Guid itemId) + public ActionResult 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) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index f9273bad6..cc8051365 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -144,7 +144,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{uId}/Items", Name = "GetItems_2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( - [FromRoute] Guid? uId, + [FromRoute][Required] Guid? uId, [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, @@ -529,7 +529,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Items/Resume")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetResumeItems( - [FromRoute] Guid userId, + [FromRoute][Required] Guid userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? searchTerm, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index a30873e9e..ac28fd6ca 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -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 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 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 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> GetAncestors([FromRoute] Guid itemId, [FromQuery] Guid? userId) + public ActionResult> 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 GetDownload([FromRoute] Guid itemId) + public async Task 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> GetSimilarItems( - [FromRoute] Guid itemId, + [FromRoute][Required] Guid itemId, [FromQuery] string? excludeArtistIds, [FromQuery] Guid? userId, [FromQuery] int? limit, diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index eace0f911..e086e9029 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -209,7 +209,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Channels/{channelId}")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult GetChannel([FromRoute] Guid channelId, [FromQuery] Guid? userId) + public ActionResult GetChannel([FromRoute][Required] Guid channelId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) @@ -406,7 +406,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Recordings/{recordingId}")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult GetRecording([FromRoute] Guid recordingId, [FromQuery] Guid? userId) + public ActionResult GetRecording([FromRoute][Required] Guid recordingId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) @@ -428,7 +428,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 +744,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProgram( - [FromRoute] string programId, + [FromRoute][Required] string programId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) @@ -765,7 +765,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 +792,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Timers/{timerId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task CancelTimer([FromRoute] string timerId) + public async Task CancelTimer([FromRoute][Required] string timerId) { AssertUserCanManageLiveTv(); await _liveTvManager.CancelTimer(timerId).ConfigureAwait(false); @@ -810,7 +810,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 UpdateTimer([FromRoute] string timerId, [FromBody] TimerInfoDto timerInfo) + public async Task UpdateTimer([FromRoute][Required] string timerId, [FromBody] TimerInfoDto timerInfo) { AssertUserCanManageLiveTv(); await _liveTvManager.UpdateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false); @@ -844,7 +844,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetSeriesTimer([FromRoute] string timerId) + public async Task> GetSeriesTimer([FromRoute][Required] string timerId) { var timer = await _liveTvManager.GetSeriesTimer(timerId, CancellationToken.None).ConfigureAwait(false); if (timer == null) @@ -884,7 +884,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("SeriesTimers/{timerId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task CancelSeriesTimer([FromRoute] string timerId) + public async Task CancelSeriesTimer([FromRoute][Required] string timerId) { AssertUserCanManageLiveTv(); await _liveTvManager.CancelSeriesTimer(timerId).ConfigureAwait(false); @@ -902,7 +902,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 UpdateSeriesTimer([FromRoute] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo) + public async Task UpdateSeriesTimer([FromRoute][Required] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo) { AssertUserCanManageLiveTv(); await _liveTvManager.UpdateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false); @@ -934,7 +934,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Obsolete("This endpoint is obsolete.")] - public ActionResult GetRecordingGroup([FromRoute] Guid? groupId) + public ActionResult GetRecordingGroup([FromRoute][Required] Guid? groupId) { return NotFound(); } @@ -1176,7 +1176,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveRecordings/{recordingId}/stream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetLiveRecordingFile([FromRoute] string recordingId) + public async Task GetLiveRecordingFile([FromRoute][Required] string recordingId) { var path = _liveTvManager.GetEmbyTvActiveRecordingPath(recordingId); @@ -1206,7 +1206,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveStreamFiles/{streamId}/stream.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetLiveStreamFile([FromRoute] string streamId, [FromRoute] string container) + public async Task GetLiveStreamFile([FromRoute][Required] string streamId, [FromRoute][Required] string container) { var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false); if (liveStreamInfo == null) diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 1e154a039..8bb0ace15 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers /// A containing a with the playback information. [HttpGet("Items/{itemId}/PlaybackInfo")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery, Required] Guid? userId) + public async Task> 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> GetPostedPlaybackInfo( - [FromRoute] Guid itemId, + [FromRoute][Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] long? maxStreamingBitrate, [FromQuery] long? startTimeTicks, diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 0d319137a..493386e93 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -258,7 +258,7 @@ namespace Jellyfin.Api.Controllers /// An containing a with the music genre. [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetMusicGenre([FromRoute] string genreName, [FromQuery] Guid? userId) + public ActionResult GetMusicGenre([FromRoute][Required] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 3d6a87909..ea85e1909 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Packages/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> 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 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(); diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index b6ccec666..be5fb7f7c 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -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 GetPerson([FromRoute] string name, [FromQuery] Guid? userId) + public ActionResult GetPerson([FromRoute][Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index f4c6a9253..07bb108e3 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task 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 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 /// An on success. [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds) + public async Task 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 /// The original playlist items. [HttpGet("{playlistId}/Items")] public ActionResult> 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) diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 22f2ca5c3..797c5aa36 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -71,8 +71,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("Users/{userId}/PlayedItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult 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 +96,7 @@ namespace Jellyfin.Api.Controllers /// A containing the . [HttpDelete("Users/{userId}/PlayedItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult MarkUnplayedItem([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult MarkUnplayedItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { var user = _userManager.GetUserById(userId); var session = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -195,8 +195,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task 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 +245,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task 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 +297,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackStopped( - [FromRoute] Guid userId, - [FromRoute] Guid itemId, + [FromRoute][Required] Guid userId, + [FromRoute][Required] Guid itemId, [FromQuery] string? mediaSourceId, [FromQuery] string? nextMediaType, [FromQuery] long? positionTicks, diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index a82f2621a..d0de1a422 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -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 GetPluginConfiguration([FromRoute] Guid pluginId) + public ActionResult 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 UpdatePluginConfiguration([FromRoute] Guid pluginId) + public async Task 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 GetRegistrationStatus([FromRoute] string? name) + public ActionResult 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. diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 81aefd15c..597d3f2f6 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -70,7 +70,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> 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> GetRemoteImageProviders([FromRoute] Guid itemId) + public ActionResult> 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 DownloadRemoteImage( - [FromRoute] Guid itemId, + [FromRoute][Required] Guid itemId, [FromQuery, Required] ImageType type, [FromQuery] string? imageUrl) { diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs index e672070c0..ea6288de0 100644 --- a/Jellyfin.Api/Controllers/ScheduledTasksController.cs +++ b/Jellyfin.Api/Controllers/ScheduledTasksController.cs @@ -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)); diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index ba8d51598..4f0f241c6 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -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(); diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 6f2787d93..b3bb06500 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -259,7 +259,7 @@ namespace Jellyfin.Api.Controllers /// An containing the studio. [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetStudio([FromRoute] string name, [FromQuery] Guid? userId) + public ActionResult GetStudio([FromRoute][Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 988acccc3..1096a06d2 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -86,8 +86,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult 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>> 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 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 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); diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 42db6b6a1..4fff3cd3e 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Suggestions")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSuggestions( - [FromRoute] Guid userId, + [FromRoute][Required] Guid userId, [FromQuery] string? mediaType, [FromQuery] string? type, [FromQuery] int? startIndex, diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index b13cf9fa5..d57f23d9c 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -92,8 +92,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] public async Task GetUniversalAudioStream( - [FromRoute] Guid itemId, - [FromRoute] string? container, + [FromRoute][Required] Guid itemId, + [FromRoute][Required] string? container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index d67f82219..a9cab9cde 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -108,7 +108,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.IgnoreParentalControl)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetUserById([FromRoute] Guid userId) + public ActionResult 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 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 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)) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index f55ff6f3d..809fbf43a 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -70,7 +70,7 @@ namespace Jellyfin.Api.Controllers /// An containing the d item. [HttpGet("Users/{userId}/Items/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetItem([FromRoute] Guid userId, [FromRoute] Guid itemId) + public async Task> GetItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -93,7 +93,7 @@ namespace Jellyfin.Api.Controllers /// An containing the user's root folder. [HttpGet("Users/{userId}/Items/Root")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetRootFolder([FromRoute] Guid userId) + public ActionResult GetRootFolder([FromRoute][Required] Guid userId) { var user = _userManager.GetUserById(userId); var item = _libraryManager.GetUserRootFolder(); @@ -110,7 +110,7 @@ namespace Jellyfin.Api.Controllers /// An containing the intros to play. [HttpGet("Users/{userId}/Items/{itemId}/Intros")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetIntros([FromRoute] Guid userId, [FromRoute] Guid itemId) + public async Task>> GetIntros([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -138,7 +138,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpPost("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult MarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult MarkFavoriteItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { return MarkFavorite(userId, itemId, true); } @@ -152,7 +152,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpDelete("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult UnmarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult UnmarkFavoriteItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { return MarkFavorite(userId, itemId, false); } @@ -166,7 +166,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpDelete("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult DeleteUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult DeleteUserItemRating([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { return UpdateUserItemRatingInternal(userId, itemId, null); } @@ -181,7 +181,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpPost("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult UpdateUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool? likes) + public ActionResult UpdateUserItemRating([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId, [FromQuery] bool? likes) { return UpdateUserItemRatingInternal(userId, itemId, likes); } @@ -195,7 +195,7 @@ namespace Jellyfin.Api.Controllers /// The items local trailers. [HttpGet("Users/{userId}/Items/{itemId}/LocalTrailers")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetLocalTrailers([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult> GetLocalTrailers([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -230,7 +230,7 @@ namespace Jellyfin.Api.Controllers /// An containing the special features. [HttpGet("Users/{userId}/Items/{itemId}/SpecialFeatures")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetSpecialFeatures([FromRoute] Guid userId, [FromRoute] Guid itemId) + public ActionResult> GetSpecialFeatures([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -264,7 +264,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Items/Latest")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetLatestMedia( - [FromRoute] Guid userId, + [FromRoute][Required] Guid userId, [FromQuery] Guid? parentId, [FromQuery] string? fields, [FromQuery] string? includeItemTypes, diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index 6df7cc779..fb78707f8 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Views")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetUserViews( - [FromRoute] Guid userId, + [FromRoute][Required] Guid userId, [FromQuery] bool? includeExternalContent, [FromQuery] string? presetViews, [FromQuery] bool includeHidden = false) @@ -126,7 +126,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/GroupingOptions")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult> GetGroupingOptions([FromRoute] Guid userId) + public ActionResult> GetGroupingOptions([FromRoute][Required] Guid userId) { var user = _userManager.GetUserById(userId); if (user == null) diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 76188f46d..77f21fcf3 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -162,7 +162,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/live.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetLiveHlsStream( - [FromRoute] Guid itemId, + [FromRoute][Required] Guid itemId, [FromQuery] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 83b03f965..224cc7b72 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{itemId}/AdditionalParts")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid? userId) + public ActionResult> 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 DeleteAlternateSources([FromRoute] Guid itemId) + public async Task 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 GetVideoStream( - [FromRoute] Guid itemId, - [FromRoute] string? container, + [FromRoute][Required] Guid itemId, + [FromRoute][Required] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index eb91ac23e..620edf905 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -179,7 +179,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{year}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetYear([FromRoute] int year, [FromQuery] Guid? userId) + public ActionResult GetYear([FromRoute][Required] int year, [FromQuery] Guid? userId) { var item = _libraryManager.GetYear(year); if (item == null) -- cgit v1.2.3 From b64108923aebd0f3e5a960462ad4cb2dbd74b6cc Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 5 Sep 2020 17:11:44 -0600 Subject: Add missing references --- Jellyfin.Api/Controllers/ChannelsController.cs | 1 + Jellyfin.Api/Controllers/DlnaController.cs | 1 + Jellyfin.Api/Controllers/DlnaServerController.cs | 1 + Jellyfin.Api/Controllers/GenresController.cs | 1 + Jellyfin.Api/Controllers/HlsSegmentController.cs | 1 + Jellyfin.Api/Controllers/ImageController.cs | 1 + Jellyfin.Api/Controllers/ItemRefreshController.cs | 1 + Jellyfin.Api/Controllers/ItemsController.cs | 1 + Jellyfin.Api/Controllers/LiveTvController.cs | 1 + Jellyfin.Api/Controllers/MusicGenresController.cs | 1 + Jellyfin.Api/Controllers/PlaystateController.cs | 1 + Jellyfin.Api/Controllers/StudiosController.cs | 1 + Jellyfin.Api/Controllers/SuggestionsController.cs | 1 + Jellyfin.Api/Controllers/UniversalAudioController.cs | 1 + Jellyfin.Api/Controllers/UserLibraryController.cs | 1 + Jellyfin.Api/Controllers/UserViewsController.cs | 1 + Jellyfin.Api/Controllers/VideoHlsController.cs | 1 + Jellyfin.Api/Controllers/YearsController.cs | 1 + 18 files changed, 18 insertions(+) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index 93d9a9d00..36dff2ad3 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/DlnaController.cs b/Jellyfin.Api/Controllers/DlnaController.cs index 69c948174..e6f0fb41e 100644 --- a/Jellyfin.Api/Controllers/DlnaController.cs +++ b/Jellyfin.Api/Controllers/DlnaController.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Constants; using MediaBrowser.Controller.Dlna; using MediaBrowser.Model.Dlna; diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs index 832fcc8c6..2f93ca2c2 100644 --- a/Jellyfin.Api/Controllers/DlnaServerController.cs +++ b/Jellyfin.Api/Controllers/DlnaServerController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Mime; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 230aff417..53be16370 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 304b5ce82..58c583d09 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 3cde4062d..e28957c9b 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs index 0d1e02a78..87086c681 100644 --- a/Jellyfin.Api/Controllers/ItemRefreshController.cs +++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs @@ -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; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index cc8051365..170606b11 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index e086e9029..fb3f0f5f5 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 493386e93..df97c0ab9 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 797c5aa36..091f884d2 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index b3bb06500..0208ebfbb 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 4fff3cd3e..52593b1ce 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index d57f23d9c..a3678454f 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 809fbf43a..f93e80393 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index fb78707f8..8582a5a21 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using Jellyfin.Api.Extensions; diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 77f21fcf3..cf667bf43 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; using System.Threading; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 620edf905..b83b09c35 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -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; -- cgit v1.2.3 From 29fc882037162b8c7a79557556be9d535e94779f Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 6 Sep 2020 09:07:27 -0600 Subject: merge all attributes --- Jellyfin.Api/Controllers/AlbumsController.cs | 4 +- Jellyfin.Api/Controllers/ArtistsController.cs | 2 +- Jellyfin.Api/Controllers/AudioController.cs | 4 +- Jellyfin.Api/Controllers/ChannelsController.cs | 4 +- Jellyfin.Api/Controllers/CollectionController.cs | 4 +- .../Controllers/ConfigurationController.cs | 4 +- .../Controllers/DisplayPreferencesController.cs | 4 +- Jellyfin.Api/Controllers/DlnaController.cs | 6 +- Jellyfin.Api/Controllers/DlnaServerController.cs | 18 +-- Jellyfin.Api/Controllers/DynamicHlsController.cs | 32 ++--- Jellyfin.Api/Controllers/GenresController.cs | 2 +- Jellyfin.Api/Controllers/HlsSegmentController.cs | 12 +- Jellyfin.Api/Controllers/ImageController.cs | 156 ++++++++++----------- Jellyfin.Api/Controllers/InstantMixController.cs | 12 +- Jellyfin.Api/Controllers/ItemLookupController.cs | 4 +- Jellyfin.Api/Controllers/ItemRefreshController.cs | 2 +- Jellyfin.Api/Controllers/ItemUpdateController.cs | 6 +- Jellyfin.Api/Controllers/ItemsController.cs | 4 +- Jellyfin.Api/Controllers/LibraryController.cs | 16 +-- Jellyfin.Api/Controllers/LiveTvController.cs | 26 ++-- Jellyfin.Api/Controllers/MediaInfoController.cs | 4 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 2 +- Jellyfin.Api/Controllers/PackageController.cs | 6 +- Jellyfin.Api/Controllers/PersonsController.cs | 2 +- Jellyfin.Api/Controllers/PlaylistsController.cs | 28 ++-- Jellyfin.Api/Controllers/PlaystateController.cs | 18 +-- Jellyfin.Api/Controllers/PluginsController.cs | 10 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 6 +- .../Controllers/ScheduledTasksController.cs | 2 +- Jellyfin.Api/Controllers/SessionController.cs | 6 +- Jellyfin.Api/Controllers/StudiosController.cs | 2 +- Jellyfin.Api/Controllers/SubtitleController.cs | 16 +-- Jellyfin.Api/Controllers/SuggestionsController.cs | 2 +- .../Controllers/UniversalAudioController.cs | 4 +- Jellyfin.Api/Controllers/UserController.cs | 14 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 20 +-- Jellyfin.Api/Controllers/UserViewsController.cs | 4 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 8 +- Jellyfin.Api/Controllers/YearsController.cs | 2 +- 40 files changed, 240 insertions(+), 240 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs index 9b68d056f..357f646a2 100644 --- a/Jellyfin.Api/Controllers/AlbumsController.cs +++ b/Jellyfin.Api/Controllers/AlbumsController.cs @@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Albums/{albumId}/Similar")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarAlbums( - [FromRoute][Required] string albumId, + [FromRoute, Required] string albumId, [FromQuery] Guid? userId, [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) @@ -85,7 +85,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Artists/{artistId}/Similar")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarArtists( - [FromRoute][Required] string artistId, + [FromRoute, Required] string artistId, [FromQuery] Guid? userId, [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index b3dad14f3..d38214116 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -470,7 +470,7 @@ namespace Jellyfin.Api.Controllers /// An containing the artist. [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetArtistByName([FromRoute][Required] string name, [FromQuery] Guid? userId) + public ActionResult GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index a81efe966..3bec43720 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -90,8 +90,8 @@ namespace Jellyfin.Api.Controllers [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetAudioStream( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] string? container, + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index 36dff2ad3..33a969f85 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -91,7 +91,7 @@ namespace Jellyfin.Api.Controllers /// Channel features returned. /// An containing the channel features. [HttpGet("{channelId}/Features")] - public ActionResult GetChannelFeatures([FromRoute][Required] string channelId) + public ActionResult GetChannelFeatures([FromRoute, Required] string channelId) { return _channelManager.GetChannelFeatures(channelId); } @@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers /// [HttpGet("{channelId}/Items")] public async Task>> GetChannelItems( - [FromRoute][Required] Guid channelId, + [FromRoute, Required] Guid channelId, [FromQuery] Guid? folderId, [FromQuery] Guid? userId, [FromQuery] int? startIndex, diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 0b1f655da..f78690b06 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task AddToCollection([FromRoute][Required] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task 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 /// A indicating success. [HttpDelete("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromCollection([FromRoute][Required] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task RemoveFromCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string? itemIds) { await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(false); return NoContent(); diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index f13b6d38d..5fd4c712a 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -73,7 +73,7 @@ namespace Jellyfin.Api.Controllers /// Configuration. [HttpGet("Configuration/{key}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetNamedConfiguration([FromRoute][Required] string? key) + public ActionResult 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 UpdateNamedConfiguration([FromRoute][Required] string? key) + public async Task UpdateNamedConfiguration([FromRoute, Required] string? key) { var configurationType = _configurationManager.GetConfigurationType(key); var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 6422a45fd..6bb7b1910 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -43,7 +43,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] public ActionResult GetDisplayPreferences( - [FromRoute][Required] 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][Required] string? displayPreferencesId, + [FromRoute, Required] string? displayPreferencesId, [FromQuery, Required] Guid userId, [FromQuery, Required] string? client, [FromBody, Required] DisplayPreferencesDto displayPreferences) diff --git a/Jellyfin.Api/Controllers/DlnaController.cs b/Jellyfin.Api/Controllers/DlnaController.cs index e6f0fb41e..052a6aff2 100644 --- a/Jellyfin.Api/Controllers/DlnaController.cs +++ b/Jellyfin.Api/Controllers/DlnaController.cs @@ -60,7 +60,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Profiles/{profileId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetProfile([FromRoute][Required] string profileId) + public ActionResult GetProfile([FromRoute, Required] string profileId) { var profile = _dlnaManager.GetProfile(profileId); if (profile == null) @@ -81,7 +81,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Profiles/{profileId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteProfile([FromRoute][Required] string profileId) + public ActionResult DeleteProfile([FromRoute, Required] string profileId) { var existingDeviceProfile = _dlnaManager.GetProfile(profileId); if (existingDeviceProfile == null) @@ -118,7 +118,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Profiles/{profileId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UpdateProfile([FromRoute][Required] string profileId, [FromBody] DeviceProfile deviceProfile) + public ActionResult UpdateProfile([FromRoute, Required] string profileId, [FromBody] DeviceProfile deviceProfile) { var existingDeviceProfile = _dlnaManager.GetProfile(profileId); if (existingDeviceProfile == null) diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs index 2f93ca2c2..8cdea4367 100644 --- a/Jellyfin.Api/Controllers/DlnaServerController.cs +++ b/Jellyfin.Api/Controllers/DlnaServerController.cs @@ -46,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][Required] string serverId) + public ActionResult GetDescriptionXml([FromRoute, Required] string serverId) { var url = GetAbsoluteUri(); var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase)); @@ -66,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][Required] string serverId) + public ActionResult GetContentDirectory([FromRoute, Required] string serverId) { return Ok(_contentDirectory.GetServiceXml()); } @@ -82,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][Required] string serverId) + public ActionResult GetMediaReceiverRegistrar([FromRoute, Required] string serverId) { return Ok(_mediaReceiverRegistrar.GetServiceXml()); } @@ -98,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][Required] string serverId) + public ActionResult GetConnectionManager([FromRoute, Required] string serverId) { return Ok(_connectionManager.GetServiceXml()); } @@ -109,7 +109,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/ContentDirectory/Control")] - public async Task> ProcessContentDirectoryControlRequest([FromRoute][Required] string serverId) + public async Task> ProcessContentDirectoryControlRequest([FromRoute, Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _contentDirectory).ConfigureAwait(false); } @@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/ConnectionManager/Control")] - public async Task> ProcessConnectionManagerControlRequest([FromRoute][Required] string serverId) + public async Task> ProcessConnectionManagerControlRequest([FromRoute, Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _connectionManager).ConfigureAwait(false); } @@ -131,7 +131,7 @@ namespace Jellyfin.Api.Controllers /// Server UUID. /// Control response. [HttpPost("{serverId}/MediaReceiverRegistrar/Control")] - public async Task> ProcessMediaReceiverRegistrarControlRequest([FromRoute][Required] string serverId) + public async Task> ProcessMediaReceiverRegistrarControlRequest([FromRoute, Required] string serverId) { return await ProcessControlRequestInternalAsync(serverId, Request.Body, _mediaReceiverRegistrar).ConfigureAwait(false); } @@ -186,7 +186,7 @@ namespace Jellyfin.Api.Controllers /// Icon stream. [HttpGet("{serverId}/icons/{fileName}")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")] - public ActionResult GetIconId([FromRoute][Required] string serverId, [FromRoute][Required] string fileName) + public ActionResult GetIconId([FromRoute, Required] string serverId, [FromRoute, Required] string fileName) { return GetIconInternal(fileName); } @@ -197,7 +197,7 @@ namespace Jellyfin.Api.Controllers /// The icon filename. /// Icon stream. [HttpGet("icons/{fileName}")] - public ActionResult GetIcon([FromRoute][Required] string fileName) + public ActionResult GetIcon([FromRoute, Required] string fileName) { return GetIconInternal(fileName); } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index ec711ce34..d81c7996e 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -167,8 +167,8 @@ namespace Jellyfin.Api.Controllers [HttpHead("Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetMasterHlsVideoPlaylist( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] 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 GetMasterHlsAudioPlaylist( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] 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 GetVariantHlsVideoPlaylist( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] 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 GetVariantHlsAudioPlaylist( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] 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 GetHlsVideoSegment( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] string playlistId, - [FromRoute][Required] int segmentId, - [FromRoute][Required] 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 GetHlsAudioSegment( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] string playlistId, - [FromRoute][Required] int segmentId, - [FromRoute][Required] 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, diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 53be16370..de6aa86c9 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -261,7 +261,7 @@ namespace Jellyfin.Api.Controllers /// An containing the genre. [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetGenre([FromRoute][Required] string genreName, [FromQuery] Guid? userId) + public ActionResult GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 58c583d09..e96df83fa 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -56,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][Required] string itemId, [FromRoute][Required] 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); @@ -76,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][Required] string itemId, [FromRoute][Required] 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); @@ -115,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][Required] string itemId, - [FromRoute][Required] string playlistId, - [FromRoute][Required] string segmentId, - [FromRoute][Required] 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(); diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index e28957c9b..453da5711 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -91,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 PostUserImage( - [FromRoute][Required] Guid userId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? index = null) + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int? index = null) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -138,9 +138,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public ActionResult DeleteUserImage( - [FromRoute][Required] Guid userId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? index = null) + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int? index = null) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -176,9 +176,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteItemImage( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] Guid itemId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -206,9 +206,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] public async Task SetItemImage( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] Guid itemId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -239,9 +239,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateItemImageIndex( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int imageIndex, + [FromRoute, Required] Guid itemId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int imageIndex, [FromQuery] int newIndex) { var item = _libraryManager.GetItemById(itemId); @@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetItemImageInfos([FromRoute][Required] Guid itemId) + public async Task>> GetItemImageInfos([FromRoute, Required] Guid itemId) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -353,10 +353,10 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetItemImage( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? maxWidth, - [FromRoute][Required] 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, @@ -369,7 +369,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -431,23 +431,23 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetItemImage2( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] ImageType imageType, - [FromRoute][Required] int? maxWidth, - [FromRoute][Required] 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][Required] string tag, + [FromRoute, Required] string tag, [FromQuery] bool? cropWhitespace, - [FromRoute][Required] string format, + [FromRoute, Required] string format, [FromQuery] bool? addPlayedIndicator, - [FromRoute][Required] double? percentPlayed, - [FromRoute][Required] int? unplayedCount, + [FromRoute, Required] double? percentPlayed, + [FromRoute, Required] int? unplayedCount, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -509,14 +509,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetArtistImage( - [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, + [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, @@ -525,7 +525,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetArtist(name); if (item == null) @@ -587,14 +587,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetGenreImage( - [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, + [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, @@ -603,7 +603,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -665,14 +665,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetMusicGenreImage( - [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, + [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, @@ -681,7 +681,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -743,14 +743,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetPersonImage( - [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, + [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, @@ -759,7 +759,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -821,14 +821,14 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetStudioImage( - [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, + [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, @@ -837,7 +837,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -899,8 +899,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetUserImage( - [FromRoute][Required] Guid userId, - [FromRoute][Required] ImageType imageType, + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, [FromQuery] string? tag, [FromQuery] string? format, [FromQuery] int? maxWidth, @@ -915,7 +915,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute][Required] int? imageIndex = null) + [FromRoute, Required] int? imageIndex = null) { var user = _userManager.GetUserById(userId); if (user == null) diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 11f2b2495..01bfbba4e 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Songs/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromSong( - [FromRoute][Required] 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> GetInstantMixFromAlbum( - [FromRoute][Required] 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> GetInstantMixFromPlaylist( - [FromRoute][Required] 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> GetInstantMixFromArtists( - [FromRoute][Required] 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> GetInstantMixFromMusicGenres( - [FromRoute][Required] 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> GetInstantMixFromItem( - [FromRoute][Required] Guid id, + [FromRoute, Required] Guid id, [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index f1169f3d2..f7b515cec 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -72,7 +72,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult> GetExternalIdInfos([FromRoute][Required] Guid itemId) + public ActionResult> 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 ApplySearchCriteria( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromBody, Required] RemoteSearchResult searchResult, [FromQuery] bool replaceAllImages = true) { diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs index 87086c681..49865eb5e 100644 --- a/Jellyfin.Api/Controllers/ItemRefreshController.cs +++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs @@ -54,7 +54,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult Post( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromQuery] MetadataRefreshMode metadataRefreshMode = MetadataRefreshMode.None, [FromQuery] MetadataRefreshMode imageRefreshMode = MetadataRefreshMode.None, [FromQuery] bool replaceAllMetadata = false, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 0d064fffb..4308a434d 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Items/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task UpdateItem([FromRoute][Required] Guid itemId, [FromBody, Required] BaseItemDto request) + public async Task 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 GetMetadataEditorInfo([FromRoute][Required] Guid itemId) + public ActionResult 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][Required] 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) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 170606b11..06ab176b2 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{uId}/Items", Name = "GetItems_2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( - [FromRoute][Required] Guid? uId, + [FromRoute, Required] Guid? uId, [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, @@ -530,7 +530,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Items/Resume")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetResumeItems( - [FromRoute][Required] Guid userId, + [FromRoute, Required] Guid userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? searchTerm, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index ac28fd6ca..f1f52961d 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -104,7 +104,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetFile([FromRoute][Required] 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 GetThemeSongs( - [FromRoute][Required] 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 GetThemeVideos( - [FromRoute][Required] 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 GetThemeMedia( - [FromRoute][Required] 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> GetAncestors([FromRoute][Required] Guid itemId, [FromQuery] Guid? userId) + public ActionResult> 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][Required] string? tmdbId, [FromRoute][Required] 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 GetDownload([FromRoute][Required] Guid itemId) + public async Task 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> GetSimilarItems( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromQuery] string? excludeArtistIds, [FromQuery] Guid? userId, [FromQuery] int? limit, diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index fb3f0f5f5..8678844d2 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -210,7 +210,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Channels/{channelId}")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult GetChannel([FromRoute][Required] Guid channelId, [FromQuery] Guid? userId) + public ActionResult GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) @@ -407,7 +407,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Recordings/{recordingId}")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult GetRecording([FromRoute][Required] Guid recordingId, [FromQuery] Guid? userId) + public ActionResult GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) @@ -429,7 +429,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Tuners/{tunerId}/Reset")] [ProducesResponseType(StatusCodes.Status204NoContent)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult ResetTuner([FromRoute][Required] string tunerId) + public ActionResult ResetTuner([FromRoute, Required] string tunerId) { AssertUserCanManageLiveTv(); _liveTvManager.ResetTuner(tunerId, CancellationToken.None); @@ -745,7 +745,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProgram( - [FromRoute][Required] string programId, + [FromRoute, Required] string programId, [FromQuery] Guid? userId) { var user = userId.HasValue && !userId.Equals(Guid.Empty) @@ -766,7 +766,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteRecording([FromRoute][Required] Guid recordingId) + public ActionResult DeleteRecording([FromRoute, Required] Guid recordingId) { AssertUserCanManageLiveTv(); @@ -793,7 +793,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Timers/{timerId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task CancelTimer([FromRoute][Required] string timerId) + public async Task CancelTimer([FromRoute, Required] string timerId) { AssertUserCanManageLiveTv(); await _liveTvManager.CancelTimer(timerId).ConfigureAwait(false); @@ -811,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 UpdateTimer([FromRoute][Required] string timerId, [FromBody] TimerInfoDto timerInfo) + public async Task UpdateTimer([FromRoute, Required] string timerId, [FromBody] TimerInfoDto timerInfo) { AssertUserCanManageLiveTv(); await _liveTvManager.UpdateTimer(timerInfo, CancellationToken.None).ConfigureAwait(false); @@ -845,7 +845,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetSeriesTimer([FromRoute][Required] string timerId) + public async Task> GetSeriesTimer([FromRoute, Required] string timerId) { var timer = await _liveTvManager.GetSeriesTimer(timerId, CancellationToken.None).ConfigureAwait(false); if (timer == null) @@ -885,7 +885,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("SeriesTimers/{timerId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task CancelSeriesTimer([FromRoute][Required] string timerId) + public async Task CancelSeriesTimer([FromRoute, Required] string timerId) { AssertUserCanManageLiveTv(); await _liveTvManager.CancelSeriesTimer(timerId).ConfigureAwait(false); @@ -903,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 UpdateSeriesTimer([FromRoute][Required] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo) + public async Task UpdateSeriesTimer([FromRoute, Required] string timerId, [FromBody] SeriesTimerInfoDto seriesTimerInfo) { AssertUserCanManageLiveTv(); await _liveTvManager.UpdateSeriesTimer(seriesTimerInfo, CancellationToken.None).ConfigureAwait(false); @@ -935,7 +935,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Obsolete("This endpoint is obsolete.")] - public ActionResult GetRecordingGroup([FromRoute][Required] Guid? groupId) + public ActionResult GetRecordingGroup([FromRoute, Required] Guid? groupId) { return NotFound(); } @@ -1177,7 +1177,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveRecordings/{recordingId}/stream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetLiveRecordingFile([FromRoute][Required] string recordingId) + public async Task GetLiveRecordingFile([FromRoute, Required] string recordingId) { var path = _liveTvManager.GetEmbyTvActiveRecordingPath(recordingId); @@ -1207,7 +1207,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("LiveStreamFiles/{streamId}/stream.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task GetLiveStreamFile([FromRoute][Required] string streamId, [FromRoute][Required] string container) + public async Task GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container) { var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false); if (liveStreamInfo == null) diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 8bb0ace15..cc6eba4ae 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers /// A containing a with the playback information. [HttpGet("Items/{itemId}/PlaybackInfo")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetPlaybackInfo([FromRoute][Required] Guid itemId, [FromQuery, Required] Guid? userId) + public async Task> 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> GetPostedPlaybackInfo( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, [FromQuery] long? maxStreamingBitrate, [FromQuery] long? startTimeTicks, diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index df97c0ab9..570ae8fdc 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -259,7 +259,7 @@ namespace Jellyfin.Api.Controllers /// An containing a with the music genre. [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetMusicGenre([FromRoute][Required] string genreName, [FromQuery] Guid? userId) + public ActionResult GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index ea85e1909..7e406b418 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Packages/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> 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 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(); diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index be5fb7f7c..8bd610dad 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -263,7 +263,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetPerson([FromRoute][Required] string name, [FromQuery] Guid? userId) + public ActionResult GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 07bb108e3..69e0b8e07 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task AddToPlaylist( - [FromRoute][Required] 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 MoveItem( - [FromRoute][Required] string? playlistId, - [FromRoute][Required] string? itemId, - [FromRoute][Required] 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 /// An on success. [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromPlaylist([FromRoute][Required] string? playlistId, [FromQuery] string? entryIds) + public async Task 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 /// The original playlist items. [HttpGet("{playlistId}/Items")] public ActionResult> GetPlaylistItems( - [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) + [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) diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 091f884d2..5c15e9a0d 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -72,8 +72,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("Users/{userId}/PlayedItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult MarkPlayedItem( - [FromRoute][Required] Guid userId, - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId, [FromQuery] DateTime? datePlayed) { var user = _userManager.GetUserById(userId); @@ -97,7 +97,7 @@ namespace Jellyfin.Api.Controllers /// A containing the . [HttpDelete("Users/{userId}/PlayedItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult MarkUnplayedItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult MarkUnplayedItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); var session = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -196,8 +196,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackStart( - [FromRoute][Required] Guid userId, - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, @@ -246,8 +246,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackProgress( - [FromRoute][Required] Guid userId, - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, [FromQuery] long? positionTicks, [FromQuery] int? audioStreamIndex, @@ -298,8 +298,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackStopped( - [FromRoute][Required] Guid userId, - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid userId, + [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, [FromQuery] string? nextMediaType, [FromQuery] long? positionTicks, diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index d0de1a422..342b0328d 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UninstallPlugin([FromRoute][Required] 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 GetPluginConfiguration([FromRoute][Required] Guid pluginId) + public ActionResult 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 UpdatePluginConfiguration([FromRoute][Required] Guid pluginId) + public async Task 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 GetRegistrationStatus([FromRoute][Required] string? name) + public ActionResult 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][Required] 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. diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 597d3f2f6..bdc817126 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -70,7 +70,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetRemoteImages( - [FromRoute][Required] 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> GetRemoteImageProviders([FromRoute][Required] Guid itemId) + public ActionResult> 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 DownloadRemoteImage( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromQuery, Required] ImageType type, [FromQuery] string? imageUrl) { diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs index ea6288de0..3206f2734 100644 --- a/Jellyfin.Api/Controllers/ScheduledTasksController.cs +++ b/Jellyfin.Api/Controllers/ScheduledTasksController.cs @@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Running/{taskId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult StartTask([FromRoute][Required] string? taskId) + public ActionResult StartTask([FromRoute, Required] string? taskId) { var task = _taskManager.ScheduledTasks.FirstOrDefault(o => o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase)); diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index 4f0f241c6..cff7c1501 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -336,7 +336,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddUserToSession( [FromRoute, Required] string? sessionId, - [FromRoute][Required] 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][Required] string? sessionId, - [FromRoute][Required] Guid userId) + [FromRoute, Required] string? sessionId, + [FromRoute, Required] Guid userId) { _sessionManager.RemoveAdditionalUser(sessionId, userId); return NoContent(); diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 0208ebfbb..cdd5f958e 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers /// An containing the studio. [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetStudio([FromRoute][Required] string name, [FromQuery] Guid? userId) + public ActionResult GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 1096a06d2..2c82b5423 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -86,8 +86,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult DeleteSubtitle( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] 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>> SearchRemoteSubtitles( - [FromRoute][Required] 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 DownloadRemoteSubtitles( - [FromRoute][Required] 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][Required] 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 GetSubtitlePlaylist( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] int index, - [FromRoute][Required] string? mediaSourceId, + [FromRoute, Required] Guid itemId, + [FromRoute, Required] int index, + [FromRoute, Required] string? mediaSourceId, [FromQuery, Required] int segmentLength) { var item = (Video)_libraryManager.GetItemById(itemId); diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 52593b1ce..d7c81a3ab 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -54,7 +54,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Suggestions")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSuggestions( - [FromRoute][Required] Guid userId, + [FromRoute, Required] Guid userId, [FromQuery] string? mediaType, [FromQuery] string? type, [FromQuery] int? startIndex, diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index a3678454f..f7f2d0174 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -93,8 +93,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] public async Task GetUniversalAudioStream( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] string? container, + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string? container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index a9cab9cde..95067bc17 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -108,7 +108,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.IgnoreParentalControl)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetUserById([FromRoute][Required] Guid userId) + public ActionResult 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][Required] 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 UpdateUserPassword( - [FromRoute][Required] 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][Required] 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 UpdateUser( - [FromRoute][Required] 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][Required] 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][Required] Guid userId, + [FromRoute, Required] Guid userId, [FromBody] UserConfiguration userConfig) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false)) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index f93e80393..48262f062 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -71,7 +71,7 @@ namespace Jellyfin.Api.Controllers /// An containing the d item. [HttpGet("Users/{userId}/Items/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public async Task> GetItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers /// An containing the user's root folder. [HttpGet("Users/{userId}/Items/Root")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetRootFolder([FromRoute][Required] Guid userId) + public ActionResult GetRootFolder([FromRoute, Required] Guid userId) { var user = _userManager.GetUserById(userId); var item = _libraryManager.GetUserRootFolder(); @@ -111,7 +111,7 @@ namespace Jellyfin.Api.Controllers /// An containing the intros to play. [HttpGet("Users/{userId}/Items/{itemId}/Intros")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetIntros([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public async Task>> GetIntros([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -139,7 +139,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpPost("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult MarkFavoriteItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult MarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { return MarkFavorite(userId, itemId, true); } @@ -153,7 +153,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpDelete("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult UnmarkFavoriteItem([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult UnmarkFavoriteItem([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { return MarkFavorite(userId, itemId, false); } @@ -167,7 +167,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpDelete("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult DeleteUserItemRating([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult DeleteUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { return UpdateUserItemRatingInternal(userId, itemId, null); } @@ -182,7 +182,7 @@ namespace Jellyfin.Api.Controllers /// An containing the . [HttpPost("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult UpdateUserItemRating([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId, [FromQuery] bool? likes) + public ActionResult UpdateUserItemRating([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] bool? likes) { return UpdateUserItemRatingInternal(userId, itemId, likes); } @@ -196,7 +196,7 @@ namespace Jellyfin.Api.Controllers /// The items local trailers. [HttpGet("Users/{userId}/Items/{itemId}/LocalTrailers")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetLocalTrailers([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult> GetLocalTrailers([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -231,7 +231,7 @@ namespace Jellyfin.Api.Controllers /// An containing the special features. [HttpGet("Users/{userId}/Items/{itemId}/SpecialFeatures")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetSpecialFeatures([FromRoute][Required] Guid userId, [FromRoute][Required] Guid itemId) + public ActionResult> GetSpecialFeatures([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) { var user = _userManager.GetUserById(userId); @@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Items/Latest")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetLatestMedia( - [FromRoute][Required] Guid userId, + [FromRoute, Required] Guid userId, [FromQuery] Guid? parentId, [FromQuery] string? fields, [FromQuery] string? includeItemTypes, diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index 8582a5a21..d575bfc3b 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/Views")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetUserViews( - [FromRoute][Required] Guid userId, + [FromRoute, Required] Guid userId, [FromQuery] bool? includeExternalContent, [FromQuery] string? presetViews, [FromQuery] bool includeHidden = false) @@ -127,7 +127,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{userId}/GroupingOptions")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult> GetGroupingOptions([FromRoute][Required] Guid userId) + public ActionResult> GetGroupingOptions([FromRoute, Required] Guid userId) { var user = _userManager.GetUserById(userId); if (user == null) diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index cf667bf43..dabf04dee 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -163,7 +163,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Videos/{itemId}/live.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetLiveHlsStream( - [FromRoute][Required] Guid itemId, + [FromRoute, Required] Guid itemId, [FromQuery] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 224cc7b72..5c65399cb 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -115,7 +115,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{itemId}/AdditionalParts")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetAdditionalPart([FromRoute][Required] Guid itemId, [FromQuery] Guid? userId) + public ActionResult> 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 DeleteAlternateSources([FromRoute][Required] Guid itemId) + public async Task 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 GetVideoStream( - [FromRoute][Required] Guid itemId, - [FromRoute][Required] string? container, + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index b83b09c35..4ecf0407b 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -180,7 +180,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{year}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetYear([FromRoute][Required] int year, [FromQuery] Guid? userId) + public ActionResult GetYear([FromRoute, Required] int year, [FromQuery] Guid? userId) { var item = _libraryManager.GetYear(year); if (item == null) -- cgit v1.2.3 From 7294dc103f0cc6342c5f5a3c9456c17878031d3c Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 7 Sep 2020 18:45:06 -0600 Subject: Fix api routes --- Jellyfin.Api/Controllers/ApiKeyController.cs | 2 +- Jellyfin.Api/Controllers/AudioController.cs | 2 +- .../Controllers/ConfigurationController.cs | 4 +- .../Controllers/DisplayPreferencesController.cs | 4 +- Jellyfin.Api/Controllers/DynamicHlsController.cs | 6 +- Jellyfin.Api/Controllers/ImageByNameController.cs | 10 +-- Jellyfin.Api/Controllers/ImageController.cs | 90 +++++++++++----------- Jellyfin.Api/Controllers/InstantMixController.cs | 2 +- Jellyfin.Api/Controllers/ItemsController.cs | 2 +- Jellyfin.Api/Controllers/LibraryController.cs | 2 +- Jellyfin.Api/Controllers/LiveTvController.cs | 2 +- Jellyfin.Api/Controllers/PackageController.cs | 4 +- Jellyfin.Api/Controllers/PlaylistsController.cs | 22 +++--- Jellyfin.Api/Controllers/PluginsController.cs | 4 +- .../Controllers/ScheduledTasksController.cs | 8 +- Jellyfin.Api/Controllers/SessionController.cs | 32 ++++---- Jellyfin.Api/Controllers/SubtitleController.cs | 14 ++-- Jellyfin.Api/Controllers/TvShowsController.cs | 8 +- .../Controllers/UniversalAudioController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 2 +- 20 files changed, 111 insertions(+), 111 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 0e28d4c47..bf973b8dd 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Keys/{key}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RevokeKey([FromRoute, Required] string? key) + public ActionResult RevokeKey([FromRoute, Required] string key) { _sessionManager.RevokeToken(key); return NoContent(); diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 3bec43720..219577955 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -91,7 +91,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetAudioStream( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? container, + [FromRoute] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index 5fd4c712a..7596af39b 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -73,7 +73,7 @@ namespace Jellyfin.Api.Controllers /// Configuration. [HttpGet("Configuration/{key}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetNamedConfiguration([FromRoute, Required] string? key) + public ActionResult 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 UpdateNamedConfiguration([FromRoute, Required] string? key) + public async Task UpdateNamedConfiguration([FromRoute, Required] string key) { var configurationType = _configurationManager.GetConfigurationType(key); var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType, _serializerOptions).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 6bb7b1910..5d22ba665 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -43,7 +43,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] public ActionResult GetDisplayPreferences( - [FromRoute, Required] 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, Required] string? displayPreferencesId, + [FromRoute, Required] string displayPreferencesId, [FromQuery, Required] Guid userId, [FromQuery, Required] string? client, [FromBody, Required] DisplayPreferencesDto displayPreferences) diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index d81c7996e..6b45d7944 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -168,7 +168,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetMasterHlsVideoPlaylist( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? container, + [FromRoute, Required] string container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, @@ -335,7 +335,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetMasterHlsAudioPlaylist( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? container, + [FromRoute, Required] string container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, @@ -344,7 +344,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? segmentContainer, [FromQuery] int? segmentLength, [FromQuery] int? minSegments, - [FromQuery, Required] string? mediaSourceId, + [FromQuery, Required] string mediaSourceId, [FromQuery] string? deviceId, [FromQuery] string? audioCodec, [FromQuery] bool? enableAutoStreamCopy, diff --git a/Jellyfin.Api/Controllers/ImageByNameController.cs b/Jellyfin.Api/Controllers/ImageByNameController.cs index 528590536..56b72eb60 100644 --- a/Jellyfin.Api/Controllers/ImageByNameController.cs +++ b/Jellyfin.Api/Controllers/ImageByNameController.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers [Produces(MediaTypeNames.Application.Octet)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetGeneralImage([FromRoute, Required] string? name, [FromRoute, Required] string? type) + public ActionResult GetGeneralImage([FromRoute, Required] string name, [FromRoute, Required] string type) { var filename = string.Equals(type, "primary", StringComparison.OrdinalIgnoreCase) ? "folder" @@ -111,8 +111,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetRatingImage( - [FromRoute, Required] string? theme, - [FromRoute, Required] string? name) + [FromRoute, Required] string theme, + [FromRoute, Required] string name) { return GetImageFile(_applicationPaths.RatingsPath, theme, name); } @@ -144,8 +144,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetMediaInfoImage( - [FromRoute, Required] string? theme, - [FromRoute, Required] string? name) + [FromRoute, Required] string theme, + [FromRoute, Required] string name) { return GetImageFile(_applicationPaths.MediaInfoImagesPath, theme, name); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 453da5711..978d2eefa 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -93,7 +93,7 @@ namespace Jellyfin.Api.Controllers public async Task PostUserImage( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? index = null) + [FromRoute] int? index = null) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers public ActionResult DeleteUserImage( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? index = null) + [FromRoute] int? index = null) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -178,7 +178,7 @@ namespace Jellyfin.Api.Controllers public async Task DeleteItemImage( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -208,7 +208,7 @@ namespace Jellyfin.Api.Controllers public async Task SetItemImage( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -355,8 +355,8 @@ namespace Jellyfin.Api.Controllers public async Task GetItemImage( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? maxWidth, - [FromRoute, Required] int? maxHeight, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -369,7 +369,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -433,8 +433,8 @@ namespace Jellyfin.Api.Controllers public async Task GetItemImage2( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] int? maxWidth, - [FromRoute, Required] int? maxHeight, + [FromRoute, Required] int maxWidth, + [FromRoute, Required] int maxHeight, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -442,12 +442,12 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? cropWhitespace, [FromRoute, Required] string format, [FromQuery] bool? addPlayedIndicator, - [FromRoute, Required] double? percentPlayed, - [FromRoute, Required] int? unplayedCount, + [FromRoute, Required] double percentPlayed, + [FromRoute, Required] int unplayedCount, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute, Required] int imageIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -504,19 +504,19 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Artists/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("Artists/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadArtistImage")] + [HttpGet("Artists/{name}/Images/{imageType}/{imageIndex}")] + [HttpHead("Artists/{name}/Images/{imageType}/{imageIndex}", Name = "HeadArtistImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetArtistImage( [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] string tag, + [FromQuery] string format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -525,7 +525,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute, Required] int imageIndex) { var item = _libraryManager.GetArtist(name); if (item == null) @@ -582,19 +582,19 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Genres/{name}/Images/{imageType}/{imageIndex?}")] + [HttpGet("Genres/{name}/Images/{imageType}/{imageIndex}")] [HttpHead("Genres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetGenreImage( [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] string tag, + [FromQuery] string format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -603,7 +603,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -667,12 +667,12 @@ namespace Jellyfin.Api.Controllers public async Task GetMusicGenreImage( [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] string tag, + [FromQuery] string format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -681,7 +681,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -745,12 +745,12 @@ namespace Jellyfin.Api.Controllers public async Task GetPersonImage( [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] string tag, + [FromQuery] string format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, @@ -759,7 +759,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -837,7 +837,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -915,7 +915,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int? imageIndex = null) + [FromRoute] int? imageIndex = null) { var user = _userManager.GetUserById(userId); if (user == null) diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 01bfbba4e..07fed9764 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -175,7 +175,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("MusicGenres/{name}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenre( - [FromRoute, Required] string? name, + [FromRoute, Required] string name, [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 06ab176b2..652c4689d 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Users/{uId}/Items", Name = "GetItems_2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( - [FromRoute, Required] Guid? uId, + [FromRoute] Guid? uId, [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index f1f52961d..4adaee852 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -555,7 +555,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Library/Movies/Updated")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult PostUpdatedMovies([FromRoute, Required] string? tmdbId, [FromRoute, Required] string? imdbId) + public ActionResult PostUpdatedMovies([FromQuery] string? tmdbId, [FromQuery] string? imdbId) { var movies = _libraryManager.GetItemList(new InternalItemsQuery { diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 8678844d2..c32395705 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -935,7 +935,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Obsolete("This endpoint is obsolete.")] - public ActionResult GetRecordingGroup([FromRoute, Required] Guid? groupId) + public ActionResult GetRecordingGroup([FromRoute, Required] Guid groupId) { return NotFound(); } diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 9509f8708..eaf56aa56 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Packages/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPackageInfo( - [FromRoute, Required] string? name, + [FromRoute, Required] string name, [FromQuery] string? assemblyGuid) { var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); @@ -85,7 +85,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] [Authorize(Policy = Policies.RequiresElevation)] public async Task InstallPackage( - [FromRoute, Required] string? name, + [FromRoute, Required] string name, [FromQuery] string? assemblyGuid, [FromQuery] string? version) { diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 69e0b8e07..1e95bd2b3 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -103,8 +103,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task MoveItem( - [FromRoute, Required] string? playlistId, - [FromRoute, Required] string? itemId, + [FromRoute, Required] string playlistId, + [FromRoute, Required] string itemId, [FromRoute, Required] int newIndex) { await _playlistManager.MoveItemAsync(playlistId, itemId, newIndex).ConfigureAwait(false); @@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers /// An on success. [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromPlaylist([FromRoute, Required] string? playlistId, [FromQuery] string? entryIds) + public async Task RemoveFromPlaylist([FromRoute, Required] string playlistId, [FromQuery] string? entryIds) { await _playlistManager.RemoveFromPlaylistAsync(playlistId, RequestHelpers.Split(entryIds, ',', true)).ConfigureAwait(false); return NoContent(); @@ -144,14 +144,14 @@ namespace Jellyfin.Api.Controllers [HttpGet("{playlistId}/Items")] public ActionResult> GetPlaylistItems( [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) + [FromQuery, Required] Guid userId, + [FromQuery] int? startIndex, + [FromQuery] int? limit, + [FromQuery] string? fields, + [FromQuery] bool? enableImages, + [FromQuery] bool? enableUserData, + [FromQuery] int? imageTypeLimit, + [FromQuery] string? enableImageTypes) { var playlist = (Playlist)_libraryManager.GetItemById(playlistId); if (playlist == null) diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 342b0328d..0f8ceba29 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -172,7 +172,7 @@ namespace Jellyfin.Api.Controllers [Obsolete("This endpoint should not be used.")] [HttpPost("RegistrationRecords/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetRegistrationStatus([FromRoute, Required] string? name) + public ActionResult 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, Required] 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. diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs index 3206f2734..ab7920895 100644 --- a/Jellyfin.Api/Controllers/ScheduledTasksController.cs +++ b/Jellyfin.Api/Controllers/ScheduledTasksController.cs @@ -71,7 +71,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("{taskId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetTask([FromRoute, Required] string? taskId) + public ActionResult GetTask([FromRoute, Required] string taskId) { var task = _taskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, taskId, StringComparison.OrdinalIgnoreCase)); @@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Running/{taskId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult StartTask([FromRoute, Required] string? taskId) + public ActionResult StartTask([FromRoute, Required] string taskId) { var task = _taskManager.ScheduledTasks.FirstOrDefault(o => o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase)); @@ -118,7 +118,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Running/{taskId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult StopTask([FromRoute, Required] string? taskId) + public ActionResult StopTask([FromRoute, Required] string taskId) { var task = _taskManager.ScheduledTasks.FirstOrDefault(o => o.Id.Equals(taskId, StringComparison.OrdinalIgnoreCase)); @@ -144,7 +144,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateTask( - [FromRoute, Required] string? taskId, + [FromRoute, Required] string taskId, [FromBody, Required] TaskTriggerInfo[] triggerInfos) { var task = _taskManager.ScheduledTasks.FirstOrDefault(o => diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index cff7c1501..3bb9b11d9 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -125,10 +125,10 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult DisplayContent( - [FromRoute, Required] string? sessionId, - [FromQuery, Required] string? itemType, - [FromQuery, Required] string? itemId, - [FromQuery, Required] string? itemName) + [FromRoute, Required] string sessionId, + [FromQuery, Required] string itemType, + [FromQuery, Required] string itemId, + [FromQuery, Required] string itemName) { var command = new BrowseRequest { @@ -159,7 +159,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult Play( - [FromRoute, Required] string? sessionId, + [FromRoute, Required] string sessionId, [FromQuery] Guid[] itemIds, [FromQuery] long? startPositionTicks, [FromQuery] PlayCommand playCommand) @@ -187,11 +187,11 @@ namespace Jellyfin.Api.Controllers /// The . /// Playstate command sent to session. /// A . - [HttpPost("Sessions/{sessionId}/Playing/{command}")] + [HttpPost("Sessions/{sessionId}/Playing")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendPlaystateCommand( - [FromRoute, Required] string? sessionId, + [FromRoute, Required] string sessionId, [FromBody] PlaystateRequest playstateRequest) { _sessionManager.SendPlaystateCommand( @@ -214,8 +214,8 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendSystemCommand( - [FromRoute, Required] string? sessionId, - [FromRoute, Required] string? command) + [FromRoute, Required] string sessionId, + [FromRoute, Required] string command) { var name = command; if (Enum.TryParse(name, true, out GeneralCommandType commandType)) @@ -246,8 +246,8 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendGeneralCommand( - [FromRoute, Required] string? sessionId, - [FromRoute, Required] string? command) + [FromRoute, Required] string sessionId, + [FromRoute, Required] string command) { var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -273,7 +273,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendFullGeneralCommand( - [FromRoute, Required] string? sessionId, + [FromRoute, Required] string sessionId, [FromBody, Required] GeneralCommand command) { var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -307,8 +307,8 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendMessageCommand( - [FromRoute, Required] string? sessionId, - [FromQuery, Required] string? text, + [FromRoute, Required] string sessionId, + [FromQuery, Required] string text, [FromQuery, Required] string? header, [FromQuery] long? timeoutMs) { @@ -335,7 +335,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddUserToSession( - [FromRoute, Required] string? sessionId, + [FromRoute, Required] string sessionId, [FromRoute, Required] Guid userId) { _sessionManager.AddAdditionalUser(sessionId, userId); @@ -353,7 +353,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RemoveUserFromSession( - [FromRoute, Required] string? sessionId, + [FromRoute, Required] string sessionId, [FromRoute, Required] Guid userId) { _sessionManager.RemoveAdditionalUser(sessionId, userId); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 2c82b5423..09704d484 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> SearchRemoteSubtitles( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? language, + [FromRoute, Required] string language, [FromQuery] bool? isPerfectMatch) { var video = (Video)_libraryManager.GetItemById(itemId); @@ -133,7 +133,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task DownloadRemoteSubtitles( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? subtitleId) + [FromRoute, Required] string subtitleId) { var video = (Video)_libraryManager.GetItemById(itemId); @@ -162,7 +162,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [Produces(MediaTypeNames.Application.Octet)] - public async Task GetRemoteSubtitles([FromRoute, Required] string? id) + public async Task GetRemoteSubtitles([FromRoute, Required] string id) { var result = await _subtitleManager.GetRemoteSubtitles(id, CancellationToken.None).ConfigureAwait(false); @@ -187,13 +187,13 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetSubtitle( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? mediaSourceId, + [FromRoute, Required] string mediaSourceId, [FromRoute, Required] int index, - [FromRoute, Required] string? format, + [FromRoute, Required] string format, [FromQuery] long? endPositionTicks, [FromQuery] bool copyTimestamps = false, [FromQuery] bool addVttTimeMap = false, - [FromRoute, Required] long startPositionTicks = 0) + [FromRoute] long startPositionTicks = 0) { if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) { @@ -255,7 +255,7 @@ namespace Jellyfin.Api.Controllers public async Task GetSubtitlePlaylist( [FromRoute, Required] Guid itemId, [FromRoute, Required] int index, - [FromRoute, Required] string? mediaSourceId, + [FromRoute, Required] string mediaSourceId, [FromQuery, Required] int segmentLength) { var item = (Video)_libraryManager.GetItemById(itemId); diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index f463ab889..b9c3bd1e7 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -194,8 +194,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetEpisodes( - [FromRoute, Required] string? seriesId, - [FromQuery, Required] Guid? userId, + [FromRoute, Required] string seriesId, + [FromQuery] Guid? userId, [FromQuery] string? fields, [FromQuery] int? season, [FromQuery] string? seasonId, @@ -317,8 +317,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetSeasons( - [FromRoute, Required] string? seriesId, - [FromQuery, Required] Guid? userId, + [FromRoute, Required] string seriesId, + [FromQuery] Guid? userId, [FromQuery] string? fields, [FromQuery] bool? isSpecialSeason, [FromQuery] bool? isMissing, diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index f7f2d0174..a3cb7718c 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -94,7 +94,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status302Found)] public async Task GetUniversalAudioStream( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? container, + [FromRoute] string? container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 5c65399cb..f732529c9 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -332,7 +332,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetVideoStream( [FromRoute, Required] Guid itemId, - [FromRoute, Required] string? container, + [FromRoute] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, -- cgit v1.2.3 From 7576824cee0dc0d8e1729ae0a7e8e4f256b71efd Mon Sep 17 00:00:00 2001 From: cvium Date: Thu, 10 Sep 2020 14:16:41 +0200 Subject: Standardize use of IsLocal and RemoteIp --- .../HttpServer/Security/SessionContext.cs | 2 +- Jellyfin.Api/Auth/BaseAuthorizationHandler.cs | 3 +- Jellyfin.Api/Controllers/MediaInfoController.cs | 3 +- Jellyfin.Api/Controllers/SystemController.cs | 5 ++- .../Controllers/UniversalAudioController.cs | 3 +- Jellyfin.Api/Controllers/UserController.cs | 21 +++++----- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 10 ++--- Jellyfin.Api/Helpers/MediaInfoHelper.cs | 3 +- Jellyfin.Api/Helpers/RequestHelpers.cs | 3 +- .../IpBasedAccessValidationMiddleware.cs | 4 +- .../Middleware/ResponseTimeMiddleware.cs | 3 +- .../Extensions/HttpContextExtensions.cs | 46 ++++++---------------- 12 files changed, 45 insertions(+), 61 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs index 8777c59b7..86914dea2 100644 --- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.HttpServer.Security var authorization = _authContext.GetAuthorizationInfo(requestContext); var user = authorization.User; - return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.Request.RemoteIp(), user); + return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.GetNormalizedRemoteIp(), user); } public SessionInfo GetSession(object requestContext) diff --git a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs index aa366f567..d732b6bc6 100644 --- a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs @@ -1,6 +1,7 @@ using System.Security.Claims; using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; @@ -69,7 +70,7 @@ namespace Jellyfin.Api.Auth return false; } - var ip = RequestHelpers.NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString(); + var ip = _httpContextAccessor.HttpContext.GetNormalizedRemoteIp(); var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip); // User cannot access remotely and user is remote if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork) diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index cc6eba4ae..f32bdb161 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -8,6 +8,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.MediaInfoDtos; using Jellyfin.Api.Models.VideoDtos; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; @@ -164,7 +165,7 @@ namespace Jellyfin.Api.Controllers enableTranscoding, allowVideoStreamCopy, allowAudioStreamCopy, - Request.HttpContext.Connection.RemoteIpAddress.ToString()); + Request.HttpContext.GetNormalizedRemoteIp()); } _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index bbfd163de..34c7bb18d 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -176,8 +177,8 @@ namespace Jellyfin.Api.Controllers { return new EndPointInfo { - IsLocal = Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress), - IsInNetwork = _network.IsInLocalNetwork(Request.HttpContext.Connection.RemoteIpAddress.ToString()) + IsLocal = HttpContext.IsLocal(), + IsInNetwork = _network.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp()) }; } diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index f7f2d0174..e3e3166b0 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.StreamingDtos; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -158,7 +159,7 @@ namespace Jellyfin.Api.Controllers true, true, true, - Request.HttpContext.Connection.RemoteIpAddress.ToString()); + Request.HttpContext.GetNormalizedRemoteIp()); } _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 95067bc17..85430e63f 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -7,6 +7,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data.Enums; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; @@ -117,7 +118,7 @@ namespace Jellyfin.Api.Controllers return NotFound("User not found"); } - var result = _userManager.GetUserDto(user, HttpContext.Connection.RemoteIpAddress.ToString()); + var result = _userManager.GetUserDto(user, HttpContext.GetNormalizedRemoteIp()); return result; } @@ -203,7 +204,7 @@ namespace Jellyfin.Api.Controllers DeviceName = auth.Device, Password = request.Pw, PasswordSha1 = request.Password, - RemoteEndPoint = HttpContext.Connection.RemoteIpAddress.ToString(), + RemoteEndPoint = HttpContext.GetNormalizedRemoteIp(), Username = request.Username }).ConfigureAwait(false); @@ -212,7 +213,7 @@ namespace Jellyfin.Api.Controllers catch (SecurityException e) { // rethrow adding IP address to message - throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e); + throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e); } } @@ -246,7 +247,7 @@ namespace Jellyfin.Api.Controllers catch (SecurityException e) { // rethrow adding IP address to message - throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e); + throw new SecurityException($"[{HttpContext.GetNormalizedRemoteIp()}] {e.Message}", e); } } @@ -290,7 +291,7 @@ namespace Jellyfin.Api.Controllers user.Username, request.CurrentPw, request.CurrentPw, - HttpContext.Connection.RemoteIpAddress.ToString(), + HttpContext.GetNormalizedRemoteIp(), false).ConfigureAwait(false); if (success == null) @@ -496,7 +497,7 @@ namespace Jellyfin.Api.Controllers await _userManager.ChangePassword(newUser, request.Password).ConfigureAwait(false); } - var result = _userManager.GetUserDto(newUser, HttpContext.Connection.RemoteIpAddress.ToString()); + var result = _userManager.GetUserDto(newUser, HttpContext.GetNormalizedRemoteIp()); return result; } @@ -511,8 +512,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> ForgotPassword([FromBody] string? enteredUsername) { - var isLocal = HttpContext.Connection.RemoteIpAddress.Equals(HttpContext.Connection.LocalIpAddress) - || _networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString()); + var isLocal = HttpContext.IsLocal() + || _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp()); var result = await _userManager.StartForgotPasswordProcess(enteredUsername, isLocal).ConfigureAwait(false); @@ -559,7 +560,7 @@ namespace Jellyfin.Api.Controllers if (filterByNetwork) { - if (!_networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString())) + if (!_networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIp())) { users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess)); } @@ -567,7 +568,7 @@ namespace Jellyfin.Api.Controllers var result = users .OrderBy(u => u.Username) - .Select(i => _userManager.GetUserDto(i, HttpContext.Connection.RemoteIpAddress.ToString())); + .Select(i => _userManager.GetUserDto(i, HttpContext.GetNormalizedRemoteIp())); return result; } diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 6a8829d46..af0519ffa 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.StreamingDtos; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; @@ -198,12 +199,12 @@ namespace Jellyfin.Api.Helpers if (!string.IsNullOrWhiteSpace(subtitleGroup)) { - AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.Request.HttpContext.User); + AddSubtitles(state, subtitleStreams, builder, _httpContextAccessor.HttpContext.User); } AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup); - if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress)) + if (EnableAdaptiveBitrateStreaming(state, isLiveStream, enableAdaptiveBitrateStreaming, _httpContextAccessor.HttpContext.GetNormalizedRemoteIp())) { var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0; @@ -334,11 +335,10 @@ namespace Jellyfin.Api.Helpers } } - private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, IPAddress ipAddress) + private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream, bool enableAdaptiveBitrateStreaming, string ipAddress) { // Within the local network this will likely do more harm than good. - var ip = RequestHelpers.NormalizeIp(ipAddress).ToString(); - if (_networkManager.IsInLocalNetwork(ip)) + if (_networkManager.IsInLocalNetwork(ipAddress)) { return false; } diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index 3a736d1e8..1207fb513 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; @@ -498,7 +499,7 @@ namespace Jellyfin.Api.Helpers true, true, true, - httpRequest.HttpContext.Connection.RemoteIpAddress.ToString()); + httpRequest.HttpContext.GetNormalizedRemoteIp()); } else { diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index fbaa69270..d15b5603e 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using Jellyfin.Data.Enums; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Querying; @@ -119,7 +120,7 @@ namespace Jellyfin.Api.Helpers authorization.Version, authorization.DeviceId, authorization.Device, - request.HttpContext.Connection.RemoteIpAddress.ToString(), + request.HttpContext.GetNormalizedRemoteIp(), user); if (session == null) diff --git a/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs b/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs index 59b5fb1ed..4bda8f273 100644 --- a/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs +++ b/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs @@ -32,13 +32,13 @@ namespace Jellyfin.Server.Middleware /// The async task. public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager) { - if (httpContext.Request.IsLocal()) + if (httpContext.IsLocal()) { await _next(httpContext).ConfigureAwait(false); return; } - var remoteIp = httpContext.Request.RemoteIp(); + var remoteIp = httpContext.GetNormalizedRemoteIp(); if (serverConfigurationManager.Configuration.EnableRemoteAccess) { diff --git a/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs b/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs index 3122d92cb..74874da1b 100644 --- a/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs +++ b/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Globalization; using System.Threading.Tasks; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -69,7 +70,7 @@ namespace Jellyfin.Server.Middleware _logger.LogWarning( "Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}", context.Request.GetDisplayUrl(), - context.Connection.RemoteIpAddress, + context.GetNormalizedRemoteIp(), watch.Elapsed, context.Response.StatusCode); } diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index e0cf3f9ac..8d2908882 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -1,5 +1,3 @@ -using System.Net; -using MediaBrowser.Common.Net; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Common.Extensions @@ -10,54 +8,32 @@ namespace MediaBrowser.Common.Extensions public static class HttpContextExtensions { /// - /// Checks the origin of the HTTP request. + /// Checks the origin of the HTTP context. /// - /// The incoming HTTP request. + /// The incoming HTTP context. /// true if the request is coming from LAN, false otherwise. - public static bool IsLocal(this HttpRequest request) + public static bool IsLocal(this HttpContext context) { - return (request.HttpContext.Connection.LocalIpAddress == null - && request.HttpContext.Connection.RemoteIpAddress == null) - || request.HttpContext.Connection.LocalIpAddress.Equals(request.HttpContext.Connection.RemoteIpAddress); + return (context.Connection.LocalIpAddress == null + && context.Connection.RemoteIpAddress == null) + || context.Connection.LocalIpAddress.Equals(context.Connection.RemoteIpAddress); } /// - /// Extracts the remote IP address of the caller of the HTTP request. + /// Extracts the remote IP address of the caller of the HTTP context. /// - /// The HTTP request. + /// The HTTP context. /// The remote caller IP address. - public static string RemoteIp(this HttpRequest request) + public static string GetNormalizedRemoteIp(this HttpContext context) { - var cachedRemoteIp = request.HttpContext.Items["RemoteIp"]?.ToString(); - if (!string.IsNullOrEmpty(cachedRemoteIp)) - { - return cachedRemoteIp; - } - - IPAddress ip; - - // "Real" remote ip might be in X-Forwarded-For of X-Real-Ip - // (if the server is behind a reverse proxy for example) - if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XForwardedFor].ToString(), out ip)) - { - if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XRealIP].ToString(), out ip)) - { - ip = request.HttpContext.Connection.RemoteIpAddress; - - // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests) - ip ??= IPAddress.Loopback; - } - } + var ip = context.Connection.RemoteIpAddress; if (ip.IsIPv4MappedToIPv6) { ip = ip.MapToIPv4(); } - var normalizedIp = ip.ToString(); - - request.HttpContext.Items["RemoteIp"] = normalizedIp; - return normalizedIp; + return ip.ToString(); } } } -- cgit v1.2.3 From 00f0c14d7b953111e0bacc134b161c329b8e5fa1 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sat, 31 Oct 2020 16:09:22 +0800 Subject: respect music quality settings when transcoding --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 12 +++++++++--- Jellyfin.Api/Controllers/MediaInfoController.cs | 4 ++-- Jellyfin.Api/Controllers/UniversalAudioController.cs | 8 +++++--- Jellyfin.Api/Helpers/MediaInfoHelper.cs | 4 ++-- MediaBrowser.Model/Dlna/AudioOptions.cs | 4 ++-- MediaBrowser.Model/Dlna/DeviceProfile.cs | 4 ++-- MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs | 2 +- 7 files changed, 23 insertions(+), 15 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 1153a601e..e07690e11 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -295,6 +295,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Whether to break on non key frames. /// Optional. Specify a specific audio sample rate, e.g. 44100. /// Optional. The maximum audio bit depth. + /// Optional. The maximum streaming bitrate. /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. /// Optional. Specify a specific number of audio channels to encode to, e.g. 2. /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2. @@ -351,6 +352,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? breakOnNonKeyFrames, [FromQuery] int? audioSampleRate, [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? maxStreamingBitrate, [FromQuery] int? audioBitRate, [FromQuery] int? audioChannels, [FromQuery] int? maxAudioChannels, @@ -403,7 +405,7 @@ namespace Jellyfin.Api.Controllers BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false, AudioSampleRate = audioSampleRate, MaxAudioChannels = maxAudioChannels, - AudioBitRate = audioBitRate, + AudioBitRate = audioBitRate ?? maxStreamingBitrate, MaxAudioBitDepth = maxAudioBitDepth, AudioChannels = audioChannels, Profile = profile, @@ -623,6 +625,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Whether to break on non key frames. /// Optional. Specify a specific audio sample rate, e.g. 44100. /// Optional. The maximum audio bit depth. + /// Optional. The maximum streaming bitrate. /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. /// Optional. Specify a specific number of audio channels to encode to, e.g. 2. /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2. @@ -677,6 +680,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? breakOnNonKeyFrames, [FromQuery] int? audioSampleRate, [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? maxStreamingBitrate, [FromQuery] int? audioBitRate, [FromQuery] int? audioChannels, [FromQuery] int? maxAudioChannels, @@ -729,7 +733,7 @@ namespace Jellyfin.Api.Controllers BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false, AudioSampleRate = audioSampleRate, MaxAudioChannels = maxAudioChannels, - AudioBitRate = audioBitRate, + AudioBitRate = audioBitRate ?? maxStreamingBitrate, MaxAudioBitDepth = maxAudioBitDepth, AudioChannels = audioChannels, Profile = profile, @@ -959,6 +963,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Whether to break on non key frames. /// Optional. Specify a specific audio sample rate, e.g. 44100. /// Optional. The maximum audio bit depth. + /// Optional. The maximum streaming bitrate. /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. /// Optional. Specify a specific number of audio channels to encode to, e.g. 2. /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2. @@ -1017,6 +1022,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? breakOnNonKeyFrames, [FromQuery] int? audioSampleRate, [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? maxStreamingBitrate, [FromQuery] int? audioBitRate, [FromQuery] int? audioChannels, [FromQuery] int? maxAudioChannels, @@ -1069,7 +1075,7 @@ namespace Jellyfin.Api.Controllers BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false, AudioSampleRate = audioSampleRate, MaxAudioChannels = maxAudioChannels, - AudioBitRate = audioBitRate, + AudioBitRate = audioBitRate ?? maxStreamingBitrate, MaxAudioBitDepth = maxAudioBitDepth, AudioChannels = audioChannels, Profile = profile, diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 4c21999b1..186024585 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -104,7 +104,7 @@ namespace Jellyfin.Api.Controllers public async Task> GetPostedPlaybackInfo( [FromRoute, Required] Guid itemId, [FromQuery] Guid? userId, - [FromQuery] long? maxStreamingBitrate, + [FromQuery] int? maxStreamingBitrate, [FromQuery] long? startTimeTicks, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, @@ -234,7 +234,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? openToken, [FromQuery] Guid? userId, [FromQuery] string? playSessionId, - [FromQuery] long? maxStreamingBitrate, + [FromQuery] int? maxStreamingBitrate, [FromQuery] long? startTimeTicks, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index df20a92b3..1cfdb9d8b 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -76,6 +76,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of audio channels. /// Optional. The number of how many audio channels to transcode to. /// Optional. The maximum streaming bitrate. + /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. /// Optional. The container to transcode to. /// Optional. The transcoding protocol. @@ -104,7 +105,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? audioCodec, [FromQuery] int? maxAudioChannels, [FromQuery] int? transcodingAudioChannels, - [FromQuery] long? maxStreamingBitrate, + [FromQuery] int? maxStreamingBitrate, + [FromQuery] int? audioBitRate, [FromQuery] long? startTimeTicks, [FromQuery] string? transcodingContainer, [FromQuery] string? transcodingProtocol, @@ -212,7 +214,7 @@ namespace Jellyfin.Api.Controllers AudioSampleRate = maxAudioSampleRate, MaxAudioChannels = maxAudioChannels, MaxAudioBitDepth = maxAudioBitDepth, - AudioChannels = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), + AudioBitRate = audioBitRate ?? maxStreamingBitrate, StartTimeTicks = startTimeTicks, SubtitleMethod = SubtitleDeliveryMethod.Hls, RequireAvc = true, @@ -244,7 +246,7 @@ namespace Jellyfin.Api.Controllers BreakOnNonKeyFrames = breakOnNonKeyFrames, AudioSampleRate = maxAudioSampleRate, MaxAudioChannels = maxAudioChannels, - AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)), + AudioBitRate = isStatic ? (int?)null : (audioBitRate ?? maxStreamingBitrate), MaxAudioBitDepth = maxAudioBitDepth, AudioChannels = maxAudioChannels, CopyTimestamps = true, diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs index e78f63b25..0d8315dee 100644 --- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs +++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs @@ -166,7 +166,7 @@ namespace Jellyfin.Api.Helpers MediaSourceInfo mediaSource, DeviceProfile profile, AuthorizationInfo auth, - long? maxBitrate, + int? maxBitrate, long startTimeTicks, string mediaSourceId, int? audioStreamIndex, @@ -551,7 +551,7 @@ namespace Jellyfin.Api.Helpers } } - private long? GetMaxBitrate(long? clientMaxBitrate, User user, string ipAddress) + private int? GetMaxBitrate(int? clientMaxBitrate, User user, string ipAddress) { var maxBitrate = clientMaxBitrate; var remoteClientMaxBitrate = user.RemoteClientBitrateLimit ?? 0; diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs index 67e4ffe03..bbb8bf426 100644 --- a/MediaBrowser.Model/Dlna/AudioOptions.cs +++ b/MediaBrowser.Model/Dlna/AudioOptions.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Dlna /// /// The application's configured quality setting. /// - public long? MaxBitrate { get; set; } + public int? MaxBitrate { get; set; } /// /// Gets or sets the context. @@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Dlna /// Gets the maximum bitrate. /// /// System.Nullable<System.Int32>. - public long? GetMaxBitrate(bool isAudio) + public int? GetMaxBitrate(bool isAudio) { if (MaxBitrate.HasValue) { diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 44412f3e4..e842efead 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -62,9 +62,9 @@ namespace MediaBrowser.Model.Dlna public int? MaxIconHeight { get; set; } - public long? MaxStreamingBitrate { get; set; } + public int? MaxStreamingBitrate { get; set; } - public long? MaxStaticBitrate { get; set; } + public int? MaxStaticBitrate { get; set; } public int? MusicStreamingTranscodingBitrate { get; set; } diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs index 83bda5d56..a8ea405e2 100644 --- a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs +++ b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Model.MediaInfo public string PlaySessionId { get; set; } - public long? MaxStreamingBitrate { get; set; } + public int? MaxStreamingBitrate { get; set; } public long? StartTimeTicks { get; set; } -- cgit v1.2.3 From e5237384d5f4d525f0427b4571d2c4a2182adae8 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 1 Nov 2020 04:20:25 +0800 Subject: fix the route of audio containers --- Jellyfin.Api/Controllers/UniversalAudioController.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index df20a92b3..70848aed6 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -88,16 +88,14 @@ namespace Jellyfin.Api.Controllers /// Redirected to remote audio stream. /// A containing the audio file. [HttpGet("Audio/{itemId}/universal")] - [HttpGet("Audio/{itemId}/universal.{container}", Name = "GetUniversalAudioStream_2")] [HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] - [HttpHead("Audio/{itemId}/universal.{container}", Name = "HeadUniversalAudioStream_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] [ProducesAudioFile] public async Task GetUniversalAudioStream( [FromRoute, Required] Guid itemId, - [FromRoute] string? container, + [FromQuery] string? container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, -- cgit v1.2.3 From 599e20ab9b760e6cd8300e8d0e401e1856518db5 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 1 Nov 2020 18:45:42 +0800 Subject: fix music directplay on Gelli --- Jellyfin.Api/Controllers/UniversalAudioController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 70848aed6..a219a74cf 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -274,7 +274,7 @@ namespace Jellyfin.Api.Controllers foreach (var cont in containers) { - var parts = RequestHelpers.Split(cont, ',', true); + var parts = RequestHelpers.Split(cont, '|', true); var audioCodecs = parts.Length == 1 ? null : string.Join(",", parts.Skip(1).ToArray()); -- cgit v1.2.3 From b21919c7f40770c909a0fc217bf2a326397f84f7 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 6 Nov 2020 16:15:30 +0100 Subject: Minor perf improvements --- Emby.Dlna/ContentDirectory/ControlHandler.cs | 4 ++-- Emby.Dlna/Didl/DidlBuilder.cs | 2 +- Emby.Dlna/DlnaManager.cs | 6 +++--- Emby.Dlna/Eventing/DlnaEventManager.cs | 2 +- Emby.Dlna/Main/DlnaEntryPoint.cs | 4 ++-- Emby.Dlna/PlayTo/PlayToController.cs | 4 ++-- Emby.Notifications/NotificationEntryPoint.cs | 5 ++++- .../Channels/ChannelManager.cs | 17 ++++++----------- Jellyfin.Api/Controllers/InstantMixController.cs | 4 ++-- Jellyfin.Api/Controllers/UniversalAudioController.cs | 20 ++++++++++++-------- Jellyfin.Api/Helpers/SimilarItemsHelper.cs | 4 ++-- MediaBrowser.Controller/IServerApplicationHost.cs | 9 +++++---- 12 files changed, 42 insertions(+), 39 deletions(-) (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs') diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 299186112..5f25b8cdc 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -1346,8 +1346,8 @@ namespace Emby.Dlna.ContentDirectory { if (id.StartsWith(name + "_", StringComparison.OrdinalIgnoreCase)) { - stubType = (StubType)Enum.Parse(typeof(StubType), name, true); - id = id.Split(new[] { '_' }, 2)[1]; + stubType = Enum.Parse(name, true); + id = id.Split('_', 2)[1]; break; } diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 5b8a89d8f..abaf522bc 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -123,7 +123,7 @@ namespace Emby.Dlna.Didl { foreach (var att in profile.XmlRootAttributes) { - var parts = att.Name.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + var parts = att.Name.Split(':', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 2) { writer.WriteAttributeString(parts[0], parts[1], null, att.Value); diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 1807ac6a1..069400833 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -383,9 +383,9 @@ namespace Emby.Dlna continue; } - var filename = Path.GetFileName(name).Substring(namespaceName.Length); - - var path = Path.Combine(systemProfilesPath, filename); + var path = Path.Join( + systemProfilesPath, + Path.GetFileName(name.AsSpan()).Slice(namespaceName.Length)); using (var stream = _assembly.GetManifestResourceStream(name)) { diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index 7d8da86ef..770d56c30 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -168,7 +168,7 @@ namespace Emby.Dlna.Eventing builder.Append(""); - using var options = new HttpRequestMessage(new HttpMethod("NOTIFY"), subscription.CallbackUrl); + using var options = new HttpRequestMessage(new HttpMethod("NOTIFY"), subscription.CallbackUrl); options.Content = new StringContent(builder.ToString(), Encoding.UTF8, MediaTypeNames.Text.Xml); options.Headers.TryAddWithoutValidation("NT", subscription.NotificationType); options.Headers.TryAddWithoutValidation("NTS", "upnp:propchange"); diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 40c2cc0e0..f8a00efac 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -257,9 +257,10 @@ namespace Emby.Dlna.Main private async Task RegisterServerEndpoints() { - var addresses = await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false); + var addresses = await _appHost.GetLocalIpAddresses().ConfigureAwait(false); var udn = CreateUuid(_appHost.SystemId); + var descriptorUri = "/dlna/" + udn + "/description.xml"; foreach (var address in addresses) { @@ -279,7 +280,6 @@ namespace Emby.Dlna.Main _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address); - var descriptorUri = "/dlna/" + udn + "/description.xml"; var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri); var device = new SsdpRootDevice diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index a5b8e2b3c..c07c8aefa 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -326,7 +326,7 @@ namespace Emby.Dlna.PlayTo public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken) { - _logger.LogDebug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand); + _logger.LogDebug("{0} - Received PlayRequest: {1}", _session.DeviceName, command.PlayCommand); var user = command.ControllingUserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(command.ControllingUserId); @@ -339,7 +339,7 @@ namespace Emby.Dlna.PlayTo var startIndex = command.StartIndex ?? 0; if (startIndex > 0) { - items = items.Skip(startIndex).ToList(); + items = items.GetRange(startIndex, items.Count - startIndex); } var playlist = new List(); diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs index ded22d26c..7116d52b1 100644 --- a/Emby.Notifications/NotificationEntryPoint.cs +++ b/Emby.Notifications/NotificationEntryPoint.cs @@ -209,7 +209,10 @@ namespace Emby.Notifications _libraryUpdateTimer = null; } - items = items.Take(10).ToList(); + if (items.Count > 10) + { + items = items.GetRange(0, 10); + } foreach (var item in items) { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index db44bf489..19045b72b 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -250,21 +250,16 @@ namespace Emby.Server.Implementations.Channels var all = channels; var totalCount = all.Count; - if (query.StartIndex.HasValue) + if (query.StartIndex.HasValue || query.Limit.HasValue) { - all = all.Skip(query.StartIndex.Value).ToList(); + int startIndex = query.StartIndex ?? 0; + int count = query.Limit == null ? totalCount - startIndex : Math.Min(query.Limit.Value, totalCount - startIndex); + all = all.GetRange(startIndex, count); } - if (query.Limit.HasValue) - { - all = all.Take(query.Limit.Value).ToList(); - } - - var returnItems = all.ToArray(); - if (query.RefreshLatestChannelItems) { - foreach (var item in returnItems) + foreach (var item in all) { RefreshLatestChannelItems(GetChannelProvider(item), CancellationToken.None).GetAwaiter().GetResult(); } @@ -272,7 +267,7 @@ namespace Emby.Server.Implementations.Channels return new QueryResult { - Items = returnItems, + Items = all, TotalRecordCount = totalCount }; } diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index e6e6b3e70..7682ceff3 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -316,9 +316,9 @@ namespace Jellyfin.Api.Controllers TotalRecordCount = list.Count }; - if (limit.HasValue) + if (limit.HasValue && limit > list.Count) { - list = list.Take(limit.Value).ToList(); + list = list.GetRange(0, limit.Value); } var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user); diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index a219a74cf..924ae0477 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -268,20 +268,24 @@ namespace Jellyfin.Api.Controllers { var deviceProfile = new DeviceProfile(); - var directPlayProfiles = new List(); - var containers = RequestHelpers.Split(container, ',', true); - - foreach (var cont in containers) + int len = containers.Length; + var directPlayProfiles = new DirectPlayProfile[len]; + for (int i = 0; i < len; i++) { - var parts = RequestHelpers.Split(cont, '|', true); + var parts = RequestHelpers.Split(containers[i], '|', true); - var audioCodecs = parts.Length == 1 ? null : string.Join(",", parts.Skip(1).ToArray()); + var audioCodecs = parts.Length == 1 ? null : string.Join(',', parts.Skip(1)); - directPlayProfiles.Add(new DirectPlayProfile { Type = DlnaProfileType.Audio, Container = parts[0], AudioCodec = audioCodecs }); + directPlayProfiles[i] = new DirectPlayProfile + { + Type = DlnaProfileType.Audio, + Container = parts[0], + AudioCodec = audioCodecs + }; } - deviceProfile.DirectPlayProfiles = directPlayProfiles.ToArray(); + deviceProfile.DirectPlayProfiles = directPlayProfiles; deviceProfile.TranscodingProfiles = new[] { diff --git a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs index b922e76cf..f4b654ef0 100644 --- a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs +++ b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs @@ -50,9 +50,9 @@ namespace Jellyfin.Api.Helpers var returnItems = items; - if (limit.HasValue) + if (limit.HasValue && limit > returnItems.Count) { - returnItems = returnItems.Take(limit.Value).ToList(); + returnItems = returnItems.GetRange(0, limit.Value); } var dtos = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user); diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index cfad17fb7..649b0eaec 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -56,10 +56,11 @@ namespace MediaBrowser.Controller /// /// Gets the system info. /// + /// A cancellation token that can be used to cancel the task. /// SystemInfo. - Task GetSystemInfo(CancellationToken cancellationToken); + Task GetSystemInfo(CancellationToken cancellationToken = default); - Task GetPublicSystemInfo(CancellationToken cancellationToken); + Task GetPublicSystemInfo(CancellationToken cancellationToken = default); /// /// Gets all the local IP addresses of this API instance. Each address is validated by sending a 'ping' request @@ -67,7 +68,7 @@ namespace MediaBrowser.Controller /// /// A cancellation token that can be used to cancel the task. /// A list containing all the local IP addresses of the server. - Task> GetLocalIpAddresses(CancellationToken cancellationToken); + Task> GetLocalIpAddresses(CancellationToken cancellationToken = default); /// /// Gets a local (LAN) URL that can be used to access the API. The hostname used is the first valid configured @@ -75,7 +76,7 @@ namespace MediaBrowser.Controller /// /// A cancellation token that can be used to cancel the task. /// The server URL. - Task GetLocalApiUrl(CancellationToken cancellationToken); + Task GetLocalApiUrl(CancellationToken cancellationToken = default); /// /// Gets a localhost URL that can be used to access the API using the loop-back IP address (127.0.0.1) -- cgit v1.2.3