From db99903c3588e33aabbcfc07e4265a97cd42ccd3 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 31 Aug 2020 07:24:23 -0600 Subject: Properly verify cache duration --- Jellyfin.Api/Controllers/ImageController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index ca9c2fa46..a204fe35c 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -1281,9 +1281,9 @@ namespace Jellyfin.Api.Controllers Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false))); // if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified - if (!(dateImageModified > ifModifiedSinceHeader)) + if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue) { - if (ifModifiedSinceHeader.Add(cacheDuration!.Value) < DateTime.UtcNow) + if (ifModifiedSinceHeader.Add(cacheDuration.Value) < DateTime.UtcNow) { Response.StatusCode = StatusCodes.Status304NotModified; return new ContentResult(); -- 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/ImageController.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 a698dab66fb8cb17ca12f03c4a271cbe15b7fac1 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 2 Sep 2020 11:14:59 -0600 Subject: Specify image file return for GetItemImage2 --- Jellyfin.Api/Controllers/DashboardController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index d20964d66..7624fd79f 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -214,7 +214,7 @@ namespace Jellyfin.Api.Controllers { return Redirect("index.html?start=wizard#!/wizardstart.html"); } - + return PhysicalFile(_resourceFileManager.GetResourcePath(basePath, path), MimeTypes.GetMimeType(path)); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index dbd569e07..c012acef3 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -431,6 +431,7 @@ namespace Jellyfin.Api.Controllers [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}", Name = "HeadItemImage2")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] public async Task GetItemImage2( [FromRoute] Guid itemId, [FromRoute] ImageType imageType, -- 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/ImageController.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/ImageController.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/ImageController.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/ImageController.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 af2186ab83d6ed1829915ac8a2f3cb559857abb6 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 7 Sep 2020 18:50:09 -0600 Subject: add back optional for route param --- Jellyfin.Api/Controllers/ImageController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 978d2eefa..9a40c1101 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -504,8 +504,8 @@ 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( @@ -582,7 +582,7 @@ 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)] -- cgit v1.2.3 From 63ebae2f9eb015b1b7a834417c2958c81e82bbf8 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 9 Sep 2020 14:28:30 -0600 Subject: Remove nullable from required --- Jellyfin.Api/Controllers/ApiKeyController.cs | 2 +- Jellyfin.Api/Controllers/CollectionController.cs | 4 ++-- Jellyfin.Api/Controllers/DevicesController.cs | 8 ++++---- Jellyfin.Api/Controllers/DisplayPreferencesController.cs | 4 ++-- Jellyfin.Api/Controllers/DynamicHlsController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 8 ++++---- Jellyfin.Api/Controllers/ItemUpdateController.cs | 2 +- Jellyfin.Api/Controllers/MediaInfoController.cs | 4 ++-- Jellyfin.Api/Controllers/SearchController.cs | 2 +- Jellyfin.Api/Controllers/SessionController.cs | 4 ++-- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 4 ++-- Jellyfin.Api/Controllers/UserController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index bf973b8dd..e8d6ccdf2 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Keys")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult CreateKey([FromQuery, Required] string? app) + public ActionResult CreateKey([FromQuery, Required] string app) { _authRepo.Create(new AuthenticationInfo { diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index f78690b06..2fc697a6a 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/DevicesController.cs b/Jellyfin.Api/Controllers/DevicesController.cs index 1aed20ade..74380c2ef 100644 --- a/Jellyfin.Api/Controllers/DevicesController.cs +++ b/Jellyfin.Api/Controllers/DevicesController.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetDeviceInfo([FromQuery, Required] string? id) + public ActionResult GetDeviceInfo([FromQuery, Required] string id) { var deviceInfo = _deviceManager.GetDevice(id); if (deviceInfo == null) @@ -87,7 +87,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetDeviceOptions([FromQuery, Required] string? id) + public ActionResult GetDeviceOptions([FromQuery, Required] string id) { var deviceInfo = _deviceManager.GetDeviceOptions(id); if (deviceInfo == null) @@ -111,7 +111,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateDeviceOptions( - [FromQuery, Required] string? id, + [FromQuery, Required] string id, [FromBody, Required] DeviceOptions deviceOptions) { var existingDeviceOptions = _deviceManager.GetDeviceOptions(id); @@ -134,7 +134,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteDevice([FromQuery, Required] string? id) + public ActionResult DeleteDevice([FromQuery, Required] string id) { var existingDevice = _deviceManager.GetDevice(id); if (existingDevice == null) diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 86aa52d05..874467c75 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -45,7 +45,7 @@ namespace Jellyfin.Api.Controllers public ActionResult GetDisplayPreferences( [FromRoute, Required] string displayPreferencesId, [FromQuery, Required] Guid userId, - [FromQuery, Required] string? client) + [FromQuery, Required] string client) { var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, client); var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client); @@ -99,7 +99,7 @@ namespace Jellyfin.Api.Controllers public ActionResult UpdateDisplayPreferences( [FromRoute, Required] string displayPreferencesId, [FromQuery, Required] Guid userId, - [FromQuery, Required] string? client, + [FromQuery, Required] string client, [FromBody, Required] DisplayPreferencesDto displayPreferences) { HomeSectionType[] defaults = diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 778c18560..670b41611 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -179,7 +179,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/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index ab4bf3d88..7afec1219 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -833,10 +833,10 @@ namespace Jellyfin.Api.Controllers [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? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 4308a434d..0a6ed31ae 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -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] string contentType) { var item = _libraryManager.GetItemById(itemId); if (item == null) diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index ee171e856..a984afc96 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -69,7 +69,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, @@ -270,7 +270,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("LiveStreams/Close")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task CloseLiveStream([FromQuery, Required] string? liveStreamId) + public async Task CloseLiveStream([FromQuery, Required] string liveStreamId) { await _mediaSourceManager.CloseLiveStream(liveStreamId).ConfigureAwait(false); return NoContent(); diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index e159a9666..62c870cb1 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -81,7 +81,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] Guid? userId, - [FromQuery, Required] string? searchTerm, + [FromQuery, Required] string searchTerm, [FromQuery] string? includeItemTypes, [FromQuery] string? excludeItemTypes, [FromQuery] string? mediaTypes, diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index 9da8b3ed4..b00675d67 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -309,7 +309,7 @@ namespace Jellyfin.Api.Controllers public ActionResult SendMessageCommand( [FromRoute, Required] string sessionId, [FromQuery, Required] string text, - [FromQuery, Required] string? header, + [FromQuery] string? header, [FromQuery] long? timeoutMs) { var command = new MessageCommand @@ -375,7 +375,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostCapabilities( - [FromQuery, Required] string? id, + [FromQuery] string? id, [FromQuery] string? playableMediaTypes, [FromQuery] string? supportedCommands, [FromQuery] bool supportsMediaControl = false, diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e878e8f36..a5dc123dd 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesFile(MediaTypeNames.Text.Plain)] - public ActionResult GetLogFile([FromQuery, Required] string? name) + public ActionResult GetLogFile([FromQuery, Required] string name) { var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) .First(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index b9c3bd1e7..d158f6c34 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("NextUp")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetNextUp( - [FromQuery, Required] Guid? userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? fields, @@ -127,7 +127,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Upcoming")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetUpcomingEpisodes( - [FromQuery, Required] Guid? userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? fields, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 435588146..f3e4b1bea 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -156,7 +156,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> AuthenticateUser( [FromRoute, Required] Guid userId, - [FromQuery, Required] string? pw, + [FromQuery, Required] string pw, [FromQuery] string? password) { var user = _userManager.GetUserById(userId); diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 2608ba916..cce4cfbe3 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -203,7 +203,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task MergeVersions([FromQuery, Required] string? itemIds) + public async Task MergeVersions([FromQuery, Required] string itemIds) { var items = RequestHelpers.Split(itemIds, ',', true) .Select(i => _libraryManager.GetItemById(i)) -- cgit v1.2.3 From 754e859f6e13c0fad0ed91d694b7fca163f58ce1 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Fri, 2 Oct 2020 12:05:39 -0500 Subject: Convert strings to ImageFormat --- Jellyfin.Api/Controllers/ImageController.cs | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 7afec1219..6f925dec5 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -364,7 +364,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] string? tag, [FromQuery] bool? cropWhitespace, - [FromQuery] string? format, + [FromQuery] ImageFormat? format, [FromQuery] bool? addPlayedIndicator, [FromQuery] double? percentPlayed, [FromQuery] int? unplayedCount, @@ -443,7 +443,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromRoute, Required] string tag, [FromQuery] bool? cropWhitespace, - [FromRoute, Required] string format, + [FromRoute, Required] ImageFormat format, [FromQuery] bool? addPlayedIndicator, [FromRoute, Required] double percentPlayed, [FromRoute, Required] int unplayedCount, @@ -516,7 +516,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromQuery] string tag, - [FromQuery] string format, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -595,7 +595,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromQuery] string tag, - [FromQuery] string format, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -674,7 +674,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromQuery] string tag, - [FromQuery] string format, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -753,7 +753,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromQuery] string tag, - [FromQuery] string format, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -832,7 +832,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromRoute, Required] string tag, - [FromRoute, Required] string format, + [FromRoute, Required] ImageFormat format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -911,7 +911,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, [FromQuery] string? tag, - [FromQuery] string? format, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -1038,7 +1038,7 @@ namespace Jellyfin.Api.Controllers ImageType imageType, int? imageIndex, string? tag, - string? format, + ImageFormat? format, int? maxWidth, int? maxHeight, double? percentPlayed, @@ -1128,12 +1128,11 @@ namespace Jellyfin.Api.Controllers isHeadRequest).ConfigureAwait(false); } - private ImageFormat[] GetOutputFormats(string? format) + private ImageFormat[] GetOutputFormats(ImageFormat? format) { - if (!string.IsNullOrWhiteSpace(format) - && Enum.TryParse(format, true, out ImageFormat parsedFormat)) + if (format.HasValue) { - return new[] { parsedFormat }; + return new[] { format.Value }; } return GetClientSupportedFormats(); @@ -1157,7 +1156,7 @@ namespace Jellyfin.Api.Controllers var acceptParam = Request.Query[HeaderNames.Accept]; - var supportsWebP = SupportsFormat(supportedFormats, acceptParam, "webp", false); + var supportsWebP = SupportsFormat(supportedFormats, acceptParam, ImageFormat.Webp, false); if (!supportsWebP) { @@ -1179,7 +1178,7 @@ namespace Jellyfin.Api.Controllers formats.Add(ImageFormat.Jpg); formats.Add(ImageFormat.Png); - if (SupportsFormat(supportedFormats, acceptParam, "gif", true)) + if (SupportsFormat(supportedFormats, acceptParam, ImageFormat.Gif, true)) { formats.Add(ImageFormat.Gif); } @@ -1187,9 +1186,10 @@ namespace Jellyfin.Api.Controllers return formats.ToArray(); } - private bool SupportsFormat(IReadOnlyCollection requestAcceptTypes, string acceptParam, string format, bool acceptAll) + private bool SupportsFormat(IReadOnlyCollection requestAcceptTypes, string acceptParam, ImageFormat format, bool acceptAll) { - var mimeType = "image/" + format; + var normalized = format.ToString().ToLowerInvariant(); + var mimeType = "image/" + normalized; if (requestAcceptTypes.Contains(mimeType)) { @@ -1201,7 +1201,7 @@ namespace Jellyfin.Api.Controllers return true; } - return string.Equals(acceptParam, format, StringComparison.OrdinalIgnoreCase); + return string.Equals(acceptParam, normalized, StringComparison.OrdinalIgnoreCase); } private async Task GetImageResult( -- cgit v1.2.3 From 7cec65b97390dd9fc5fe75a81eb69d61d48329c5 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:35:57 -0500 Subject: Update documentation --- Jellyfin.Api/Controllers/ImageController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 6f925dec5..05efe2355 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -333,7 +333,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. - /// Determines the output format of the image - original,gif,jpg,png. + /// Optional. The of the returned image. /// Optional. Add a played indicator. /// Optional. Percent to render for the percent played overlay. /// Optional. Unplayed count overlay to render. -- cgit v1.2.3 From 72263613d039ccfb70b70bae9f53da53bc8757c4 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 29 Oct 2020 20:30:33 -0400 Subject: Convert some code in UserManager to async --- Jellyfin.Api/Controllers/ImageController.cs | 6 +++--- Jellyfin.Api/Controllers/UserController.cs | 18 +++++++----------- .../Users/UserManager.cs | 22 ++++++++++------------ MediaBrowser.Controller/Library/IUserManager.cs | 9 ++++++--- 4 files changed, 26 insertions(+), 29 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 05efe2355..4a67c1aed 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -109,7 +109,7 @@ namespace Jellyfin.Api.Controllers var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); if (user.ProfileImage != null) { - _userManager.ClearProfileImage(user); + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); } user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); @@ -138,7 +138,7 @@ namespace Jellyfin.Api.Controllers [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public ActionResult DeleteUserImage( + public async Task DeleteUserImage( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, [FromRoute] int? index = null) @@ -158,7 +158,7 @@ namespace Jellyfin.Api.Controllers _logger.LogError(e, "Error deleting user profile image:"); } - _userManager.ClearProfileImage(user); + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 50bb8bb2a..7b0897bfb 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -381,17 +381,13 @@ namespace Jellyfin.Api.Controllers var user = _userManager.GetUserById(userId); - if (string.Equals(user.Username, updateUser.Name, StringComparison.Ordinal)) - { - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - _userManager.UpdateConfiguration(user.Id, updateUser.Configuration); - } - else + if (!string.Equals(user.Username, updateUser.Name, StringComparison.Ordinal)) { await _userManager.RenameUser(user, updateUser.Name).ConfigureAwait(false); - _userManager.UpdateConfiguration(updateUser.Id, updateUser.Configuration); } + await _userManager.UpdateConfigurationAsync(user.Id, updateUser.Configuration).ConfigureAwait(false); + return NoContent(); } @@ -409,7 +405,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public ActionResult UpdateUserPolicy( + public async Task UpdateUserPolicy( [FromRoute, Required] Guid userId, [FromBody] UserPolicy newPolicy) { @@ -447,7 +443,7 @@ namespace Jellyfin.Api.Controllers _sessionManager.RevokeUserTokens(user.Id, currentToken); } - _userManager.UpdatePolicy(userId, newPolicy); + await _userManager.UpdatePolicyAsync(userId, newPolicy).ConfigureAwait(false); return NoContent(); } @@ -464,7 +460,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public ActionResult UpdateUserConfiguration( + public async Task UpdateUserConfiguration( [FromRoute, Required] Guid userId, [FromBody] UserConfiguration userConfig) { @@ -473,7 +469,7 @@ namespace Jellyfin.Api.Controllers return Forbid("User configuration update not allowed"); } - _userManager.UpdateConfiguration(userId, userConfig); + await _userManager.UpdateConfigurationAsync(userId, userConfig).ConfigureAwait(false); return NoContent(); } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index b41a5ee5c..40b89ed28 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -434,9 +434,7 @@ namespace Jellyfin.Server.Implementations.Users if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy && user != null) { - UpdatePolicy(user.Id, hasNewUserPolicy.GetNewUserPolicy()); - - await UpdateUserAsync(user).ConfigureAwait(false); + await UpdatePolicyAsync(user.Id, hasNewUserPolicy.GetNewUserPolicy()).ConfigureAwait(false); } } } @@ -615,9 +613,9 @@ namespace Jellyfin.Server.Implementations.Users } /// - public void UpdateConfiguration(Guid userId, UserConfiguration config) + public async Task UpdateConfigurationAsync(Guid userId, UserConfiguration config) { - using var dbContext = _dbProvider.CreateContext(); + await using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) @@ -644,13 +642,13 @@ namespace Jellyfin.Server.Implementations.Users user.SetPreference(PreferenceKind.LatestItemExcludes, config.LatestItemsExcludes); dbContext.Update(user); - dbContext.SaveChanges(); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } /// - public void UpdatePolicy(Guid userId, UserPolicy policy) + public async Task UpdatePolicyAsync(Guid userId, UserPolicy policy) { - using var dbContext = _dbProvider.CreateContext(); + await using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) @@ -715,15 +713,15 @@ namespace Jellyfin.Server.Implementations.Users user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders); dbContext.Update(user); - dbContext.SaveChanges(); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } /// - public void ClearProfileImage(User user) + public async Task ClearProfileImageAsync(User user) { - using var dbContext = _dbProvider.CreateContext(); + await using var dbContext = _dbProvider.CreateContext(); dbContext.Remove(user.ProfileImage); - dbContext.SaveChanges(); + await dbContext.SaveChangesAsync().ConfigureAwait(false); user.ProfileImage = null; } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 6a4f5cf67..8fd3b8c34 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -158,7 +158,8 @@ namespace MediaBrowser.Controller.Library /// /// The user's Id. /// The request containing the new user configuration. - void UpdateConfiguration(Guid userId, UserConfiguration config); + /// A task representing the update. + Task UpdateConfigurationAsync(Guid userId, UserConfiguration config); /// /// This method updates the user's policy. @@ -167,12 +168,14 @@ namespace MediaBrowser.Controller.Library /// /// The user's Id. /// The request containing the new user policy. - void UpdatePolicy(Guid userId, UserPolicy policy); + /// A task representing the update. + Task UpdatePolicyAsync(Guid userId, UserPolicy policy); /// /// Clears the user's profile image. /// /// The user. - void ClearProfileImage(User user); + /// A task representing the clearing of the profile image. + Task ClearProfileImageAsync(User user); } } -- cgit v1.2.3 From 01355e049855a21b69e7e258599c3fa35965375a Mon Sep 17 00:00:00 2001 From: crobibero Date: Fri, 13 Nov 2020 09:04:31 -0700 Subject: Fix nullability errors in Jellyfin.Api (part 1) --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 12 +++++++++- Jellyfin.Api/Controllers/EnvironmentController.cs | 5 ++++ Jellyfin.Api/Controllers/GenresController.cs | 2 +- Jellyfin.Api/Controllers/HlsSegmentController.cs | 5 ++++ Jellyfin.Api/Controllers/ImageByNameController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 3 ++- Jellyfin.Api/Controllers/ItemLookupController.cs | 21 ++++++++++++++-- Jellyfin.Api/Controllers/LibraryController.cs | 6 ++--- Jellyfin.Api/Controllers/LiveTvController.cs | 2 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 4 ++-- Jellyfin.Api/Controllers/PackageController.cs | 5 ++++ Jellyfin.Api/Controllers/RemoteImageController.cs | 28 ++++++++++++++++++---- Jellyfin.Api/Controllers/SearchController.cs | 2 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 8 ++++++- Jellyfin.Api/Helpers/AudioHelper.cs | 8 ++++++- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 11 ++++++--- Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs | 4 ++-- Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs | 6 ++--- Jellyfin.Api/Helpers/HlsHelpers.cs | 4 ++++ Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 5 ++++ Jellyfin.Api/Helpers/StreamingHelpers.cs | 4 ++++ Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 26 +++++++++++++------- .../Models/PlaybackDtos/TranscodingJobDto.cs | 4 ++-- .../Models/PlaybackDtos/TranscodingThrottler.cs | 2 +- .../ActivityLogWebSocketListener.cs | 2 +- .../ScheduledTasksWebSocketListener.cs | 6 ++--- .../SessionInfoWebSocketListener.cs | 14 +++++------ .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/Net/MimeTypes.cs | 6 ++--- 29 files changed, 155 insertions(+), 54 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index e07690e11..b0d5a7cd8 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1347,7 +1347,13 @@ namespace Jellyfin.Api.Controllers var mapArgs = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty; - var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer); + var directory = Path.GetDirectoryName(outputPath); + if (directory == null) + { + throw new NullReferenceException(nameof(directory)); + } + + var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer); var segmentFormat = GetSegmentFileExtension(state.Request.SegmentContainer).TrimStart('.'); if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase)) @@ -1566,6 +1572,10 @@ namespace Jellyfin.Api.Controllers private string GetSegmentPath(StreamState state, string playlist, int index) { var folder = Path.GetDirectoryName(playlist); + if (folder == null) + { + throw new NullReferenceException(nameof(folder)); + } var filename = Path.GetFileNameWithoutExtension(playlist); diff --git a/Jellyfin.Api/Controllers/EnvironmentController.cs b/Jellyfin.Api/Controllers/EnvironmentController.cs index ce88b0b99..8de217bbf 100644 --- a/Jellyfin.Api/Controllers/EnvironmentController.cs +++ b/Jellyfin.Api/Controllers/EnvironmentController.cs @@ -103,6 +103,11 @@ namespace Jellyfin.Api.Controllers if (validatePathDto.ValidateWritable) { + if (validatePathDto.Path == null) + { + throw new NullReferenceException(nameof(validatePathDto.Path)); + } + var file = Path.Combine(validatePathDto.Path, Guid.NewGuid().ToString()); try { diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index f6e0772ec..9c009d784 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -177,7 +177,7 @@ namespace Jellyfin.Api.Controllers return _dtoService.GetBaseItemDto(item, dtoOptions); } - private T GetItemFromSlugName(ILibraryManager libraryManager, string name, DtoOptions dtoOptions) + private T? GetItemFromSlugName(ILibraryManager libraryManager, string name, DtoOptions dtoOptions) where T : BaseItem, new() { var result = libraryManager.GetItemList(new InternalItemsQuery diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 054e586ce..2cee0e9ef 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -136,6 +136,11 @@ namespace Jellyfin.Api.Controllers string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); + if (playlistPath == null) + { + throw new NullReferenceException(nameof(playlistPath)); + } + return GetFileResult(file, playlistPath); } diff --git a/Jellyfin.Api/Controllers/ImageByNameController.cs b/Jellyfin.Api/Controllers/ImageByNameController.cs index 980c3273d..198dbc51f 100644 --- a/Jellyfin.Api/Controllers/ImageByNameController.cs +++ b/Jellyfin.Api/Controllers/ImageByNameController.cs @@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers /// Theme to search. /// File name to search for. /// A containing the image contents on success, or a if the image could not be found. - private ActionResult GetImageFile(string basePath, string? theme, string? name) + private ActionResult GetImageFile(string basePath, string theme, string? name) { var themeFolder = Path.Combine(basePath, theme); if (Directory.Exists(themeFolder)) diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 4a67c1aed..76e53b9a5 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; @@ -1268,7 +1269,7 @@ namespace Jellyfin.Api.Controllers Response.Headers.Add(key, value); } - Response.ContentType = imageContentType; + Response.ContentType = imageContentType ?? MediaTypeNames.Text.Plain; Response.Headers.Add(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateImageModified).TotalSeconds).ToString(CultureInfo.InvariantCulture)); Response.Headers.Add(HeaderNames.Vary, HeaderNames.Accept); diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index ab73aa428..b6cb79716 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -334,10 +334,21 @@ namespace Jellyfin.Api.Controllers private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath) { using var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false); + if (result.Content.Headers.ContentType?.MediaType == null) + { + throw new NullReferenceException(nameof(result.Content.Headers.ContentType)); + } + var ext = result.Content.Headers.ContentType.MediaType.Split('/')[^1]; var fullCachePath = GetFullCachePath(urlHash + "." + ext); - Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); + var directory = Path.GetDirectoryName(fullCachePath); + if (directory == null) + { + throw new NullReferenceException(nameof(directory)); + } + + Directory.CreateDirectory(directory); using (var stream = result.Content) { await using var fileStream = new FileStream( @@ -351,7 +362,13 @@ namespace Jellyfin.Api.Controllers await stream.CopyToAsync(fileStream).ConfigureAwait(false); } - Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath); + if (pointerCacheDirectory == null) + { + throw new NullReferenceException(nameof(pointerCacheDirectory)); + } + + Directory.CreateDirectory(pointerCacheDirectory); await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath).ConfigureAwait(false); } diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 8a872ae13..60bbc5022 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -455,7 +455,7 @@ namespace Jellyfin.Api.Controllers : null; var dtoOptions = new DtoOptions().AddClientFields(Request); - BaseItem parent = item.GetParent(); + BaseItem? parent = item.GetParent(); while (parent != null) { @@ -466,7 +466,7 @@ namespace Jellyfin.Api.Controllers baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); - parent = parent.GetParent(); + parent = parent?.GetParent(); } return baseItemDtos; @@ -854,7 +854,7 @@ namespace Jellyfin.Api.Controllers return _libraryManager.GetItemsResult(query).TotalRecordCount; } - private BaseItem TranslateParentItem(BaseItem item, User user) + private BaseItem? TranslateParentItem(BaseItem item, User user) { return item.GetParent() is AggregateFolder ? _libraryManager.GetUserRootFolder().GetChildren(user, true) diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 31253cbbc..384a48705 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1078,7 +1078,7 @@ namespace Jellyfin.Api.Controllers var client = _httpClientFactory.CreateClient(NamedClient.Default); // https://json.schedulesdirect.org/20141201/available/countries // Can't dispose the response as it's required up the call chain. - var response = await client.GetAsync("https://json.schedulesdirect.org/20141201/available/countries") + var response = await client.GetAsync(new Uri("https://json.schedulesdirect.org/20141201/available/countries")) .ConfigureAwait(false); return File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), MediaTypeNames.Application.Json); diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index e434f190a..989c383fd 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers { var dtoOptions = new DtoOptions().AddClientFields(Request); - MusicGenre item; + MusicGenre? item; if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1) { @@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers return _dtoService.GetBaseItemDto(item, dtoOptions); } - private T GetItemFromSlugName(ILibraryManager libraryManager, string name, DtoOptions dtoOptions) + private T? GetItemFromSlugName(ILibraryManager libraryManager, string name, DtoOptions dtoOptions) where T : BaseItem, new() { var result = libraryManager.GetItemList(new InternalItemsQuery diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 1d9de14d2..a104af4e6 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -54,6 +54,11 @@ namespace Jellyfin.Api.Controllers string.IsNullOrEmpty(assemblyGuid) ? default : Guid.Parse(assemblyGuid)) .FirstOrDefault(); + if (result == null) + { + return NotFound(); + } + return result; } diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 5f095443b..ad76b3984 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -157,9 +157,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetRemoteImage([FromQuery, Required] string imageUrl) + public async Task GetRemoteImage([FromQuery, Required] Uri imageUrl) { - var urlHash = imageUrl.GetMD5(); + var urlHash = imageUrl.ToString().GetMD5(); var pointerCachePath = GetFullCachePath(urlHash.ToString()); string? contentPath = null; @@ -245,17 +245,35 @@ namespace Jellyfin.Api.Controllers /// The URL hash. /// The pointer cache path. /// Task. - private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath) + private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath) { var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); using var response = await httpClient.GetAsync(url).ConfigureAwait(false); + if (response.Content.Headers.ContentType?.MediaType == null) + { + throw new NullReferenceException(nameof(response.Content.Headers.ContentType)); + } + var ext = response.Content.Headers.ContentType.MediaType.Split('/').Last(); var fullCachePath = GetFullCachePath(urlHash + "." + ext); - Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); + var fullCacheDirectory = Path.GetDirectoryName(fullCachePath); + if (fullCacheDirectory == null) + { + throw new NullReferenceException(nameof(fullCacheDirectory)); + } + + Directory.CreateDirectory(fullCacheDirectory); await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); - Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + + var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath); + if (pointerCacheDirectory == null) + { + throw new NullReferenceException(nameof(pointerCacheDirectory)); + } + + Directory.CreateDirectory(pointerCacheDirectory); await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None) .ConfigureAwait(false); } diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 62c870cb1..e75f0d06b 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers } } - private T GetParentWithImage(BaseItem item, ImageType type) + private T? GetParentWithImage(BaseItem item, ImageType type) where T : BaseItem { return item.GetParents().OfType().FirstOrDefault(i => i.HasImage(type)); diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index d7bcf79c1..517239966 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -361,7 +361,13 @@ namespace Jellyfin.Api.Controllers var threads = _encodingHelper.GetNumberOfThreads(state, _encodingOptions, videoCodec); var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions); var format = !string.IsNullOrWhiteSpace(state.Request.SegmentContainer) ? "." + state.Request.SegmentContainer : ".ts"; - var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format; + var directory = Path.GetDirectoryName(outputPath); + if (directory == null) + { + throw new NullReferenceException(nameof(directory)); + } + + var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format; var segmentFormat = format.TrimStart('.'); if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase)) diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index a3f2d88ce..c6d577b19 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -1,4 +1,5 @@ -using System.Net.Http; +using System; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.StreamingDtos; @@ -98,6 +99,11 @@ namespace Jellyfin.Api.Helpers TranscodingJobType transcodingJobType, StreamingRequestDto streamingRequest) { + if (_httpContextAccessor.HttpContext == null) + { + throw new NullReferenceException(nameof(_httpContextAccessor.HttpContext)); + } + bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head; var cancellationTokenSource = new CancellationTokenSource(); diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index ea012f837..20bca731f 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -113,7 +113,7 @@ namespace Jellyfin.Api.Helpers StreamingRequestDto streamingRequest, bool enableAdaptiveBitrateStreaming) { - var isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == WebRequestMethods.Http.Head; + var isHeadRequest = _httpContextAccessor.HttpContext?.Request.Method == WebRequestMethods.Http.Head; var cancellationTokenSource = new CancellationTokenSource(); return await GetMasterPlaylistInternal( streamingRequest, @@ -130,6 +130,11 @@ namespace Jellyfin.Api.Helpers TranscodingJobType transcodingJobType, CancellationTokenSource cancellationTokenSource) { + if (_httpContextAccessor.HttpContext == null) + { + throw new NullReferenceException(nameof(_httpContextAccessor.HttpContext)); + } + using var state = await StreamingHelpers.GetStreamingState( streamingRequest, _httpContextAccessor.HttpContext.Request, @@ -487,14 +492,14 @@ namespace Jellyfin.Api.Helpers if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) { - string profile = state.GetRequestedProfiles("h264").FirstOrDefault(); + string? profile = state.GetRequestedProfiles("h264").FirstOrDefault(); return HlsCodecStringHelpers.GetH264String(profile, level); } if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) { - string profile = state.GetRequestedProfiles("h265").FirstOrDefault(); + string? profile = state.GetRequestedProfiles("h265").FirstOrDefault(); return HlsCodecStringHelpers.GetH265String(profile, level); } diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs index 366301d3e..20c94cdda 100644 --- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs +++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs @@ -37,8 +37,8 @@ namespace Jellyfin.Api.Helpers } // Can't dispose the response as it's required up the call chain. - var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false); - var contentType = response.Content.Headers.ContentType.ToString(); + var response = await httpClient.GetAsync(new Uri(state.MediaPath)).ConfigureAwait(false); + var contentType = response.Content.Headers.ContentType?.ToString(); httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none"; diff --git a/Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs b/Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs index 95f1906ef..1bd3d67ff 100644 --- a/Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsCodecStringHelpers.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Api.Helpers /// /// AAC profile. /// AAC codec string. - public static string GetAACString(string profile) + public static string GetAACString(string? profile) { StringBuilder result = new StringBuilder("mp4a", 9); @@ -46,7 +46,7 @@ namespace Jellyfin.Api.Helpers /// H.264 profile. /// H.264 level. /// H.264 string. - public static string GetH264String(string profile, int level) + public static string GetH264String(string? profile, int level) { StringBuilder result = new StringBuilder("avc1", 11); @@ -80,7 +80,7 @@ namespace Jellyfin.Api.Helpers /// H.265 profile. /// H.265 level. /// H.265 string. - public static string GetH265String(string profile, int level) + public static string GetH265String(string? profile, int level) { // The h265 syntax is a bit of a mystery at the time this comment was written. // This is what I've found through various sources: diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index 242496697..16fbac7ae 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -45,6 +45,10 @@ namespace Jellyfin.Api.Helpers while (!reader.EndOfStream) { var line = await reader.ReadLineAsync().ConfigureAwait(false); + if (line == null) + { + throw new NullReferenceException(nameof(line)); + } if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1) { diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs index e00ed3304..65c03c710 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs @@ -90,6 +90,11 @@ namespace Jellyfin.Api.Helpers allowAsyncFileRead = true; } + if (_path == null) + { + throw new NullReferenceException(nameof(_path)); + } + await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); var eofCount = 0; diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index f4ec29bde..1d102071c 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -83,6 +83,10 @@ namespace Jellyfin.Api.Helpers } streamingRequest.StreamOptions = ParseStreamOptions(httpRequest.Query); + if (httpRequest.Path.Value == null) + { + throw new NullReferenceException(nameof(httpRequest.Path)); + } var url = httpRequest.Path.Value.Split('.').Last(); diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 0db1fabff..b72e33af3 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -102,7 +102,7 @@ namespace Jellyfin.Api.Helpers /// /// Playback session id. /// The transcoding job. - public TranscodingJobDto GetTranscodingJob(string playSessionId) + public TranscodingJobDto? GetTranscodingJob(string playSessionId) { lock (_activeTranscodingJobs) { @@ -116,7 +116,7 @@ namespace Jellyfin.Api.Helpers /// Path to the transcoding file. /// The . /// The transcoding job. - public TranscodingJobDto GetTranscodingJob(string path, TranscodingJobType type) + public TranscodingJobDto? GetTranscodingJob(string path, TranscodingJobType type) { lock (_activeTranscodingJobs) { @@ -193,9 +193,13 @@ namespace Jellyfin.Api.Helpers /// Called when [transcode kill timer stopped]. /// /// The state. - private async void OnTranscodeKillTimerStopped(object state) + private async void OnTranscodeKillTimerStopped(object? state) { - var job = (TranscodingJobDto)state; + var job = (TranscodingJobDto?)state; + if (job == null) + { + throw new NullReferenceException(nameof(job)); + } if (!job.HasExited && job.Type != TranscodingJobType.Progressive) { @@ -489,7 +493,13 @@ namespace Jellyfin.Api.Helpers CancellationTokenSource cancellationTokenSource, string? workingDirectory = null) { - Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + var directory = Path.GetDirectoryName(outputPath); + if (directory == null) + { + throw new NullReferenceException(nameof(directory)); + } + + Directory.CreateDirectory(directory); await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); @@ -523,7 +533,7 @@ namespace Jellyfin.Api.Helpers RedirectStandardInput = true, FileName = _mediaEncoder.EncoderPath, Arguments = commandLineArguments, - WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory, + WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? string.Empty : workingDirectory, ErrorDialog = false }, EnableRaisingEvents = true @@ -827,7 +837,7 @@ namespace Jellyfin.Api.Helpers { lock (_transcodingLocks) { - if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim result)) + if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim? result)) { result = new SemaphoreSlim(1, 1); _transcodingLocks[outputPath] = result; @@ -837,7 +847,7 @@ namespace Jellyfin.Api.Helpers } } - private void OnPlaybackProgress(object sender, PlaybackProgressEventArgs e) + private void OnPlaybackProgress(object? sender, PlaybackProgressEventArgs e) { if (!string.IsNullOrWhiteSpace(e.PlaySessionId)) { diff --git a/Jellyfin.Api/Models/PlaybackDtos/TranscodingJobDto.cs b/Jellyfin.Api/Models/PlaybackDtos/TranscodingJobDto.cs index b9507a4e5..9edc19bb6 100644 --- a/Jellyfin.Api/Models/PlaybackDtos/TranscodingJobDto.cs +++ b/Jellyfin.Api/Models/PlaybackDtos/TranscodingJobDto.cs @@ -196,7 +196,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos /// Start kill timer. /// /// Callback action. - public void StartKillTimer(Action callback) + public void StartKillTimer(Action callback) { StartKillTimer(callback, PingTimeout); } @@ -206,7 +206,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos /// /// Callback action. /// Callback interval. - public void StartKillTimer(Action callback, int intervalMs) + public void StartKillTimer(Action callback, int intervalMs) { if (HasExited) { diff --git a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs index b5e42ea29..872a46824 100644 --- a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs +++ b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs @@ -101,7 +101,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos return _config.GetConfiguration("encoding"); } - private async void TimerCallback(object state) + private async void TimerCallback(object? state) { if (_job.HasExited) { diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 77d55828d..ce5465116 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -56,7 +56,7 @@ namespace Jellyfin.Api.WebSocketListeners base.Dispose(dispose); } - private void OnEntryCreated(object sender, GenericEventArgs e) + private void OnEntryCreated(object? sender, GenericEventArgs e) { SendData(true); } diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs index 80314b923..94df23e56 100644 --- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs @@ -64,19 +64,19 @@ namespace Jellyfin.Api.WebSocketListeners base.Dispose(dispose); } - private void OnTaskCompleted(object sender, TaskCompletionEventArgs e) + private void OnTaskCompleted(object? sender, TaskCompletionEventArgs e) { SendData(true); e.Task.TaskProgress -= OnTaskProgress; } - private void OnTaskExecuting(object sender, GenericEventArgs e) + private void OnTaskExecuting(object? sender, GenericEventArgs e) { SendData(true); e.Argument.TaskProgress += OnTaskProgress; } - private void OnTaskProgress(object sender, GenericEventArgs e) + private void OnTaskProgress(object? sender, GenericEventArgs e) { SendData(false); } diff --git a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs index 1cf43a005..d996ac69f 100644 --- a/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/SessionInfoWebSocketListener.cs @@ -66,37 +66,37 @@ namespace Jellyfin.Api.WebSocketListeners base.Dispose(dispose); } - private async void OnSessionManagerSessionActivity(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionActivity(object? sender, SessionEventArgs e) { await SendData(false).ConfigureAwait(false); } - private async void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e) + private async void OnSessionManagerCapabilitiesChanged(object? sender, SessionEventArgs e) { await SendData(true).ConfigureAwait(false); } - private async void OnSessionManagerPlaybackProgress(object sender, PlaybackProgressEventArgs e) + private async void OnSessionManagerPlaybackProgress(object? sender, PlaybackProgressEventArgs e) { await SendData(!e.IsAutomated).ConfigureAwait(false); } - private async void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) + private async void OnSessionManagerPlaybackStopped(object? sender, PlaybackStopEventArgs e) { await SendData(true).ConfigureAwait(false); } - private async void OnSessionManagerPlaybackStart(object sender, PlaybackProgressEventArgs e) + private async void OnSessionManagerPlaybackStart(object? sender, PlaybackProgressEventArgs e) { await SendData(true).ConfigureAwait(false); } - private async void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionEnded(object? sender, SessionEventArgs e) { await SendData(true).ConfigureAwait(false); } - private async void OnSessionManagerSessionStarted(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionStarted(object? sender, SessionEventArgs e) { await SendData(true).ConfigureAwait(false); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 0a9958b9e..8b3c6b2e6 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -758,7 +758,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles case MediaProtocol.Http: { using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(path, cancellationToken) + .GetAsync(new Uri(path), cancellationToken) .ConfigureAwait(false); return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); } diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index afe7351d3..55c0e6c9a 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -210,9 +210,9 @@ namespace MediaBrowser.Model.Net return enableStreamDefault ? "application/octet-stream" : null; } - public static string? ToExtension(string mimeType) + public static string? ToExtension(string? mimeType) { - if (mimeType.Length == 0) + if (string.IsNullOrEmpty(mimeType)) { throw new ArgumentException("String can't be empty.", nameof(mimeType)); } @@ -220,7 +220,7 @@ namespace MediaBrowser.Model.Net // handle text/html; charset=UTF-8 mimeType = mimeType.Split(';')[0]; - if (_extensionLookup.TryGetValue(mimeType, out string result)) + if (_extensionLookup.TryGetValue(mimeType, out string? result)) { return result; } -- cgit v1.2.3 From 547ee885613591021ad5ff5595249b1f8448d742 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 15 Nov 2020 10:58:39 -0700 Subject: Remove api client generator errors --- Jellyfin.Api/Controllers/AudioController.cs | 169 ++++- Jellyfin.Api/Controllers/DynamicHlsController.cs | 4 +- Jellyfin.Api/Controllers/ImageController.cs | 736 +++++++++++++++++++-- Jellyfin.Api/Controllers/InstantMixController.cs | 4 +- Jellyfin.Api/Controllers/ItemsController.cs | 257 ++++++- Jellyfin.Api/Controllers/SubtitleController.cs | 42 +- Jellyfin.Api/Controllers/TrailersController.cs | 1 - .../Controllers/VideoAttachmentsController.cs | 3 +- Jellyfin.Api/Controllers/VideosController.cs | 165 ++++- MediaBrowser.Model/Dlna/StreamBuilder.cs | 2 +- 10 files changed, 1309 insertions(+), 74 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index d4c6e4af9..330e56614 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -85,15 +85,178 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Audio stream returned. /// A containing the audio file. - [HttpGet("{itemId}/stream.{container:required}", Name = "GetAudioStreamByContainer")] [HttpGet("{itemId}/stream", Name = "GetAudioStream")] - [HttpHead("{itemId}/stream.{container:required}", Name = "HeadAudioStreamByContainer")] [HttpHead("{itemId}/stream", Name = "HeadAudioStream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesAudioFile] public async Task GetAudioStream( [FromRoute, Required] Guid itemId, - [FromRoute] string? container, + [FromQuery] string? container, + [FromQuery] bool? @static, + [FromQuery] string? @params, + [FromQuery] string? tag, + [FromQuery] string? deviceProfileId, + [FromQuery] string? playSessionId, + [FromQuery] string? segmentContainer, + [FromQuery] int? segmentLength, + [FromQuery] int? minSegments, + [FromQuery] string? mediaSourceId, + [FromQuery] string? deviceId, + [FromQuery] string? audioCodec, + [FromQuery] bool? enableAutoStreamCopy, + [FromQuery] bool? allowVideoStreamCopy, + [FromQuery] bool? allowAudioStreamCopy, + [FromQuery] bool? breakOnNonKeyFrames, + [FromQuery] int? audioSampleRate, + [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? audioBitRate, + [FromQuery] int? audioChannels, + [FromQuery] int? maxAudioChannels, + [FromQuery] string? profile, + [FromQuery] string? level, + [FromQuery] float? framerate, + [FromQuery] float? maxFramerate, + [FromQuery] bool? copyTimestamps, + [FromQuery] long? startTimeTicks, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? videoBitRate, + [FromQuery] int? subtitleStreamIndex, + [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] int? maxRefFrames, + [FromQuery] int? maxVideoBitDepth, + [FromQuery] bool? requireAvc, + [FromQuery] bool? deInterlace, + [FromQuery] bool? requireNonAnamorphic, + [FromQuery] int? transcodingMaxAudioChannels, + [FromQuery] int? cpuCoreLimit, + [FromQuery] string? liveStreamId, + [FromQuery] bool? enableMpegtsM2TsMode, + [FromQuery] string? videoCodec, + [FromQuery] string? subtitleCodec, + [FromQuery] string? transcodingReasons, + [FromQuery] int? audioStreamIndex, + [FromQuery] int? videoStreamIndex, + [FromQuery] EncodingContext? context, + [FromQuery] Dictionary? streamOptions) + { + StreamingRequestDto streamingRequest = new StreamingRequestDto + { + Id = itemId, + Container = container, + Static = @static ?? true, + Params = @params, + Tag = tag, + DeviceProfileId = deviceProfileId, + PlaySessionId = playSessionId, + SegmentContainer = segmentContainer, + SegmentLength = segmentLength, + MinSegments = minSegments, + MediaSourceId = mediaSourceId, + DeviceId = deviceId, + AudioCodec = audioCodec, + EnableAutoStreamCopy = enableAutoStreamCopy ?? true, + AllowAudioStreamCopy = allowAudioStreamCopy ?? true, + AllowVideoStreamCopy = allowVideoStreamCopy ?? true, + BreakOnNonKeyFrames = breakOnNonKeyFrames ?? false, + AudioSampleRate = audioSampleRate, + MaxAudioChannels = maxAudioChannels, + AudioBitRate = audioBitRate, + MaxAudioBitDepth = maxAudioBitDepth, + AudioChannels = audioChannels, + Profile = profile, + Level = level, + Framerate = framerate, + MaxFramerate = maxFramerate, + CopyTimestamps = copyTimestamps ?? true, + StartTimeTicks = startTimeTicks, + Width = width, + Height = height, + VideoBitRate = videoBitRate, + SubtitleStreamIndex = subtitleStreamIndex, + SubtitleMethod = subtitleMethod, + MaxRefFrames = maxRefFrames, + MaxVideoBitDepth = maxVideoBitDepth, + RequireAvc = requireAvc ?? true, + DeInterlace = deInterlace ?? true, + RequireNonAnamorphic = requireNonAnamorphic ?? true, + TranscodingMaxAudioChannels = transcodingMaxAudioChannels, + CpuCoreLimit = cpuCoreLimit, + LiveStreamId = liveStreamId, + EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? true, + VideoCodec = videoCodec, + SubtitleCodec = subtitleCodec, + TranscodeReasons = transcodingReasons, + AudioStreamIndex = audioStreamIndex, + VideoStreamIndex = videoStreamIndex, + Context = context ?? EncodingContext.Static, + StreamOptions = streamOptions + }; + + return await _audioHelper.GetAudioStream(_transcodingJobType, streamingRequest).ConfigureAwait(false); + } + + /// + /// Gets an audio stream. + /// + /// The item id. + /// The audio container. + /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + /// The streaming parameters. + /// The tag. + /// Optional. The dlna device profile id to utilize. + /// The play session id. + /// The segment container. + /// The segment lenght. + /// The minimum number of segments. + /// The media version id, if playing an alternate version. + /// The device id of the client requesting. Used to stop encoding processes when needed. + /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + /// Whether or not to allow copying of the video stream url. + /// Whether or not to allow copying of the audio stream url. + /// Optional. Whether to break on non key frames. + /// Optional. Specify a specific audio sample rate, e.g. 44100. + /// Optional. The maximum audio bit depth. + /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + /// Optional. Specify a specific number of audio channels to encode to, e.g. 2. + /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + /// Optional. The fixed horizontal resolution of the encoded video. + /// Optional. The fixed vertical resolution of the encoded video. + /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + /// Optional. Specify the subtitle delivery method. + /// Optional. + /// Optional. The maximum video bit depth. + /// Optional. Whether to require avc. + /// Optional. Whether to deinterlace the video. + /// Optional. Whether to require a non anamporphic stream. + /// Optional. The maximum number of audio channels to transcode. + /// Optional. The limit of how many cpu cores to use. + /// The live stream id. + /// Optional. Whether to enable the MpegtsM2Ts mode. + /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + /// Optional. Specify a subtitle codec to encode to. + /// Optional. The transcoding reason. + /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + /// Optional. The index of the video stream to use. If omitted the first video stream will be used. + /// Optional. The . + /// Optional. The streaming options. + /// Audio stream returned. + /// A containing the audio file. + [HttpGet("{itemId}/stream.{container}", Name = "GetAudioStreamByContainer")] + [HttpHead("{itemId}/stream.{container}", Name = "HeadAudioStreamByContainer")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesAudioFile] + public async Task GetAudioStreamByContainer( + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index e07690e11..a6b249ccf 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -833,7 +833,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid itemId, [FromRoute, Required] string playlistId, [FromRoute, Required] int segmentId, - [FromRoute] string container, + [FromRoute, Required] string container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, @@ -1004,7 +1004,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid itemId, [FromRoute, Required] string playlistId, [FromRoute, Required] int segmentId, - [FromRoute] string container, + [FromRoute, Required] string container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 4a67c1aed..bb0f27312 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -85,7 +85,6 @@ namespace Jellyfin.Api.Controllers /// User does not have permission to delete the image. /// A . [HttpPost("Users/{userId}/Images/{imageType}")] - [HttpPost("Users/{userId}/Images/{imageType}/{index?}", Name = "PostUserImage_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] @@ -94,7 +93,53 @@ namespace Jellyfin.Api.Controllers public async Task PostUserImage( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, - [FromRoute] int? index = null) + [FromQuery] int? index = null) + { + if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) + { + return Forbid("User is not allowed to update the image."); + } + + var user = _userManager.GetUserById(userId); + await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage != null) + { + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + } + + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); + + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + + return NoContent(); + } + + /// + /// Sets the user image. + /// + /// User Id. + /// (Unused) Image type. + /// (Unused) Image index. + /// Image updated. + /// User does not have permission to delete the image. + /// A . + [HttpPost("Users/{userId}/Images/{imageType}/{index}")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [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 PostUserImageByIndex( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromRoute] int index) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -131,8 +176,7 @@ namespace Jellyfin.Api.Controllers /// Image deleted. /// User does not have permission to delete the image. /// A . - [HttpDelete("Users/{userId}/Images/{itemType}")] - [HttpDelete("Users/{userId}/Images/{itemType}/{index?}", Name = "DeleteUserImage_2")] + [HttpDelete("Users/{userId}/Images/{imageType}")] [Authorize(Policy = Policies.DefaultAuthorization)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] @@ -141,7 +185,46 @@ namespace Jellyfin.Api.Controllers public async Task DeleteUserImage( [FromRoute, Required] Guid userId, [FromRoute, Required] ImageType imageType, - [FromRoute] int? index = null) + [FromQuery] int? index = null) + { + if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) + { + return Forbid("User is not allowed to delete the image."); + } + + var user = _userManager.GetUserById(userId); + try + { + System.IO.File.Delete(user.ProfileImage.Path); + } + catch (IOException e) + { + _logger.LogError(e, "Error deleting user profile image:"); + } + + await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); + return NoContent(); + } + + /// + /// Delete the user's image. + /// + /// User Id. + /// (Unused) Image type. + /// (Unused) Image index. + /// Image deleted. + /// User does not have permission to delete the image. + /// A . + [HttpDelete("Users/{userId}/Images/{imageType}/{index}")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task DeleteUserImageByIndex( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromRoute] int index) { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { @@ -172,14 +255,13 @@ namespace Jellyfin.Api.Controllers /// Item not found. /// A on success, or a if item not found. [HttpDelete("Items/{itemId}/Images/{imageType}")] - [HttpDelete("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "DeleteItemImage_2")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteItemImage( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute] int? imageIndex = null) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -191,25 +273,83 @@ namespace Jellyfin.Api.Controllers return NoContent(); } + /// + /// Delete an item's image. + /// + /// Item id. + /// Image type. + /// The image index. + /// Image deleted. + /// Item not found. + /// A on success, or a if item not found. + [HttpDelete("Items/{itemId}/Images/{imageType}/{imageIndex}")] + [Authorize(Policy = Policies.RequiresElevation)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteItemImageByIndex( + [FromRoute, Required] Guid itemId, + [FromRoute, Required] ImageType imageType, + [FromRoute] int imageIndex) + { + var item = _libraryManager.GetItemById(itemId); + if (item == null) + { + return NotFound(); + } + + await item.DeleteImageAsync(imageType, imageIndex).ConfigureAwait(false); + return NoContent(); + } + /// /// Set item image. /// /// Item id. /// Image type. - /// (Unused) Image index. /// Image saved. /// Item not found. /// A on success, or a if item not found. [HttpPost("Items/{itemId}/Images/{imageType}")] - [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "SetItemImage_2")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [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) + { + var item = _libraryManager.GetItemById(itemId); + if (item == null) + { + return NotFound(); + } + + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + await _providerManager.SaveImage(item, Request.Body, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + + return NoContent(); + } + + /// + /// Set item image. + /// + /// Item id. + /// Image type. + /// (Unused) Image index. + /// Image saved. + /// Item not found. + /// A on success, or a if item not found. + [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}")] + [Authorize(Policy = Policies.RequiresElevation)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] + public async Task SetItemImageByIndex( [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, - [FromRoute] int? imageIndex = null) + [FromRoute] int imageIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -349,8 +489,6 @@ namespace Jellyfin.Api.Controllers /// [HttpGet("Items/{itemId}/Images/{imageType}")] [HttpHead("Items/{itemId}/Images/{imageType}", Name = "HeadItemImage")] - [HttpGet("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "GetItemImage_2")] - [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "HeadItemImage_2")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] @@ -371,7 +509,86 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] int? imageIndex) + { + var item = _libraryManager.GetItemById(itemId); + if (item == null) + { + return NotFound(); + } + + return await GetImageInternal( + itemId, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + item, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase)) + .ConfigureAwait(false); + } + + /// + /// Gets the item's image. + /// + /// Item id. + /// Image type. + /// Image index. + /// The maximum image width to return. + /// The maximum image height to return. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. The of the returned image. + /// Optional. Add a played indicator. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Items/{itemId}/Images/{imageType}/{imageIndex}")] + [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex}", Name = "HeadItemImageByIndex")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetItemImageByIndex( + [FromRoute, Required] Guid itemId, + [FromRoute, Required] ImageType imageType, + [FromRoute] int imageIndex, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] string? tag, + [FromQuery] bool? cropWhitespace, + [FromQuery] ImageFormat? format, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -507,8 +724,8 @@ 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)] [ProducesImageFile] @@ -586,8 +803,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Genres/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("Genres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadGenreImage")] + [HttpGet("Genres/{name}/Images/{imageType}")] + [HttpHead("Genres/{name}/Images/{imageType}", Name = "HeadGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] @@ -608,7 +825,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -640,10 +857,11 @@ namespace Jellyfin.Api.Controllers } /// - /// Get music genre image by name. + /// Get genre image by name. /// - /// Music genre name. + /// Genre name. /// Image type. + /// Image index. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Determines the output format of the image - original,gif,jpg,png. /// The maximum image width to return. @@ -658,21 +876,21 @@ namespace Jellyfin.Api.Controllers /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. - /// Image index. /// Image stream returned. /// Item not found. /// /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("MusicGenres/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("MusicGenres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadMusicGenreImage")] + [HttpGet("Genres/{name}/Images/{imageType}/{imageIndex}")] + [HttpHead("Genres/{name}/Images/{imageType}/{imageIndex}", Name = "HeadGenreImageByIndex")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetMusicGenreImage( + public async Task GetGenreImageByIndex( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int imageIndex, [FromQuery] string tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, @@ -686,10 +904,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] string? foregroundLayer) { - var item = _libraryManager.GetMusicGenre(name); + var item = _libraryManager.GetGenre(name); if (item == null) { return NotFound(); @@ -719,9 +936,9 @@ namespace Jellyfin.Api.Controllers } /// - /// Get person image by name. + /// Get music genre image by name. /// - /// Person name. + /// Music genre name. /// Image type. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Determines the output format of the image - original,gif,jpg,png. @@ -744,12 +961,12 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Persons/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("Persons/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadPersonImage")] + [HttpGet("MusicGenres/{name}/Images/{imageType}")] + [HttpHead("MusicGenres/{name}/Images/{imageType}", Name = "HeadMusicGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetPersonImage( + public async Task GetMusicGenreImage( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromQuery] string tag, @@ -766,9 +983,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] int? imageIndex) { - var item = _libraryManager.GetPerson(name); + var item = _libraryManager.GetMusicGenre(name); if (item == null) { return NotFound(); @@ -798,10 +1015,11 @@ namespace Jellyfin.Api.Controllers } /// - /// Get studio image by name. + /// Get music genre image by name. /// - /// Studio name. + /// Music genre name. /// Image type. + /// Image index. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Determines the output format of the image - original,gif,jpg,png. /// The maximum image width to return. @@ -816,23 +1034,23 @@ namespace Jellyfin.Api.Controllers /// Optional. Blur image. /// Optional. Apply a background color for transparent images. /// Optional. Apply a foreground layer on top of the image. - /// Image index. /// Image stream returned. /// Item not found. /// /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Studios/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("Studios/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadStudioImage")] + [HttpGet("MusicGenres/{name}/Images/{imageType}/{imageIndex}")] + [HttpHead("MusicGenres/{name}/Images/{imageType}/{imageIndex}", Name = "HeadMusicGenreImageByIndex")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetStudioImage( + public async Task GetMusicGenreImageByIndex( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromRoute, Required] string tag, - [FromRoute, Required] ImageFormat format, + [FromRoute, Required] int imageIndex, + [FromQuery] string tag, + [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, [FromQuery] double? percentPlayed, @@ -844,10 +1062,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] string? foregroundLayer) { - var item = _libraryManager.GetStudio(name); + var item = _libraryManager.GetMusicGenre(name); if (item == null) { return NotFound(); @@ -877,9 +1094,9 @@ namespace Jellyfin.Api.Controllers } /// - /// Get user profile image. + /// Get person image by name. /// - /// User id. + /// Person name. /// Image type. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Determines the output format of the image - original,gif,jpg,png. @@ -902,15 +1119,15 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("Users/{userId}/Images/{imageType}/{imageIndex?}")] - [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex?}", Name = "HeadUserImage")] + [HttpGet("Persons/{name}/Images/{imageType}")] + [HttpHead("Persons/{name}/Images/{imageType}", Name = "HeadPersonImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesImageFile] - public async Task GetUserImage( - [FromRoute, Required] Guid userId, + public async Task GetPersonImage( + [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromQuery] string? tag, + [FromQuery] string tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -924,7 +1141,420 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute] int? imageIndex = null) + [FromQuery] int? imageIndex) + { + var item = _libraryManager.GetPerson(name); + if (item == null) + { + return NotFound(); + } + + return await GetImageInternal( + item.Id, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + item, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase)) + .ConfigureAwait(false); + } + + /// + /// Get person image by name. + /// + /// Person name. + /// Image type. + /// Image index. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. Add a played indicator. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Persons/{name}/Images/{imageType}/{imageIndex}")] + [HttpHead("Persons/{name}/Images/{imageType}/{imageIndex}", Name = "HeadPersonImageByIndex")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetPersonImageByIndex( + [FromRoute, Required] string name, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int imageIndex, + [FromQuery] string tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] bool? cropWhitespace, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer) + { + var item = _libraryManager.GetPerson(name); + if (item == null) + { + return NotFound(); + } + + return await GetImageInternal( + item.Id, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + item, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase)) + .ConfigureAwait(false); + } + + /// + /// Get studio image by name. + /// + /// Studio name. + /// Image type. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. Add a played indicator. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image index. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Studios/{name}/Images/{imageType}")] + [HttpHead("Studios/{name}/Images/{imageType}", Name = "HeadStudioImage")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetStudioImage( + [FromRoute, Required] string name, + [FromRoute, Required] ImageType imageType, + [FromQuery] string? tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] bool? cropWhitespace, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer, + [FromQuery] int? imageIndex) + { + var item = _libraryManager.GetStudio(name); + if (item == null) + { + return NotFound(); + } + + return await GetImageInternal( + item.Id, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + item, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase)) + .ConfigureAwait(false); + } + + /// + /// Get studio image by name. + /// + /// Studio name. + /// Image type. + /// Image index. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. Add a played indicator. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Studios/{name}/Images/{imageType}/{imageIndex}")] + [HttpHead("Studios/{name}/Images/{imageType}/{imageIndex}", Name = "HeadStudioImageByIndex")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetStudioImageByIndex( + [FromRoute, Required] string name, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int imageIndex, + [FromQuery] string? tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] bool? cropWhitespace, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer) + { + var item = _libraryManager.GetStudio(name); + if (item == null) + { + return NotFound(); + } + + return await GetImageInternal( + item.Id, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + item, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase)) + .ConfigureAwait(false); + } + + /// + /// Get user profile image. + /// + /// User id. + /// Image type. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. Add a played indicator. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image index. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Users/{userId}/Images/{imageType}")] + [HttpHead("Users/{userId}/Images/{imageType}", Name = "HeadUserImage")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetUserImage( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromQuery] string? tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] bool? cropWhitespace, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer, + [FromQuery] int? imageIndex) + { + var user = _userManager.GetUserById(userId); + if (user == null) + { + return NotFound(); + } + + var info = new ItemImageInfo + { + Path = user.ProfileImage.Path, + Type = ImageType.Profile, + DateModified = user.ProfileImage.LastModified + }; + + if (width.HasValue) + { + info.Width = width.Value; + } + + if (height.HasValue) + { + info.Height = height.Value; + } + + return await GetImageInternal( + user.Id, + imageType, + imageIndex, + tag, + format, + maxWidth, + maxHeight, + percentPlayed, + unplayedCount, + width, + height, + quality, + cropWhitespace, + addPlayedIndicator, + blur, + backgroundColor, + foregroundLayer, + null, + Request.Method.Equals(HttpMethods.Head, StringComparison.OrdinalIgnoreCase), + info) + .ConfigureAwait(false); + } + + /// + /// Get user profile image. + /// + /// User id. + /// Image type. + /// Image index. + /// Optional. Supply the cache tag from the item object to receive strong caching headers. + /// Determines the output format of the image - original,gif,jpg,png. + /// The maximum image width to return. + /// The maximum image height to return. + /// Optional. Percent to render for the percent played overlay. + /// Optional. Unplayed count overlay to render. + /// The fixed image width to return. + /// The fixed image height to return. + /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. + /// Optional. Add a played indicator. + /// Optional. Blur image. + /// Optional. Apply a background color for transparent images. + /// Optional. Apply a foreground layer on top of the image. + /// Image stream returned. + /// Item not found. + /// + /// A containing the file stream on success, + /// or a if item not found. + /// + [HttpGet("Users/{userId}/Images/{imageType}/{imageIndex}")] + [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex}", Name = "HeadUserImageByIndex")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesImageFile] + public async Task GetUserImageByIndex( + [FromRoute, Required] Guid userId, + [FromRoute, Required] ImageType imageType, + [FromRoute, Required] int imageIndex, + [FromQuery] string? tag, + [FromQuery] ImageFormat? format, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] double? percentPlayed, + [FromQuery] int? unplayedCount, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? quality, + [FromQuery] bool? cropWhitespace, + [FromQuery] bool? addPlayedIndicator, + [FromQuery] int? blur, + [FromQuery] string? backgroundColor, + [FromQuery] string? foregroundLayer) { var user = _userManager.GetUserById(userId); if (user == null) diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index d17a26db4..efb0ae19b 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -206,7 +206,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("Artists/InstantMix")] + [HttpGet("Artists/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromArtists( [FromRoute, Required] Guid id, @@ -242,7 +242,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("MusicGenres/InstantMix")] + [HttpGet("MusicGenres/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenres( [FromRoute, Required] Guid id, diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index d8d371ebc..63985c72a 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -60,7 +60,6 @@ namespace Jellyfin.Api.Controllers /// /// Gets items based on a query. /// - /// The user id supplied in the /Users/{uid}/Items. /// The user id supplied as query parameter. /// Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). /// Optional filter by items with theme songs. @@ -143,10 +142,8 @@ namespace Jellyfin.Api.Controllers /// Optional, include image information in output. /// A with the items. [HttpGet("Items")] - [HttpGet("Users/{uId}/Items", Name = "GetItems_2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( - [FromRoute] Guid? uId, [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, @@ -228,9 +225,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { - // use user id route parameter over query parameter - userId = uId ?? userId; - var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) : null; @@ -505,6 +499,257 @@ namespace Jellyfin.Api.Controllers return new QueryResult { StartIndex = startIndex.GetValueOrDefault(), TotalRecordCount = result.TotalRecordCount, Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user) }; } + /// + /// Gets items based on a query. + /// + /// The user id supplied as query parameter. + /// Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). + /// Optional filter by items with theme songs. + /// Optional filter by items with theme videos. + /// Optional filter by items with subtitles. + /// Optional filter by items with special features. + /// Optional filter by items with trailers. + /// Optional. Return items that are siblings of a supplied item. + /// Optional filter by parent index number. + /// Optional filter by items that have or do not have a parental rating. + /// Optional filter by items that are HD or not. + /// Optional filter by items that are 4K or not. + /// Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted. + /// Optional. If specified, results will be filtered based on the LocationType. This allows multiple, comma delimeted. + /// Optional filter by items that are missing episodes or not. + /// Optional filter by items that are unaired episodes or not. + /// Optional filter by minimum community rating. + /// Optional filter by minimum critic rating. + /// Optional. The minimum premiere date. Format = ISO. + /// Optional. The minimum last saved date. Format = ISO. + /// Optional. The minimum last saved date for the current user. Format = ISO. + /// Optional. The maximum premiere date. Format = ISO. + /// Optional filter by items that have an overview or not. + /// Optional filter by items that have an imdb id or not. + /// Optional filter by items that have a tmdb id or not. + /// Optional filter by items that have a tvdb id or not. + /// Optional. If specified, results will be filtered by exxcluding item ids. This allows multiple, comma delimeted. + /// Optional. The record index to start at. All items with a lower index will be dropped from the results. + /// Optional. The maximum number of records to return. + /// When searching within folders, this determines whether or not the search will be recursive. true/false. + /// Optional. Filter based on a search term. + /// Sort Order - Ascending,Descending. + /// Specify this to localize the search to a specific item or folder. Omit to use the root. + /// Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines. + /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted. + /// Optional. If specified, results will be filtered based on the item type. This allows multiple, comma delimeted. + /// Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes. + /// Optional filter by items that are marked as favorite, or not. + /// Optional filter by MediaType. Allows multiple, comma delimited. + /// Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited. + /// Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime. + /// Optional filter by items that are played, or not. + /// Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on OfficialRating. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on tag. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted. + /// Optional, include user data. + /// Optional, the max number of images to return, per image type. + /// Optional. The image types to include in the output. + /// Optional. If specified, results will be filtered to include only those containing the specified person. + /// Optional. If specified, results will be filtered to include only those containing the specified person id. + /// Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited. + /// Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on artists. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on artist id. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered to include only those containing the specified artist id. + /// Optional. If specified, results will be filtered to include only those containing the specified album artist id. + /// Optional. If specified, results will be filtered to include only those containing the specified contributing artist id. + /// Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on album id. This allows multiple, pipe delimeted. + /// Optional. If specific items are needed, specify a list of item id's to retrieve. This allows multiple, comma delimited. + /// Optional filter by VideoType (videofile, dvd, bluray, iso). Allows multiple, comma delimeted. + /// Optional filter by minimum official rating (PG, PG-13, TV-MA, etc). + /// Optional filter by items that are locked. + /// Optional filter by items that are placeholders. + /// Optional filter by items that have official ratings. + /// Whether or not to hide items behind their boxsets. + /// Optional. Filter by the minimum width of the item. + /// Optional. Filter by the minimum height of the item. + /// Optional. Filter by the maximum width of the item. + /// Optional. Filter by the maximum height of the item. + /// Optional filter by items that are 3D, or not. + /// Optional filter by Series Status. Allows multiple, comma delimeted. + /// Optional filter by items whose name is sorted equally or greater than a given input string. + /// Optional filter by items whose name is sorted equally than a given input string. + /// Optional filter by items whose name is equally or lesser than a given input string. + /// Optional. If specified, results will be filtered based on studio id. This allows multiple, pipe delimeted. + /// Optional. If specified, results will be filtered based on genre id. This allows multiple, pipe delimeted. + /// Optional. Enable the total record count. + /// Optional, include image information in output. + /// A with the items. + [HttpGet("Users/{userId}/Items")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult> GetItemsByUserId( + [FromRoute] Guid userId, + [FromQuery] string? maxOfficialRating, + [FromQuery] bool? hasThemeSong, + [FromQuery] bool? hasThemeVideo, + [FromQuery] bool? hasSubtitles, + [FromQuery] bool? hasSpecialFeature, + [FromQuery] bool? hasTrailer, + [FromQuery] string? adjacentTo, + [FromQuery] int? parentIndexNumber, + [FromQuery] bool? hasParentalRating, + [FromQuery] bool? isHd, + [FromQuery] bool? is4K, + [FromQuery] string? locationTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] excludeLocationTypes, + [FromQuery] bool? isMissing, + [FromQuery] bool? isUnaired, + [FromQuery] double? minCommunityRating, + [FromQuery] double? minCriticRating, + [FromQuery] DateTime? minPremiereDate, + [FromQuery] DateTime? minDateLastSaved, + [FromQuery] DateTime? minDateLastSavedForUser, + [FromQuery] DateTime? maxPremiereDate, + [FromQuery] bool? hasOverview, + [FromQuery] bool? hasImdbId, + [FromQuery] bool? hasTmdbId, + [FromQuery] bool? hasTvdbId, + [FromQuery] string? excludeItemIds, + [FromQuery] int? startIndex, + [FromQuery] int? limit, + [FromQuery] bool? recursive, + [FromQuery] string? searchTerm, + [FromQuery] string? sortOrder, + [FromQuery] string? parentId, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, + [FromQuery] bool? isFavorite, + [FromQuery] string? mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] imageTypes, + [FromQuery] string? sortBy, + [FromQuery] bool? isPlayed, + [FromQuery] string? genres, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, + [FromQuery] bool? enableUserData, + [FromQuery] int? imageTypeLimit, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? artists, + [FromQuery] string? excludeArtistIds, + [FromQuery] string? artistIds, + [FromQuery] string? albumArtistIds, + [FromQuery] string? contributingArtistIds, + [FromQuery] string? albums, + [FromQuery] string? albumIds, + [FromQuery] string? ids, + [FromQuery] string? videoTypes, + [FromQuery] string? minOfficialRating, + [FromQuery] bool? isLocked, + [FromQuery] bool? isPlaceHolder, + [FromQuery] bool? hasOfficialRating, + [FromQuery] bool? collapseBoxSetItems, + [FromQuery] int? minWidth, + [FromQuery] int? minHeight, + [FromQuery] int? maxWidth, + [FromQuery] int? maxHeight, + [FromQuery] bool? is3D, + [FromQuery] string? seriesStatus, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, + [FromQuery] string? studioIds, + [FromQuery] string? genreIds, + [FromQuery] bool enableTotalRecordCount = true, + [FromQuery] bool? enableImages = true) + { + return GetItems( + userId, + maxOfficialRating, + hasThemeSong, + hasThemeVideo, + hasSubtitles, + hasSpecialFeature, + hasTrailer, + adjacentTo, + parentIndexNumber, + hasParentalRating, + isHd, + is4K, + locationTypes, + excludeLocationTypes, + isMissing, + isUnaired, + minCommunityRating, + minCriticRating, + minPremiereDate, + minDateLastSaved, + minDateLastSavedForUser, + maxPremiereDate, + hasOverview, + hasImdbId, + hasTmdbId, + hasTvdbId, + excludeItemIds, + startIndex, + limit, + recursive, + searchTerm, + sortOrder, + parentId, + fields, + excludeItemTypes, + includeItemTypes, + filters, + isFavorite, + mediaTypes, + imageTypes, + sortBy, + isPlayed, + genres, + officialRatings, + tags, + years, + enableUserData, + imageTypeLimit, + enableImageTypes, + person, + personIds, + personTypes, + studios, + artists, + excludeArtistIds, + artistIds, + albumArtistIds, + contributingArtistIds, + albums, + albumIds, + ids, + videoTypes, + minOfficialRating, + isLocked, + isPlaceHolder, + hasOfficialRating, + collapseBoxSetItems, + minWidth, + minHeight, + maxWidth, + maxHeight, + is3D, + seriesStatus, + nameStartsWithOrGreater, + nameStartsWith, + nameLessThan, + studioIds, + genreIds, + enableTotalRecordCount, + enableImages); + } + /// /// Gets items based on a query. /// diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index a01ae31a0..dcb8e803b 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -193,7 +193,6 @@ namespace Jellyfin.Api.Controllers /// File returned. /// A with the subtitle file. [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( @@ -204,7 +203,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] long? endPositionTicks, [FromQuery] bool copyTimestamps = false, [FromQuery] bool addVttTimeMap = false, - [FromRoute] long startPositionTicks = 0) + [FromQuery] long startPositionTicks = 0) { if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) { @@ -249,6 +248,43 @@ namespace Jellyfin.Api.Controllers MimeTypes.GetMimeType("file." + format)); } + /// + /// Gets subtitles in a specified format. + /// + /// The item id. + /// The media source id. + /// The subtitle stream index. + /// Optional. The start position of the subtitle in ticks. + /// The format of the returned subtitle. + /// Optional. The end position of the subtitle in ticks. + /// Optional. Whether to copy the timestamps. + /// Optional. Whether to add a VTT time map. + /// File returned. + /// A with the subtitle file. + [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks}/Stream.{format}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile("text/*")] + public Task GetSubtitleWithTicks( + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string mediaSourceId, + [FromRoute, Required] int index, + [FromRoute, Required] long startPositionTicks, + [FromRoute, Required] string format, + [FromQuery] long? endPositionTicks, + [FromQuery] bool copyTimestamps = false, + [FromQuery] bool addVttTimeMap = false) + { + return GetSubtitle( + itemId, + mediaSourceId, + index, + format, + endPositionTicks, + copyTimestamps, + addVttTimeMap, + startPositionTicks); + } + /// /// Gets an HLS subtitle playlist. /// @@ -335,6 +371,7 @@ namespace Jellyfin.Api.Controllers /// Subtitle uploaded. /// A . [HttpPost("Videos/{itemId}/Subtitles")] + [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task UploadSubtitle( [FromRoute, Required] Guid itemId, [FromBody, Required] UploadSubtitleDto body) @@ -446,6 +483,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("FallbackFont/Fonts/{name}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesFile("font/*")] public ActionResult GetFallbackFont([FromRoute, Required] string name) { var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index d78adcbcd..ffdbb15df 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -197,7 +197,6 @@ namespace Jellyfin.Api.Controllers return _itemsController .GetItems( - userId, userId, maxOfficialRating, hasThemeSong, diff --git a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs index 418c0c123..c2bb0dfff 100644 --- a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs +++ b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.Net.Mime; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Attributes; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -43,7 +44,7 @@ namespace Jellyfin.Api.Controllers /// Video or attachment not found. /// An containing the attachment stream on success, or a if the attachment could not be found. [HttpGet("{videoId}/{mediaSourceId}/Attachments/{index}")] - [Produces(MediaTypeNames.Application.Octet)] + [ProducesFile(MediaTypeNames.Application.Octet)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetAttachment( diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 4de7aac71..1a23076f1 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -326,15 +326,13 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Video stream returned. /// A containing the audio file. - [HttpGet("{itemId}/{stream=stream}.{container?}", Name = "GetVideoStreamWithExt")] [HttpGet("{itemId}/stream")] - [HttpHead("{itemId}/{stream=stream}.{container?}", Name = "HeadVideoStreamWithExt")] [HttpHead("{itemId}/stream", Name = "HeadVideoStream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesVideoFile] public async Task GetVideoStream( [FromRoute, Required] Guid itemId, - [FromRoute] string? container, + [FromQuery] string? container, [FromQuery] bool? @static, [FromQuery] string? @params, [FromQuery] string? tag, @@ -529,5 +527,166 @@ namespace Jellyfin.Api.Controllers _transcodingJobType, cancellationTokenSource).ConfigureAwait(false); } + + /// + /// Gets a video stream. + /// + /// The item id. + /// The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, mpg, avi, 3gp, wmv, wtv, m2ts, mov, iso, flv. + /// Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false. + /// The streaming parameters. + /// The tag. + /// Optional. The dlna device profile id to utilize. + /// The play session id. + /// The segment container. + /// The segment lenght. + /// The minimum number of segments. + /// The media version id, if playing an alternate version. + /// The device id of the client requesting. Used to stop encoding processes when needed. + /// Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma. + /// Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true. + /// Whether or not to allow copying of the video stream url. + /// Whether or not to allow copying of the audio stream url. + /// Optional. Whether to break on non key frames. + /// Optional. Specify a specific audio sample rate, e.g. 44100. + /// Optional. The maximum audio bit depth. + /// Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults. + /// Optional. Specify a specific number of audio channels to encode to, e.g. 2. + /// Optional. Specify a maximum number of audio channels to encode to, e.g. 2. + /// Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high. + /// Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1. + /// Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + /// Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements. + /// Whether or not to copy timestamps when transcoding with an offset. Defaults to false. + /// Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms. + /// Optional. The fixed horizontal resolution of the encoded video. + /// Optional. The fixed vertical resolution of the encoded video. + /// Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults. + /// Optional. The index of the subtitle stream to use. If omitted no subtitles will be used. + /// Optional. Specify the subtitle delivery method. + /// Optional. + /// Optional. The maximum video bit depth. + /// Optional. Whether to require avc. + /// Optional. Whether to deinterlace the video. + /// Optional. Whether to require a non anamporphic stream. + /// Optional. The maximum number of audio channels to transcode. + /// Optional. The limit of how many cpu cores to use. + /// The live stream id. + /// Optional. Whether to enable the MpegtsM2Ts mode. + /// Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv. + /// Optional. Specify a subtitle codec to encode to. + /// Optional. The transcoding reason. + /// Optional. The index of the audio stream to use. If omitted the first audio stream will be used. + /// Optional. The index of the video stream to use. If omitted the first video stream will be used. + /// Optional. The . + /// Optional. The streaming options. + /// Video stream returned. + /// A containing the audio file. + [HttpGet("{itemId}/{stream=stream}.{container}")] + [HttpHead("{itemId}/{stream=stream}.{container}", Name = "HeadVideoStreamByContainer")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesVideoFile] + public Task GetVideoStreamByContainer( + [FromRoute, Required] Guid itemId, + [FromRoute, Required] string container, + [FromQuery] bool? @static, + [FromQuery] string? @params, + [FromQuery] string? tag, + [FromQuery] string? deviceProfileId, + [FromQuery] string? playSessionId, + [FromQuery] string? segmentContainer, + [FromQuery] int? segmentLength, + [FromQuery] int? minSegments, + [FromQuery] string? mediaSourceId, + [FromQuery] string? deviceId, + [FromQuery] string? audioCodec, + [FromQuery] bool? enableAutoStreamCopy, + [FromQuery] bool? allowVideoStreamCopy, + [FromQuery] bool? allowAudioStreamCopy, + [FromQuery] bool? breakOnNonKeyFrames, + [FromQuery] int? audioSampleRate, + [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? audioBitRate, + [FromQuery] int? audioChannels, + [FromQuery] int? maxAudioChannels, + [FromQuery] string? profile, + [FromQuery] string? level, + [FromQuery] float? framerate, + [FromQuery] float? maxFramerate, + [FromQuery] bool? copyTimestamps, + [FromQuery] long? startTimeTicks, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? videoBitRate, + [FromQuery] int? subtitleStreamIndex, + [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] int? maxRefFrames, + [FromQuery] int? maxVideoBitDepth, + [FromQuery] bool? requireAvc, + [FromQuery] bool? deInterlace, + [FromQuery] bool? requireNonAnamorphic, + [FromQuery] int? transcodingMaxAudioChannels, + [FromQuery] int? cpuCoreLimit, + [FromQuery] string? liveStreamId, + [FromQuery] bool? enableMpegtsM2TsMode, + [FromQuery] string? videoCodec, + [FromQuery] string? subtitleCodec, + [FromQuery] string? transcodingReasons, + [FromQuery] int? audioStreamIndex, + [FromQuery] int? videoStreamIndex, + [FromQuery] EncodingContext context, + [FromQuery] Dictionary streamOptions) + { + return GetVideoStream( + itemId, + container, + @static, + @params, + tag, + deviceProfileId, + playSessionId, + segmentContainer, + segmentLength, + minSegments, + mediaSourceId, + deviceId, + audioCodec, + enableAutoStreamCopy, + allowVideoStreamCopy, + allowAudioStreamCopy, + breakOnNonKeyFrames, + audioSampleRate, + maxAudioBitDepth, + audioBitRate, + audioChannels, + maxAudioChannels, + profile, + level, + framerate, + maxFramerate, + copyTimestamps, + startTimeTicks, + width, + height, + videoBitRate, + subtitleStreamIndex, + subtitleMethod, + maxRefFrames, + maxVideoBitDepth, + requireAvc, + deInterlace, + requireNonAnamorphic, + transcodingMaxAudioChannels, + cpuCoreLimit, + liveStreamId, + enableMpegtsM2TsMode, + videoCodec, + subtitleCodec, + transcodingReasons, + audioStreamIndex, + videoStreamIndex, + context, + streamOptions); + } } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 13234c381..4959a9b92 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1647,7 +1647,7 @@ namespace MediaBrowser.Model.Dlna // strip spaces to avoid having to encode var values = value - .Split('|', StringSplitOptions.RemoveEmptyEntries); + .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); if (condition.Condition == ProfileConditionType.Equals || condition.Condition == ProfileConditionType.EqualsAny) { -- cgit v1.2.3 From c01042b35560ddc703917d8e588cfb00734dc36f Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 21 Nov 2020 12:28:32 +0100 Subject: Fix nullref --- Jellyfin.Api/Controllers/ImageController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 76e53b9a5..366f70163 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -928,7 +928,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] int? imageIndex = null) { var user = _userManager.GetUserById(userId); - if (user == null) + if (user?.ProfileImage == null) { return NotFound(); } -- cgit v1.2.3 From f5973d57e8c070692450f0e04e01615c78c954d9 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 21 Nov 2020 14:26:03 +0100 Subject: Remove UTF8 bom from some files --- Jellyfin.Api/Controllers/ApiKeyController.cs | 2 +- Jellyfin.Api/Controllers/ArtistsController.cs | 2 +- Jellyfin.Api/Controllers/BrandingController.cs | 2 +- Jellyfin.Api/Controllers/CollectionController.cs | 2 +- Jellyfin.Api/Controllers/DashboardController.cs | 2 +- Jellyfin.Api/Controllers/FilterController.cs | 2 +- Jellyfin.Api/Controllers/GenresController.cs | 2 +- Jellyfin.Api/Controllers/HlsSegmentController.cs | 2 +- Jellyfin.Api/Controllers/ImageController.cs | 2 +- Jellyfin.Api/Controllers/InstantMixController.cs | 2 +- Jellyfin.Api/Controllers/ItemLookupController.cs | 2 +- Jellyfin.Api/Controllers/ItemUpdateController.cs | 2 +- Jellyfin.Api/Controllers/LocalizationController.cs | 2 +- Jellyfin.Api/Controllers/MediaInfoController.cs | 2 +- Jellyfin.Api/Controllers/MoviesController.cs | 2 +- Jellyfin.Api/Controllers/MusicGenresController.cs | 2 +- Jellyfin.Api/Controllers/PersonsController.cs | 2 +- Jellyfin.Api/Controllers/PlaylistsController.cs | 2 +- Jellyfin.Api/Controllers/PlaystateController.cs | 2 +- Jellyfin.Api/Controllers/PluginsController.cs | 2 +- Jellyfin.Api/Controllers/StudiosController.cs | 2 +- Jellyfin.Api/Controllers/SuggestionsController.cs | 2 +- Jellyfin.Api/Controllers/SyncPlayController.cs | 2 +- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Controllers/TimeSyncController.cs | 2 +- Jellyfin.Api/Controllers/UniversalAudioController.cs | 2 +- Jellyfin.Api/Controllers/UserController.cs | 2 +- Jellyfin.Api/Controllers/UserViewsController.cs | 2 +- Jellyfin.Api/Controllers/YearsController.cs | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index e8d6ccdf2..8c43d786a 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Globalization; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index f684c649a..c65dc8620 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/BrandingController.cs b/Jellyfin.Api/Controllers/BrandingController.cs index 1d4836f27..d3ea41201 100644 --- a/Jellyfin.Api/Controllers/BrandingController.cs +++ b/Jellyfin.Api/Controllers/BrandingController.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Branding; using Microsoft.AspNetCore.Http; diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 2a342c2cb..2a7b2b5c6 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index a859ac114..ccc81dfc5 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index c97a1ed14..31cb9e273 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.ModelBinders; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 2dd504770..d2b41e0a8 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index ccdbbb297..f51987732 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.IO; diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 366f70163..f48c1df72 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index d17a26db4..6913afd0f 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index a7c1a6388..6c38f77ce 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 0a6ed31ae..9e1a39853 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; diff --git a/Jellyfin.Api/Controllers/LocalizationController.cs b/Jellyfin.Api/Controllers/LocalizationController.cs index ef2e7e8b1..3d8b9e0ca 100644 --- a/Jellyfin.Api/Controllers/LocalizationController.cs +++ b/Jellyfin.Api/Controllers/LocalizationController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Jellyfin.Api.Constants; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 186024585..b42e6686e 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.ComponentModel.DataAnnotations; using System.Linq; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index ebc148fe5..75dfd4e68 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 8c6104302..e7d0a61c5 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 9dc79b388..aaad36551 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index bc47ecbd1..3e55434c0 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 5c15e9a0d..7a60b0deb 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 0f8ceba29..98f1bc2d2 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index af28b4f59..5090bf1de 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 69292186e..9f1dec712 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index e16a10ba4..346431e60 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading; diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index 4cb1984a2..92875d735 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; diff --git a/Jellyfin.Api/Controllers/TimeSyncController.cs b/Jellyfin.Api/Controllers/TimeSyncController.cs index 2dc744e7c..27c7186fc 100644 --- a/Jellyfin.Api/Controllers/TimeSyncController.cs +++ b/Jellyfin.Api/Controllers/TimeSyncController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using MediaBrowser.Model.SyncPlay; using Microsoft.AspNetCore.Http; diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 255532307..34c9f32fa 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 0f7c25d0e..9805b84b1 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index 60fd1df01..e1483ce9d 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 9c3ecb4ce..ec7c3de97 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -- cgit v1.2.3 From 5150598c6d3d0ddb4435d73d5bea80d4b1fd2769 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 7 Dec 2020 08:55:42 -0700 Subject: Fix API forbidden response --- Jellyfin.Api/Controllers/ImageController.cs | 8 ++++---- Jellyfin.Api/Controllers/QuickConnectController.cs | 4 ++-- Jellyfin.Api/Controllers/UserController.cs | 18 +++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 65de81d7a..e828a0801 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -98,7 +98,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to update the image."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); } var user = _userManager.GetUserById(userId); @@ -144,7 +144,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to update the image."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the image."); } var user = _userManager.GetUserById(userId); @@ -190,7 +190,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to delete the image."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to delete the image."); } var user = _userManager.GetUserById(userId); @@ -229,7 +229,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to delete the image."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to delete the image."); } var user = _userManager.GetUserById(userId); diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index 73da2f906..4ac849181 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers { if (_quickConnect.State == QuickConnectState.Unavailable) { - return Forbid("Quick connect is unavailable"); + return StatusCode(StatusCodes.Status403Forbidden, "Quick connect is unavailable"); } _quickConnect.Activate(); @@ -126,7 +126,7 @@ namespace Jellyfin.Api.Controllers var userId = ClaimHelpers.GetUserId(Request.HttpContext.User); if (!userId.HasValue) { - return Forbid("Unknown user id"); + return StatusCode(StatusCodes.Status403Forbidden, "Unknown user id"); } return _quickConnect.AuthorizeRequest(userId.Value, code); diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 9805b84b1..4cf8a9095 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -169,7 +169,7 @@ namespace Jellyfin.Api.Controllers if (!string.IsNullOrEmpty(password) && string.IsNullOrEmpty(pw)) { - return Forbid("Only sha1 password is not allowed."); + return StatusCode(StatusCodes.Status403Forbidden, "Only sha1 password is not allowed."); } // Password should always be null @@ -271,7 +271,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to update the password."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the password."); } var user = _userManager.GetUserById(userId); @@ -296,7 +296,7 @@ namespace Jellyfin.Api.Controllers if (success == null) { - return Forbid("Invalid user or password entered."); + return StatusCode(StatusCodes.Status403Forbidden, "Invalid user or password entered."); } await _userManager.ChangePassword(user, request.NewPw).ConfigureAwait(false); @@ -329,7 +329,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) { - return Forbid("User is not allowed to update the easy password."); + return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the easy password."); } var user = _userManager.GetUserById(userId); @@ -376,7 +376,7 @@ namespace Jellyfin.Api.Controllers if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false)) { - return Forbid("User update not allowed."); + return StatusCode(StatusCodes.Status403Forbidden, "User update not allowed."); } var user = _userManager.GetUserById(userId); @@ -421,14 +421,14 @@ namespace Jellyfin.Api.Controllers { if (_userManager.Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1) { - return Forbid("There must be at least one user in the system with administrative access."); + return StatusCode(StatusCodes.Status403Forbidden, "There must be at least one user in the system with administrative access."); } } // If disabling if (newPolicy.IsDisabled && user.HasPermission(PermissionKind.IsAdministrator)) { - return Forbid("Administrators cannot be disabled."); + return StatusCode(StatusCodes.Status403Forbidden, "Administrators cannot be disabled."); } // If disabling @@ -436,7 +436,7 @@ namespace Jellyfin.Api.Controllers { if (_userManager.Users.Count(i => !i.HasPermission(PermissionKind.IsDisabled)) == 1) { - return Forbid("There must be at least one enabled user in the system."); + return StatusCode(StatusCodes.Status403Forbidden, "There must be at least one enabled user in the system."); } var currentToken = _authContext.GetAuthorizationInfo(Request).Token; @@ -466,7 +466,7 @@ namespace Jellyfin.Api.Controllers { if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false)) { - return Forbid("User configuration update not allowed"); + return StatusCode(StatusCodes.Status403Forbidden, "User configuration update not allowed"); } await _userManager.UpdateConfigurationAsync(userId, userConfig).ConfigureAwait(false); -- cgit v1.2.3 From 5b4eef741a0afc33a2f835a8feb3b0e600aaf47c Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 15 Dec 2020 09:27:33 +0100 Subject: Convert from base64 when saving item images --- Jellyfin.Api/Controllers/ImageController.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index e828a0801..c606d327c 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -325,9 +325,11 @@ namespace Jellyfin.Api.Controllers return NotFound(); } + await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + // Handle image/png; charset=utf-8 var mimeType = Request.ContentType.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, Request.Body, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); @@ -358,9 +360,11 @@ namespace Jellyfin.Api.Controllers return NotFound(); } + await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + // Handle image/png; charset=utf-8 var mimeType = Request.ContentType.Split(';').FirstOrDefault(); - await _providerManager.SaveImage(item, Request.Body, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); -- cgit v1.2.3 From 620fbf0f89d33ab5d4d66373c7f9fe4580691f22 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 9 Jan 2021 10:51:59 +0100 Subject: Remove CropWhitespace function --- Emby.Drawing/ImageProcessor.cs | 5 -- Jellyfin.Api/Controllers/ImageController.cs | 5 +- Jellyfin.Drawing.Skia/SkiaEncoder.cs | 85 ++-------------------- .../Drawing/ImageProcessingOptions.cs | 3 - 4 files changed, 6 insertions(+), 92 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 8a2301d2d..af6e5b339 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -181,11 +181,6 @@ namespace Emby.Drawing { if (!File.Exists(cacheFilePath)) { - if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath)) - { - options.CropWhiteSpace = false; - } - string resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat); if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase)) diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index c606d327c..cd1296310 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -1681,7 +1681,7 @@ namespace Jellyfin.Api.Controllers int? width, int? height, int? quality, - bool? cropWhitespace, + bool? cropWhitespace, // TODO: Remove bool? addPlayedIndicator, int? blur, string? backgroundColor, @@ -1756,7 +1756,6 @@ namespace Jellyfin.Api.Controllers backgroundColor, foregroundLayer, imageInfo, - cropWhitespace.Value, outputFormats, cacheDuration, responseHeaders, @@ -1855,7 +1854,6 @@ namespace Jellyfin.Api.Controllers string? backgroundColor, string? foregroundLayer, ItemImageInfo imageInfo, - bool cropWhitespace, IReadOnlyCollection supportedFormats, TimeSpan? cacheDuration, IDictionary headers, @@ -1868,7 +1866,6 @@ namespace Jellyfin.Api.Controllers var options = new ImageProcessingOptions { - CropWhiteSpace = cropWhitespace, Height = height, ImageIndex = index ?? 0, Image = imageInfo, diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index eab5777d5..a786c01a6 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -91,9 +91,6 @@ namespace Jellyfin.Drawing.Skia } } - private static bool IsTransparent(SKColor color) - => (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0; - /// /// Convert a to a . /// @@ -111,65 +108,6 @@ namespace Jellyfin.Drawing.Skia }; } - private static bool IsTransparentRow(SKBitmap bmp, int row) - { - for (var i = 0; i < bmp.Width; ++i) - { - if (!IsTransparent(bmp.GetPixel(i, row))) - { - return false; - } - } - - return true; - } - - private static bool IsTransparentColumn(SKBitmap bmp, int col) - { - for (var i = 0; i < bmp.Height; ++i) - { - if (!IsTransparent(bmp.GetPixel(col, i))) - { - return false; - } - } - - return true; - } - - private SKBitmap CropWhiteSpace(SKBitmap bitmap) - { - var topmost = 0; - while (topmost < bitmap.Height && IsTransparentRow(bitmap, topmost)) - { - topmost++; - } - - int bottommost = bitmap.Height; - while (bottommost >= 0 && IsTransparentRow(bitmap, bottommost - 1)) - { - bottommost--; - } - - var leftmost = 0; - while (leftmost < bitmap.Width && IsTransparentColumn(bitmap, leftmost)) - { - leftmost++; - } - - var rightmost = bitmap.Width; - while (rightmost >= 0 && IsTransparentColumn(bitmap, rightmost - 1)) - { - rightmost--; - } - - var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost); - - using var image = SKImage.FromBitmap(bitmap); - using var subset = image.Subset(newRect); - return SKBitmap.FromImage(subset); - } - /// /// The path is null. /// The path is not valid. @@ -312,22 +250,11 @@ namespace Jellyfin.Drawing.Skia return resultBitmap; } - private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin) - { - if (cropWhitespace) - { - using var bitmap = Decode(path, forceAnalyzeBitmap, orientation, out origin); - return bitmap == null ? null : CropWhiteSpace(bitmap); - } - - return Decode(path, forceAnalyzeBitmap, orientation, out origin); - } - - private SKBitmap? GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation) + private SKBitmap? GetBitmap(string path, bool autoOrient, ImageOrientation? orientation) { if (autoOrient) { - var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out var origin); + var bitmap = Decode(path, true, orientation, out var origin); if (bitmap != null && origin != SKEncodedOrigin.TopLeft) { @@ -340,7 +267,7 @@ namespace Jellyfin.Drawing.Skia return bitmap; } - return GetBitmap(path, cropWhitespace, false, orientation, out _); + return Decode(path, false, orientation, out _); } private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin) @@ -466,7 +393,7 @@ namespace Jellyfin.Drawing.Skia var blur = options.Blur ?? 0; var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); - using var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation); + using var bitmap = GetBitmap(inputPath, autoOrient, orientation); if (bitmap == null) { throw new InvalidDataException($"Skia unable to read image {inputPath}"); @@ -474,9 +401,7 @@ namespace Jellyfin.Drawing.Skia var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height); - if (!options.CropWhiteSpace - && options.HasDefaultOptions(inputPath, originalImageSize) - && !autoOrient) + if (options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient) { // Just spit out the original file if all the options are default return inputPath; diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 22105b7d7..22de9a43e 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -24,8 +24,6 @@ namespace MediaBrowser.Controller.Drawing public int ImageIndex { get; set; } - public bool CropWhiteSpace { get; set; } - public int? Width { get; set; } public int? Height { get; set; } @@ -106,7 +104,6 @@ namespace MediaBrowser.Controller.Drawing PercentPlayed.Equals(0) && !UnplayedCount.HasValue && !Blur.HasValue && - !CropWhiteSpace && string.IsNullOrEmpty(BackgroundColor) && string.IsNullOrEmpty(ForegroundLayer); } -- cgit v1.2.3 From d5f0b046bb21dea0c120aa27f68fabc5947a8f1d Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 10 Feb 2021 16:12:52 -0700 Subject: Add image file accept to openapi --- Jellyfin.Api/Attributes/AcceptsFileAttribute.cs | 28 ++++++++++++++ .../Attributes/AcceptsImageFileAttribute.cs | 18 +++++++++ Jellyfin.Api/Controllers/ImageController.cs | 4 ++ .../Extensions/ApiServiceCollectionExtensions.cs | 1 + Jellyfin.Server/Filters/FileRequestFilter.cs | 43 ++++++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 Jellyfin.Api/Attributes/AcceptsFileAttribute.cs create mode 100644 Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs create mode 100644 Jellyfin.Server/Filters/FileRequestFilter.cs (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs new file mode 100644 index 000000000..49b6689cd --- /dev/null +++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Jellyfin.Api.Attributes +{ + /// + /// Internal produces image attribute. + /// + [AttributeUsage(AttributeTargets.Method)] + public class AcceptsFileAttribute : Attribute + { + private readonly string[] _contentTypes; + + /// + /// Initializes a new instance of the class. + /// + /// Content types this endpoint produces. + public AcceptsFileAttribute(params string[] contentTypes) + { + _contentTypes = contentTypes; + } + + /// + /// Gets the configured content types. + /// + /// the configured content types. + public string[] GetContentTypes() => _contentTypes; + } +} diff --git a/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs new file mode 100644 index 000000000..001f27409 --- /dev/null +++ b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// + /// Produces file attribute of "image/*". + /// + public class AcceptsImageFileAttribute : AcceptsFileAttribute + { + private const string ContentType = "image/*"; + + /// + /// Initializes a new instance of the class. + /// + public AcceptsImageFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index c606d327c..dc3634970 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -87,6 +87,7 @@ namespace Jellyfin.Api.Controllers /// A . [HttpPost("Users/{userId}/Images/{imageType}")] [Authorize(Policy = Policies.DefaultAuthorization)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] @@ -133,6 +134,7 @@ namespace Jellyfin.Api.Controllers /// A . [HttpPost("Users/{userId}/Images/{imageType}/{index}")] [Authorize(Policy = Policies.DefaultAuthorization)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] @@ -312,6 +314,7 @@ namespace Jellyfin.Api.Controllers /// A on success, or a if item not found. [HttpPost("Items/{itemId}/Images/{imageType}")] [Authorize(Policy = Policies.RequiresElevation)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] @@ -346,6 +349,7 @@ namespace Jellyfin.Api.Controllers /// A on success, or a if item not found. [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}")] [Authorize(Policy = Policies.RequiresElevation)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index da4cc267b..545937207 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -316,6 +316,7 @@ namespace Jellyfin.Server.Extensions c.OperationFilter(); c.OperationFilter(); + c.OperationFilter(); c.OperationFilter(); c.DocumentFilter(); }); diff --git a/Jellyfin.Server/Filters/FileRequestFilter.cs b/Jellyfin.Server/Filters/FileRequestFilter.cs new file mode 100644 index 000000000..69e10994f --- /dev/null +++ b/Jellyfin.Server/Filters/FileRequestFilter.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Jellyfin.Api.Attributes; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Jellyfin.Server.Filters +{ + /// + public class FileRequestFilter : IOperationFilter + { + /// + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + foreach (var attribute in context.ApiDescription.ActionDescriptor.EndpointMetadata) + { + if (attribute is AcceptsFileAttribute acceptsFileAttribute) + { + operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes()); + break; + } + } + } + + private static OpenApiRequestBody GetRequestBody(IEnumerable contentTypes) + { + var body = new OpenApiRequestBody(); + var mediaType = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "string", + Format = "binary" + } + }; + foreach (var contentType in contentTypes) + { + body.Content.Add(contentType, mediaType); + } + + return body; + } + } +} -- cgit v1.2.3 From 40b9e7592f1990323b7c38ef9b869da9e5e873c9 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 20 Feb 2021 23:34:15 +0100 Subject: Fix build --- Emby.Dlna/ContentDirectory/StubType.cs | 1 - Emby.Dlna/PlayTo/TransportState.cs | 1 - Jellyfin.Api/Controllers/ImageController.cs | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Emby.Dlna/ContentDirectory/StubType.cs b/Emby.Dlna/ContentDirectory/StubType.cs index a5116055d..187dc1d75 100644 --- a/Emby.Dlna/ContentDirectory/StubType.cs +++ b/Emby.Dlna/ContentDirectory/StubType.cs @@ -1,6 +1,5 @@ #pragma warning disable CS1591 - namespace Emby.Dlna.ContentDirectory { /// diff --git a/Emby.Dlna/PlayTo/TransportState.cs b/Emby.Dlna/PlayTo/TransportState.cs index 1ca71283a..2058e9dc7 100644 --- a/Emby.Dlna/PlayTo/TransportState.cs +++ b/Emby.Dlna/PlayTo/TransportState.cs @@ -1,6 +1,5 @@ #pragma warning disable CS1591 - namespace Emby.Dlna.PlayTo { public enum TransportState diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index dc3634970..a50d6e46b 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); await _providerManager .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) @@ -160,7 +160,7 @@ namespace Jellyfin.Api.Controllers await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false); } - user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty))); await _providerManager .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) -- cgit v1.2.3 From 858c91ab485f79648aa625e89378c6de9e19df4b Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 4 Mar 2021 18:25:52 -0700 Subject: Specify defaults or set query parameter to nullable --- Jellyfin.Api/Controllers/AudioController.cs | 8 ++-- Jellyfin.Api/Controllers/DynamicHlsController.cs | 48 +++++++++++----------- Jellyfin.Api/Controllers/HlsSegmentController.cs | 4 +- Jellyfin.Api/Controllers/ImageController.cs | 16 ++++---- Jellyfin.Api/Controllers/ItemUpdateController.cs | 2 +- Jellyfin.Api/Controllers/LibraryController.cs | 2 +- Jellyfin.Api/Controllers/PlaystateController.cs | 20 ++++----- .../Controllers/UniversalAudioController.cs | 2 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 8 ++-- Jellyfin.Api/Controllers/VideosController.cs | 12 +++--- 10 files changed, 62 insertions(+), 60 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 616fe5b91..8b1813b20 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -122,7 +122,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -174,7 +174,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -287,7 +287,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -339,7 +339,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index e375645cf..f6c23c5aa 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -203,7 +203,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -218,7 +218,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, [FromQuery] bool enableAdaptiveBitrateStreaming = true) { @@ -255,7 +255,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -270,7 +270,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming }; @@ -370,7 +370,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -385,7 +385,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, [FromQuery] bool enableAdaptiveBitrateStreaming = true) { @@ -422,7 +422,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -437,7 +437,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming }; @@ -533,7 +533,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -548,7 +548,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { var cancellationTokenSource = new CancellationTokenSource(); @@ -585,7 +585,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -600,7 +600,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions }; @@ -698,7 +698,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -713,7 +713,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { var cancellationTokenSource = new CancellationTokenSource(); @@ -750,7 +750,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -765,7 +765,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions }; @@ -868,7 +868,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -883,7 +883,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { var streamingRequest = new VideoRequestDto @@ -920,7 +920,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -935,7 +935,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions }; @@ -1040,7 +1040,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -1055,7 +1055,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { var streamingRequest = new StreamingRequestDto @@ -1092,7 +1092,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -1107,7 +1107,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions }; diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 25abe73ed..d0ed45acb 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -96,7 +96,9 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Videos/ActiveEncodings")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult StopEncodingProcess([FromQuery] string deviceId, [FromQuery] string playSessionId) + public ActionResult StopEncodingProcess( + [FromQuery, Required] string deviceId, + [FromQuery, Required] string playSessionId) { _transcodingJobHelper.KillTranscodingJobs(deviceId, playSessionId, path => true); return NoContent(); diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index a50d6e46b..cfc038f23 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -392,7 +392,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid itemId, [FromRoute, Required] ImageType imageType, [FromRoute, Required] int imageIndex, - [FromQuery] int newIndex) + [FromQuery, Required] int newIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -741,7 +741,7 @@ namespace Jellyfin.Api.Controllers public async Task GetArtistImage( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -820,7 +820,7 @@ namespace Jellyfin.Api.Controllers public async Task GetGenreImage( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -900,7 +900,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromRoute, Required] int imageIndex, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -978,7 +978,7 @@ namespace Jellyfin.Api.Controllers public async Task GetMusicGenreImage( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -1058,7 +1058,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromRoute, Required] int imageIndex, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -1136,7 +1136,7 @@ namespace Jellyfin.Api.Controllers public async Task GetPersonImage( [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -1216,7 +1216,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] string name, [FromRoute, Required] ImageType imageType, [FromRoute, Required] int imageIndex, - [FromQuery] string tag, + [FromQuery] string? tag, [FromQuery] ImageFormat? format, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 9e1a39853..a9f4a5a58 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -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] string contentType) + public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery] string? contentType) { var item = _libraryManager.GetItemById(itemId); if (item == null) diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index db4aa9668..3443ebd72 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -777,7 +777,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetLibraryOptionsInfo( [FromQuery] string? libraryContentType, - [FromQuery] bool isNewLibrary) + [FromQuery] bool isNewLibrary = false) { var result = new LibraryOptionsResultDto(); diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index ec7b84ff6..f256c8c25 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -152,7 +152,7 @@ namespace Jellyfin.Api.Controllers /// A . [HttpPost("Sessions/Playing/Ping")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult PingPlaybackSession([FromQuery] string playSessionId) + public ActionResult PingPlaybackSession([FromQuery, Required] string playSessionId) { _transcodingJobHelper.PingTranscodingJob(playSessionId, null); return NoContent(); @@ -202,9 +202,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? mediaSourceId, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, - [FromQuery] PlayMethod playMethod, + [FromQuery] PlayMethod? playMethod, [FromQuery] string? liveStreamId, - [FromQuery] string playSessionId, + [FromQuery] string? playSessionId, [FromQuery] bool canSeek = false) { var playbackStartInfo = new PlaybackStartInfo @@ -214,7 +214,7 @@ namespace Jellyfin.Api.Controllers MediaSourceId = mediaSourceId, AudioStreamIndex = audioStreamIndex, SubtitleStreamIndex = subtitleStreamIndex, - PlayMethod = playMethod, + PlayMethod = playMethod ?? PlayMethod.Transcode, PlaySessionId = playSessionId, LiveStreamId = liveStreamId }; @@ -254,10 +254,10 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, [FromQuery] int? volumeLevel, - [FromQuery] PlayMethod playMethod, + [FromQuery] PlayMethod? playMethod, [FromQuery] string? liveStreamId, - [FromQuery] string playSessionId, - [FromQuery] RepeatMode repeatMode, + [FromQuery] string? playSessionId, + [FromQuery] RepeatMode? repeatMode, [FromQuery] bool isPaused = false, [FromQuery] bool isMuted = false) { @@ -271,10 +271,10 @@ namespace Jellyfin.Api.Controllers AudioStreamIndex = audioStreamIndex, SubtitleStreamIndex = subtitleStreamIndex, VolumeLevel = volumeLevel, - PlayMethod = playMethod, + PlayMethod = playMethod ?? PlayMethod.Transcode, PlaySessionId = playSessionId, LiveStreamId = liveStreamId, - RepeatMode = repeatMode + RepeatMode = repeatMode ?? RepeatMode.RepeatNone }; playbackProgressInfo.PlayMethod = ValidatePlayMethod(playbackProgressInfo.PlayMethod, playbackProgressInfo.PlaySessionId); @@ -352,7 +352,7 @@ namespace Jellyfin.Api.Controllers return _userDataRepository.GetUserDataDto(item, user); } - private PlayMethod ValidatePlayMethod(PlayMethod method, string playSessionId) + private PlayMethod ValidatePlayMethod(PlayMethod method, string? playSessionId) { if (method == PlayMethod.Transcode) { diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 5aa033ccf..0c2e6f19f 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -112,7 +112,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? maxAudioSampleRate, [FromQuery] int? maxAudioBitDepth, [FromQuery] bool? enableRemoteMedia, - [FromQuery] bool breakOnNonKeyFrames, + [FromQuery] bool breakOnNonKeyFrames = false, [FromQuery] bool enableRedirection = true) { var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels); diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index ba51aa43e..620eef568 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -198,7 +198,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -213,7 +213,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions, [FromQuery] int? maxWidth, [FromQuery] int? maxHeight, @@ -253,7 +253,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -268,7 +268,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions, MaxHeight = maxHeight, MaxWidth = maxWidth, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 44dc63952..8c7aa7325 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -364,7 +364,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -379,7 +379,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { var isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head; @@ -418,7 +418,7 @@ namespace Jellyfin.Api.Controllers Height = height, VideoBitRate = videoBitRate, SubtitleStreamIndex = subtitleStreamIndex, - SubtitleMethod = subtitleMethod, + SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode, MaxRefFrames = maxRefFrames, MaxVideoBitDepth = maxVideoBitDepth, RequireAvc = requireAvc ?? true, @@ -433,7 +433,7 @@ namespace Jellyfin.Api.Controllers TranscodeReasons = transcodeReasons, AudioStreamIndex = audioStreamIndex, VideoStreamIndex = videoStreamIndex, - Context = context, + Context = context ?? EncodingContext.Streaming, StreamOptions = streamOptions }; @@ -620,7 +620,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? height, [FromQuery] int? videoBitRate, [FromQuery] int? subtitleStreamIndex, - [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] SubtitleDeliveryMethod? subtitleMethod, [FromQuery] int? maxRefFrames, [FromQuery] int? maxVideoBitDepth, [FromQuery] bool? requireAvc, @@ -635,7 +635,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? transcodeReasons, [FromQuery] int? audioStreamIndex, [FromQuery] int? videoStreamIndex, - [FromQuery] EncodingContext context, + [FromQuery] EncodingContext? context, [FromQuery] Dictionary streamOptions) { return GetVideoStream( -- cgit v1.2.3 From f638ee6b0918c2ef05ec11cfa43584d3efad68d1 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 6 Mar 2021 17:43:01 -0500 Subject: Enable nullable for Jellyfin.Data and remove unnecessary attributes --- Emby.Drawing/ImageProcessor.cs | 7 ++++++- Jellyfin.Api/Controllers/ImageController.cs | 12 +++++++++++- Jellyfin.Api/Controllers/StartupController.cs | 5 ++++- Jellyfin.Data/Entities/AccessSchedule.cs | 7 ------- Jellyfin.Data/Entities/ActivityLog.cs | 8 +++----- Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs | 3 --- Jellyfin.Data/Entities/DisplayPreferences.cs | 7 ++----- Jellyfin.Data/Entities/Group.cs | 1 - Jellyfin.Data/Entities/HomeSection.cs | 1 - Jellyfin.Data/Entities/ImageInfo.cs | 1 - Jellyfin.Data/Entities/ItemDisplayPreferences.cs | 2 -- Jellyfin.Data/Entities/Libraries/Artwork.cs | 1 - Jellyfin.Data/Entities/Libraries/BookMetadata.cs | 2 -- Jellyfin.Data/Entities/Libraries/Chapter.cs | 3 +-- Jellyfin.Data/Entities/Libraries/Collection.cs | 2 +- Jellyfin.Data/Entities/Libraries/CollectionItem.cs | 13 +++++++++++-- Jellyfin.Data/Entities/Libraries/Company.cs | 2 +- Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs | 2 -- Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs | 6 +++--- Jellyfin.Data/Entities/Libraries/Genre.cs | 1 - Jellyfin.Data/Entities/Libraries/ItemMetadata.cs | 6 ++---- Jellyfin.Data/Entities/Libraries/Library.cs | 12 +++--------- Jellyfin.Data/Entities/Libraries/LibraryItem.cs | 1 - Jellyfin.Data/Entities/Libraries/MediaFile.cs | 1 - Jellyfin.Data/Entities/Libraries/MetadataProvider.cs | 1 - Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs | 5 +++-- Jellyfin.Data/Entities/Libraries/MovieMetadata.cs | 10 ++++------ Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs | 6 +++--- Jellyfin.Data/Entities/Libraries/Person.cs | 3 +-- Jellyfin.Data/Entities/Libraries/PersonRole.cs | 8 +++++--- Jellyfin.Data/Entities/Libraries/Rating.cs | 2 +- Jellyfin.Data/Entities/Libraries/RatingSource.cs | 4 ++-- Jellyfin.Data/Entities/Libraries/Release.cs | 1 - Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs | 2 +- Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs | 9 ++++----- Jellyfin.Data/Entities/Preference.cs | 1 - Jellyfin.Data/Entities/User.cs | 17 +++++++---------- Jellyfin.Data/Jellyfin.Data.csproj | 1 + .../Events/Consumers/Session/PlaybackStartLogger.cs | 4 ++-- Jellyfin.Server.Implementations/Users/UserManager.cs | 6 +++--- Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 4 +--- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 +- tests/Jellyfin.Api.Tests/TestHelpers.cs | 4 ++-- 44 files changed, 93 insertions(+), 111 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 8a2301d2d..aa8a3d212 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -352,8 +352,13 @@ namespace Emby.Drawing } /// - public string GetImageCacheTag(User user) + public string? GetImageCacheTag(User user) { + if (user.ProfileImage == null) + { + return null; + } + return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5() .ToString("N", CultureInfo.InvariantCulture); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index a50d6e46b..b016f2450 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -196,6 +196,11 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); + if (user?.ProfileImage == null) + { + return NoContent(); + } + try { System.IO.File.Delete(user.ProfileImage.Path); @@ -235,6 +240,11 @@ namespace Jellyfin.Api.Controllers } var user = _userManager.GetUserById(userId); + if (user?.ProfileImage == null) + { + return NoContent(); + } + try { System.IO.File.Delete(user.ProfileImage.Path); @@ -1469,7 +1479,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? imageIndex) { var user = _userManager.GetUserById(userId); - if (user == null) + if (user?.ProfileImage == null) { return NotFound(); } diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index d9cb34557..a01a617fc 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -132,7 +132,10 @@ namespace Jellyfin.Api.Controllers { var user = _userManager.Users.First(); - user.Username = startupUserDto.Name; + if (startupUserDto.Name != null) + { + user.Username = startupUserDto.Name; + } await _userManager.UpdateUserAsync(user).ConfigureAwait(false); diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs index 72bca061d..9ac0666ac 100644 --- a/Jellyfin.Data/Entities/AccessSchedule.cs +++ b/Jellyfin.Data/Entities/AccessSchedule.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Xml.Serialization; using Jellyfin.Data.Enums; @@ -33,8 +32,6 @@ namespace Jellyfin.Data.Entities /// Identity, Indexed, Required. /// [XmlIgnore] - [Key] - [Required] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; protected set; } @@ -42,28 +39,24 @@ namespace Jellyfin.Data.Entities /// Gets or sets the id of the associated user. /// [XmlIgnore] - [Required] public Guid UserId { get; protected set; } /// /// Gets or sets the day of week. /// /// The day of week. - [Required] public DynamicDayOfWeek DayOfWeek { get; set; } /// /// Gets or sets the start hour. /// /// The start hour. - [Required] public double StartHour { get; set; } /// /// Gets or sets the end hour. /// /// The end hour. - [Required] public double EndHour { get; set; } /// diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs index 80e32db30..e4534e8b5 100644 --- a/Jellyfin.Data/Entities/ActivityLog.cs +++ b/Jellyfin.Data/Entities/ActivityLog.cs @@ -50,7 +50,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 512. /// - [Required] [MaxLength(512)] [StringLength(512)] public string Name { get; set; } @@ -63,7 +62,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(512)] [StringLength(512)] - public string Overview { get; set; } + public string? Overview { get; set; } /// /// Gets or sets the short overview. @@ -73,7 +72,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(512)] [StringLength(512)] - public string ShortOverview { get; set; } + public string? ShortOverview { get; set; } /// /// Gets or sets the type. @@ -81,7 +80,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 256. /// - [Required] [MaxLength(256)] [StringLength(256)] public string Type { get; set; } @@ -102,7 +100,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(256)] [StringLength(256)] - public string ItemId { get; set; } + public string? ItemId { get; set; } /// /// Gets or sets the date created. This should be in UTC. diff --git a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs b/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs index d407180d4..cc46248c7 100644 --- a/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs +++ b/Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs @@ -57,7 +57,6 @@ namespace Jellyfin.Data.Entities /// /// Required. Max Length = 32. /// - [Required] [MaxLength(32)] [StringLength(32)] public string Client { get; set; } @@ -68,7 +67,6 @@ namespace Jellyfin.Data.Entities /// /// Required. /// - [Required] public string Key { get; set; } /// @@ -77,7 +75,6 @@ namespace Jellyfin.Data.Entities /// /// Required. /// - [Required] public string Value { get; set; } } } diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs index d186deb29..64cd6812a 100644 --- a/Jellyfin.Data/Entities/DisplayPreferences.cs +++ b/Jellyfin.Data/Entities/DisplayPreferences.cs @@ -30,8 +30,6 @@ namespace Jellyfin.Data.Entities SkipBackwardLength = 10000; ScrollDirection = ScrollDirection.Horizontal; ChromecastVersion = ChromecastVersion.Stable; - DashboardTheme = string.Empty; - TvHome = string.Empty; HomeSections = new HashSet(); } @@ -67,7 +65,6 @@ namespace Jellyfin.Data.Entities /// /// Required. Max Length = 32. /// - [Required] [MaxLength(32)] [StringLength(32)] public string Client { get; set; } @@ -138,14 +135,14 @@ namespace Jellyfin.Data.Entities /// [MaxLength(32)] [StringLength(32)] - public string DashboardTheme { get; set; } + public string? DashboardTheme { get; set; } /// /// Gets or sets the tv home screen. /// [MaxLength(32)] [StringLength(32)] - public string TvHome { get; set; } + public string? TvHome { get; set; } /// /// Gets or sets the home sections. diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs index 8c45dde92..b14e22b7b 100644 --- a/Jellyfin.Data/Entities/Group.cs +++ b/Jellyfin.Data/Entities/Group.cs @@ -46,7 +46,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string Name { get; set; } diff --git a/Jellyfin.Data/Entities/HomeSection.cs b/Jellyfin.Data/Entities/HomeSection.cs index 062046260..5adc52491 100644 --- a/Jellyfin.Data/Entities/HomeSection.cs +++ b/Jellyfin.Data/Entities/HomeSection.cs @@ -15,7 +15,6 @@ namespace Jellyfin.Data.Entities /// /// Identity. Required. /// - [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; protected set; } diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs index f9ae1a955..e0c37047d 100644 --- a/Jellyfin.Data/Entities/ImageInfo.cs +++ b/Jellyfin.Data/Entities/ImageInfo.cs @@ -39,7 +39,6 @@ namespace Jellyfin.Data.Entities /// /// Required. /// - [Required] [MaxLength(512)] [StringLength(512)] public string Path { get; set; } diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs index f0a04f8ea..4bfeb2fa3 100644 --- a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs +++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs @@ -59,7 +59,6 @@ namespace Jellyfin.Data.Entities /// /// Required. Max Length = 32. /// - [Required] [MaxLength(32)] [StringLength(32)] public string Client { get; set; } @@ -99,7 +98,6 @@ namespace Jellyfin.Data.Entities /// /// Required. /// - [Required] [MaxLength(64)] [StringLength(64)] public string SortBy { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs index df28ce737..84a524de2 100644 --- a/Jellyfin.Data/Entities/Libraries/Artwork.cs +++ b/Jellyfin.Data/Entities/Libraries/Artwork.cs @@ -44,7 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 65535. /// - [Required] [MaxLength(65535)] [StringLength(65535)] public string Path { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs index 8b0c96530..1ff4327b0 100644 --- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs @@ -1,7 +1,6 @@ #pragma warning disable CA2227 using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries @@ -32,7 +31,6 @@ namespace Jellyfin.Data.Entities.Libraries public virtual ICollection Publishers { get; protected set; } /// - [NotMapped] public ICollection Companies => Publishers; } } diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs index f253143d7..11f53ae20 100644 --- a/Jellyfin.Data/Entities/Libraries/Chapter.cs +++ b/Jellyfin.Data/Entities/Libraries/Chapter.cs @@ -45,7 +45,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the language. @@ -54,7 +54,6 @@ namespace Jellyfin.Data.Entities.Libraries /// Required, Min length = 3, Max length = 3 /// ISO-639-3 3-character language codes. /// - [Required] [MinLength(3)] [MaxLength(3)] [StringLength(3)] diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs index 39eded752..d230eeb2f 100644 --- a/Jellyfin.Data/Entities/Libraries/Collection.cs +++ b/Jellyfin.Data/Entities/Libraries/Collection.cs @@ -37,7 +37,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Name { get; set; } + public string? Name { get; set; } /// [ConcurrencyCheck] diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs index 1157de442..e19362bdf 100644 --- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs +++ b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs @@ -9,6 +9,15 @@ namespace Jellyfin.Data.Entities.Libraries /// public class CollectionItem : IHasConcurrencyToken { + /// + /// Initializes a new instance of the class. + /// + /// The library item. + public CollectionItem(LibraryItem libraryItem) + { + LibraryItem = libraryItem; + } + /// /// Gets or sets the id. /// @@ -36,7 +45,7 @@ namespace Jellyfin.Data.Entities.Libraries /// /// TODO check if this properly updated Dependant and has the proper principal relationship. /// - public virtual CollectionItem Next { get; set; } + public virtual CollectionItem? Next { get; set; } /// /// Gets or sets the previous item in the collection. @@ -44,7 +53,7 @@ namespace Jellyfin.Data.Entities.Libraries /// /// TODO check if this properly updated Dependant and has the proper principal relationship. /// - public virtual CollectionItem Previous { get; set; } + public virtual CollectionItem? Previous { get; set; } /// public void OnSavingChanges() diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs index 499ba3800..09050bb52 100644 --- a/Jellyfin.Data/Entities/Libraries/Company.cs +++ b/Jellyfin.Data/Entities/Libraries/Company.cs @@ -18,6 +18,7 @@ namespace Jellyfin.Data.Entities.Libraries public Company() { CompanyMetadata = new HashSet(); + ChildCompanies = new HashSet(); } /// @@ -44,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries public virtual ICollection ChildCompanies { get; protected set; } /// - [NotMapped] public ICollection Companies => ChildCompanies; /// diff --git a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs index 86642b38a..a29f08c7f 100644 --- a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(65535)] [StringLength(65535)] - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets or sets the headquarters. @@ -34,7 +34,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(255)] [StringLength(255)] - public string Headquarters { get; set; } + public string? Headquarters { get; set; } /// /// Gets or sets the country code. @@ -44,7 +44,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(2)] [StringLength(2)] - public string Country { get; set; } + public string? Country { get; set; } /// /// Gets or sets the homepage. @@ -54,6 +54,6 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Homepage { get; set; } + public string? Homepage { get; set; } } } diff --git a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs index a69a8eafa..af2393870 100644 --- a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs @@ -1,5 +1,3 @@ -using System; - namespace Jellyfin.Data.Entities.Libraries { /// diff --git a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs index 5662decdb..b0ef11e0f 100644 --- a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Outline { get; set; } + public string? Outline { get; set; } /// /// Gets or sets the plot. @@ -34,7 +34,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(65535)] [StringLength(65535)] - public string Plot { get; set; } + public string? Plot { get; set; } /// /// Gets or sets the tagline. @@ -44,6 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline { get; set; } + public string? Tagline { get; set; } } } diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs index befa75550..9f3d65028 100644 --- a/Jellyfin.Data/Entities/Libraries/Genre.cs +++ b/Jellyfin.Data/Entities/Libraries/Genre.cs @@ -33,7 +33,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Indexed, Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string Name { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs index a0efa66e4..d12e011a8 100644 --- a/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/ItemMetadata.cs @@ -57,7 +57,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 1024. /// - [Required] [MaxLength(1024)] [StringLength(1024)] public string Title { get; set; } @@ -70,7 +69,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string OriginalTitle { get; set; } + public string? OriginalTitle { get; set; } /// /// Gets or sets the sort title. @@ -80,7 +79,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string SortTitle { get; set; } + public string? SortTitle { get; set; } /// /// Gets or sets the language. @@ -89,7 +88,6 @@ namespace Jellyfin.Data.Entities.Libraries /// Required, Min length = 3, Max length = 3. /// ISO-639-3 3-character language codes. /// - [Required] [MinLength(3)] [MaxLength(3)] [StringLength(3)] diff --git a/Jellyfin.Data/Entities/Libraries/Library.cs b/Jellyfin.Data/Entities/Libraries/Library.cs index 3ec4341a4..e45384902 100644 --- a/Jellyfin.Data/Entities/Libraries/Library.cs +++ b/Jellyfin.Data/Entities/Libraries/Library.cs @@ -1,4 +1,3 @@ -using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Data.Interfaces; @@ -14,14 +13,11 @@ namespace Jellyfin.Data.Entities.Libraries /// Initializes a new instance of the class. /// /// The name of the library. - public Library(string name) + /// The path of the library. + public Library(string name, string path) { - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentNullException(nameof(name)); - } - Name = name; + Path = path; } /// @@ -39,7 +35,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 128. /// - [Required] [MaxLength(128)] [StringLength(128)] public string Name { get; set; } @@ -50,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required. /// - [Required] public string Path { get; set; } /// diff --git a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs index 504b9c853..67ffad944 100644 --- a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs +++ b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs @@ -44,7 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required. /// - [Required] public virtual Library Library { get; set; } /// diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs index 7f64978e2..f3e2fe653 100644 --- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs +++ b/Jellyfin.Data/Entities/Libraries/MediaFile.cs @@ -47,7 +47,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 65535. /// - [Required] [MaxLength(65535)] [StringLength(65535)] public string Path { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs index 20de5bf4b..fb2587882 100644 --- a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs @@ -39,7 +39,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 1024. /// - [Required] [MaxLength(1024)] [StringLength(1024)] public string Name { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs index 12672dd25..2a9c904c8 100644 --- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs @@ -14,7 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries /// Initializes a new instance of the class. /// /// The provider id. - public MetadataProviderId(string providerId) + /// The metadata provider. + public MetadataProviderId(string providerId, MetadataProvider metadataProvider) { if (string.IsNullOrEmpty(providerId)) { @@ -22,6 +23,7 @@ namespace Jellyfin.Data.Entities.Libraries } ProviderId = providerId; + MetadataProvider = metadataProvider; } /// @@ -39,7 +41,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string ProviderId { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs index 8cf7ca6a7..fb181dea6 100644 --- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries @@ -30,7 +29,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Outline { get; set; } + public string? Outline { get; set; } /// /// Gets or sets the tagline. @@ -40,7 +39,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline { get; set; } + public string? Tagline { get; set; } /// /// Gets or sets the plot. @@ -50,7 +49,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(65535)] [StringLength(65535)] - public string Plot { get; set; } + public string? Plot { get; set; } /// /// Gets or sets the country code. @@ -60,7 +59,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(2)] [StringLength(2)] - public string Country { get; set; } + public string? Country { get; set; } /// /// Gets or sets the studios that produced this movie. @@ -68,7 +67,6 @@ namespace Jellyfin.Data.Entities.Libraries public virtual ICollection Studios { get; protected set; } /// - [NotMapped] public ICollection Companies => Studios; } } diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs index 9e44e550a..3080bd692 100644 --- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(255)] [StringLength(255)] - public string Barcode { get; set; } + public string? Barcode { get; set; } /// /// Gets or sets the label number. @@ -38,7 +38,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(255)] [StringLength(255)] - public string LabelNumber { get; set; } + public string? LabelNumber { get; set; } /// /// Gets or sets the country code. @@ -48,7 +48,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(2)] [StringLength(2)] - public string Country { get; set; } + public string? Country { get; set; } /// /// Gets or sets a collection containing the labels. diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs index cc4b9e0f9..159bd47be 100644 --- a/Jellyfin.Data/Entities/Libraries/Person.cs +++ b/Jellyfin.Data/Entities/Libraries/Person.cs @@ -46,7 +46,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 1024. /// - [Required] [MaxLength(1024)] [StringLength(1024)] public string Name { get; set; } @@ -59,7 +58,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(256)] [StringLength(256)] - public string SourceId { get; set; } + public string? SourceId { get; set; } /// /// Gets or sets the date added. diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs index 3ae2e4a68..988aa84ba 100644 --- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs +++ b/Jellyfin.Data/Entities/Libraries/PersonRole.cs @@ -17,9 +17,12 @@ namespace Jellyfin.Data.Entities.Libraries /// Initializes a new instance of the class. /// /// The role type. - public PersonRole(PersonRoleType type) + /// The person. + public PersonRole(PersonRoleType type, Person person) { Type = type; + Person = person; + Artwork = new HashSet(); Sources = new HashSet(); } @@ -40,7 +43,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Role { get; set; } + public string? Role { get; set; } /// /// Gets or sets the person's role type. @@ -60,7 +63,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required. /// - [Required] public virtual Person Person { get; set; } /// diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs index 0ea933fd7..6862012a8 100644 --- a/Jellyfin.Data/Entities/Libraries/Rating.cs +++ b/Jellyfin.Data/Entities/Libraries/Rating.cs @@ -48,7 +48,7 @@ namespace Jellyfin.Data.Entities.Libraries /// Gets or sets the rating type. /// If this is null it's the internal user rating. /// - public virtual RatingSource RatingType { get; set; } + public virtual RatingSource? RatingType { get; set; } /// public void OnSavingChanges() diff --git a/Jellyfin.Data/Entities/Libraries/RatingSource.cs b/Jellyfin.Data/Entities/Libraries/RatingSource.cs index 7e1a5a8f4..ae0d806ff 100644 --- a/Jellyfin.Data/Entities/Libraries/RatingSource.cs +++ b/Jellyfin.Data/Entities/Libraries/RatingSource.cs @@ -37,7 +37,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the minimum value. @@ -62,7 +62,7 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Gets or sets the metadata source. /// - public virtual MetadataProviderId Source { get; set; } + public virtual MetadataProviderId? Source { get; set; } /// public void OnSavingChanges() diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs index 1871e0f10..21d403979 100644 --- a/Jellyfin.Data/Entities/Libraries/Release.cs +++ b/Jellyfin.Data/Entities/Libraries/Release.cs @@ -45,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries /// /// Required, Max length = 1024. /// - [Required] [MaxLength(1024)] [StringLength(1024)] public string Name { get; set; } diff --git a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs index 61714f909..da40a075f 100644 --- a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs @@ -24,6 +24,6 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Outline { get; set; } + public string? Outline { get; set; } } } diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs index e1acd2d45..730deccae 100644 --- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs @@ -30,7 +30,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Outline { get; set; } + public string? Outline { get; set; } /// /// Gets or sets the plot. @@ -40,7 +40,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(65535)] [StringLength(65535)] - public string Plot { get; set; } + public string? Plot { get; set; } /// /// Gets or sets the tagline. @@ -50,7 +50,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline { get; set; } + public string? Tagline { get; set; } /// /// Gets or sets the country code. @@ -60,7 +60,7 @@ namespace Jellyfin.Data.Entities.Libraries /// [MaxLength(2)] [StringLength(2)] - public string Country { get; set; } + public string? Country { get; set; } /// /// Gets or sets a collection containing the networks. @@ -68,7 +68,6 @@ namespace Jellyfin.Data.Entities.Libraries public virtual ICollection Networks { get; protected set; } /// - [NotMapped] public ICollection Companies => Networks; } } diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs index 40f2f8ede..a8813ab88 100644 --- a/Jellyfin.Data/Entities/Preference.cs +++ b/Jellyfin.Data/Entities/Preference.cs @@ -46,7 +46,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 65535. /// - [Required] [MaxLength(65535)] [StringLength(65535)] public string Value { get; set; } diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 28e12adde..9aa809164 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -51,6 +51,7 @@ namespace Jellyfin.Data.Entities PasswordResetProviderId = passwordResetProviderId; AccessSchedules = new HashSet(); + DisplayPreferences = new HashSet(); ItemDisplayPreferences = new HashSet(); // Groups = new HashSet(); Permissions = new HashSet(); @@ -92,7 +93,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string Username { get; set; } @@ -105,7 +105,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(65535)] [StringLength(65535)] - public string Password { get; set; } + public string? Password { get; set; } /// /// Gets or sets the user's easy password, or null if none is set. @@ -115,7 +115,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(65535)] [StringLength(65535)] - public string EasyPassword { get; set; } + public string? EasyPassword { get; set; } /// /// Gets or sets a value indicating whether the user must update their password. @@ -133,7 +133,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(255)] [StringLength(255)] - public string AudioLanguagePreference { get; set; } + public string? AudioLanguagePreference { get; set; } /// /// Gets or sets the authentication provider id. @@ -141,7 +141,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string AuthenticationProviderId { get; set; } @@ -152,7 +151,6 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string PasswordResetProviderId { get; set; } @@ -209,7 +207,7 @@ namespace Jellyfin.Data.Entities /// [MaxLength(255)] [StringLength(255)] - public string SubtitleLanguagePreference { get; set; } + public string? SubtitleLanguagePreference { get; set; } /// /// Gets or sets a value indicating whether missing episodes should be displayed. @@ -304,7 +302,7 @@ namespace Jellyfin.Data.Entities /// Gets or sets the user's profile image. Can be null. /// // [ForeignKey("UserId")] - public virtual ImageInfo ProfileImage { get; set; } + public virtual ImageInfo? ProfileImage { get; set; } /// /// Gets or sets the user's display preferences. @@ -312,8 +310,7 @@ namespace Jellyfin.Data.Entities /// /// Required. /// - [Required] - public virtual DisplayPreferences DisplayPreferences { get; set; } + public virtual ICollection DisplayPreferences { get; set; } /// /// Gets or sets the level of sync play permissions this user has. diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index a8ac45645..a2b6f074e 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -5,6 +5,7 @@ false true true + enable true true true diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs index 0340248bb..aa6015caa 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -86,7 +86,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session return name; } - private static string? GetPlaybackNotificationType(string mediaType) + private static string GetPlaybackNotificationType(string mediaType) { if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) { @@ -98,7 +98,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session return NotificationType.VideoPlayback.ToString(); } - return null; + return "Playback"; } } } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 76d1389ca..b400a0dd1 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -184,8 +184,8 @@ namespace Jellyfin.Server.Implementations.Users var user = new User( name, - _defaultAuthenticationProvider.GetType().FullName, - _defaultPasswordResetProvider.GetType().FullName) + _defaultAuthenticationProvider.GetType().FullName!, + _defaultPasswordResetProvider.GetType().FullName!) { InternalId = max + 1 }; @@ -444,7 +444,7 @@ namespace Jellyfin.Server.Implementations.Users { var providerId = authenticationProvider.GetType().FullName; - if (!string.Equals(providerId, user.AuthenticationProviderId, StringComparison.OrdinalIgnoreCase)) + if (providerId != null && !string.Equals(providerId, user.AuthenticationProviderId, StringComparison.OrdinalIgnoreCase)) { user.AuthenticationProviderId = providerId; await UpdateUserAsync(user).ConfigureAwait(false); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 33f039c39..6d318d232 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -1,7 +1,5 @@ using System; -using System.Globalization; using System.IO; -using System.Linq; using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Serialization; using Jellyfin.Data.Entities; @@ -104,7 +102,7 @@ namespace Jellyfin.Server.Migrations.Routines _ => policy.LoginAttemptsBeforeLockout }; - var user = new User(mockup.Name, policy.AuthenticationProviderId, policy.PasswordResetProviderId) + var user = new User(mockup.Name, policy.AuthenticationProviderId!, policy.PasswordResetProviderId!) { Id = entry[1].ReadGuidFromBlob(), InternalId = entry[0].ToInt64(), diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 935a79031..142cebd0c 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Controller.Drawing string GetImageCacheTag(BaseItem item, ChapterInfo info); - string GetImageCacheTag(User user); + string? GetImageCacheTag(User user); /// /// Processes the image. diff --git a/tests/Jellyfin.Api.Tests/TestHelpers.cs b/tests/Jellyfin.Api.Tests/TestHelpers.cs index f27cdf7b6..c1549561d 100644 --- a/tests/Jellyfin.Api.Tests/TestHelpers.cs +++ b/tests/Jellyfin.Api.Tests/TestHelpers.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Api.Tests { var user = new User( "jellyfin", - typeof(DefaultAuthenticationProvider).FullName, - typeof(DefaultPasswordResetProvider).FullName); + typeof(DefaultAuthenticationProvider).FullName!, + typeof(DefaultPasswordResetProvider).FullName!); // Set administrator flag. user.SetPermission(PermissionKind.IsAdministrator, role.Equals(UserRoles.Administrator, StringComparison.OrdinalIgnoreCase)); -- cgit v1.2.3 From 383aa4e4d9cf4b0997b9277df838728102e0db3c Mon Sep 17 00:00:00 2001 From: Odd Stråbø Date: Wed, 17 Mar 2021 00:15:09 +0100 Subject: Add Resize to fill box alternative to image endpoints --- Jellyfin.Api/Controllers/ImageController.cs | 124 ++++++++++++++++++--- MediaBrowser.Controller/Drawing/ImageHelper.cs | 2 +- .../Drawing/ImageProcessingOptions.cs | 4 + MediaBrowser.Model/Drawing/DrawingUtils.cs | 48 ++++++++ 4 files changed, 161 insertions(+), 17 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 2119e8e2c..1da567793 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -490,6 +490,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. @@ -528,7 +530,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -549,6 +553,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -570,6 +576,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. The of the returned image. @@ -607,7 +615,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? unplayedCount, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -628,6 +638,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -648,6 +660,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Supply the cache tag from the item object to receive strong caching headers. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Determines the output format of the image - original,gif,jpg,png. @@ -686,7 +700,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int imageIndex) + [FromRoute, Required] int imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -707,6 +723,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -731,6 +749,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -765,7 +785,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int imageIndex) + [FromRoute, Required] int imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetArtist(name); if (item == null) @@ -786,6 +808,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -810,6 +834,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -844,7 +870,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -865,6 +893,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -890,6 +920,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -923,7 +955,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -944,6 +978,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -968,6 +1004,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1002,7 +1040,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -1023,6 +1063,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1048,6 +1090,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1081,7 +1125,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -1102,6 +1148,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1126,6 +1174,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1160,7 +1210,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -1181,6 +1233,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1206,6 +1260,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1239,7 +1295,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -1260,6 +1318,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1284,6 +1344,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1318,7 +1380,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -1339,6 +1403,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1364,6 +1430,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1397,7 +1465,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -1418,6 +1488,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1442,6 +1514,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1476,7 +1550,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex) + [FromQuery] int? imageIndex, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var user = _userManager.GetUserById(userId); if (user?.ProfileImage == null) @@ -1514,6 +1590,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1540,6 +1618,8 @@ namespace Jellyfin.Api.Controllers /// The fixed image width to return. /// The fixed image height to return. /// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases. + /// Width of box to fill. + /// Height of box to fill. /// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art. /// Optional. Add a played indicator. /// Optional. Blur image. @@ -1573,7 +1653,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer) + [FromQuery] string? foregroundLayer, + [FromQuery] int? fillHeight, + [FromQuery] int? fillWidth) { var user = _userManager.GetUserById(userId); if (user?.ProfileImage == null) @@ -1611,6 +1693,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, + fillHeight, + fillWidth, cropWhitespace, addPlayedIndicator, blur, @@ -1695,6 +1779,8 @@ namespace Jellyfin.Api.Controllers int? width, int? height, int? quality, + int? fillHeight, + int? fillWidth, bool? cropWhitespace, // TODO: Remove bool? addPlayedIndicator, int? blur, @@ -1773,7 +1859,9 @@ namespace Jellyfin.Api.Controllers outputFormats, cacheDuration, responseHeaders, - isHeadRequest).ConfigureAwait(false); + isHeadRequest, + fillHeight, + fillWidth).ConfigureAwait(false); } private ImageFormat[] GetOutputFormats(ImageFormat? format) @@ -1871,7 +1959,9 @@ namespace Jellyfin.Api.Controllers IReadOnlyCollection supportedFormats, TimeSpan? cacheDuration, IDictionary headers, - bool isHeadRequest) + bool isHeadRequest, + int? fillHeight, + int? fillWidth) { if (!imageInfo.IsLocalFile && item != null) { @@ -1887,6 +1977,8 @@ namespace Jellyfin.Api.Controllers ItemId = itemId, MaxHeight = maxHeight, MaxWidth = maxWidth, + FillHeight = fillHeight, + FillWidth = fillWidth, Quality = quality ?? 100, Width = width, AddPlayedIndicator = addPlayedIndicator ?? false, diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index 87c28d577..740726119 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Drawing { // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0); - + newSize = DrawingUtils.ResizeFill(newSize, options.FillWidth, options.FillHeight); return newSize; } diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 22de9a43e..4befb29c4 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -32,6 +32,10 @@ namespace MediaBrowser.Controller.Drawing public int? MaxHeight { get; set; } + public int? FillWidth { get; set; } + + public int? FillHeight { get; set; } + public int Quality { get; set; } public IReadOnlyCollection SupportedOutputFormats { get; set; } diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs index 1512c5233..8fb9bdc0a 100644 --- a/MediaBrowser.Model/Drawing/DrawingUtils.cs +++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs @@ -57,6 +57,54 @@ namespace MediaBrowser.Model.Drawing return new ImageDimensions(newWidth, newHeight); } + /// + /// Resizes to fill box. + /// Returns original size if both width and height are null or zero. + /// + /// The original size object. + /// A new fixed width, if desired. + /// A new fixed height, if desired. + /// A new size object or size. + public static ImageDimensions ResizeFill( + ImageDimensions size, + int? fillWidth, + int? fillHeight) + { + // Return original size if input is invalid. + if ( + (fillWidth == null && fillHeight == null) + || (fillWidth == 0 || fillHeight == 0)) + { + return size; + } + + if (fillWidth == null || fillWidth == 0) + { + fillWidth = 1; + } + + if (fillHeight == null || fillHeight == 0) + { + fillHeight = 1; + } + + double widthRatio = (double)size.Width / (double)fillWidth; + double heightRatio = (double)size.Height / (double)fillHeight!; + // min() + double scaleRatio = widthRatio > heightRatio ? heightRatio : widthRatio; + + // Clamp to current size. + if (scaleRatio < 1) + { + return size; + } + + int newWidth = Convert.ToInt32(Math.Ceiling((double)size.Width / scaleRatio)); + int newHeight = Convert.ToInt32(Math.Ceiling((double)size.Height / scaleRatio)); + + return new ImageDimensions(newWidth, newHeight); + } + /// /// Gets the new width. /// -- cgit v1.2.3 From 13d0837b78011925d308e7ff593207b0e1cb330f Mon Sep 17 00:00:00 2001 From: Odd Stråbø Date: Wed, 17 Mar 2021 19:45:28 +0100 Subject: (mostly)Fix ResizeFill --- Jellyfin.Api/Controllers/ImageController.cs | 134 ++++++++++----------- .../Drawing/ImageProcessingOptions.cs | 10 ++ MediaBrowser.Model/Drawing/DrawingUtils.cs | 12 +- 3 files changed, 82 insertions(+), 74 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 1da567793..55c2fe735 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -521,6 +521,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] string? tag, [FromQuery] bool? cropWhitespace, [FromQuery] ImageFormat? format, @@ -530,9 +532,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -553,8 +553,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -607,6 +607,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] string? tag, [FromQuery] bool? cropWhitespace, [FromQuery] ImageFormat? format, @@ -615,9 +617,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? unplayedCount, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -638,8 +638,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -691,6 +691,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromRoute, Required] string tag, [FromQuery] bool? cropWhitespace, [FromRoute, Required] ImageFormat format, @@ -700,9 +702,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromRoute, Required] int imageIndex) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -723,8 +723,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -780,14 +780,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromRoute, Required] int imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromRoute, Required] int imageIndex) { var item = _libraryManager.GetArtist(name); if (item == null) @@ -808,8 +808,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -865,14 +865,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -893,8 +893,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -951,13 +951,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetGenre(name); if (item == null) @@ -978,8 +978,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1035,14 +1035,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -1063,8 +1063,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1121,13 +1121,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetMusicGenre(name); if (item == null) @@ -1148,8 +1148,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1205,14 +1205,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -1233,8 +1233,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1291,13 +1291,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetPerson(name); if (item == null) @@ -1318,8 +1318,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1375,14 +1375,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -1403,8 +1403,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1461,13 +1461,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var item = _libraryManager.GetStudio(name); if (item == null) @@ -1488,8 +1488,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1545,14 +1545,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, [FromQuery] string? foregroundLayer, - [FromQuery] int? imageIndex, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] int? imageIndex) { var user = _userManager.GetUserById(userId); if (user?.ProfileImage == null) @@ -1590,8 +1590,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1649,13 +1649,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? width, [FromQuery] int? height, [FromQuery] int? quality, + [FromQuery] int? fillWidth, + [FromQuery] int? fillHeight, [FromQuery] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, - [FromQuery] string? foregroundLayer, - [FromQuery] int? fillHeight, - [FromQuery] int? fillWidth) + [FromQuery] string? foregroundLayer) { var user = _userManager.GetUserById(userId); if (user?.ProfileImage == null) @@ -1693,8 +1693,8 @@ namespace Jellyfin.Api.Controllers width, height, quality, - fillHeight, fillWidth, + fillHeight, cropWhitespace, addPlayedIndicator, blur, @@ -1779,8 +1779,8 @@ namespace Jellyfin.Api.Controllers int? width, int? height, int? quality, - int? fillHeight, int? fillWidth, + int? fillHeight, bool? cropWhitespace, // TODO: Remove bool? addPlayedIndicator, int? blur, @@ -1844,11 +1844,13 @@ namespace Jellyfin.Api.Controllers item, itemId, imageIndex, + width, height, - maxHeight, maxWidth, + maxHeight, + fillWidth, + fillHeight, quality, - width, addPlayedIndicator, percentPlayed, unplayedCount, @@ -1859,9 +1861,7 @@ namespace Jellyfin.Api.Controllers outputFormats, cacheDuration, responseHeaders, - isHeadRequest, - fillHeight, - fillWidth).ConfigureAwait(false); + isHeadRequest).ConfigureAwait(false); } private ImageFormat[] GetOutputFormats(ImageFormat? format) @@ -1944,11 +1944,13 @@ namespace Jellyfin.Api.Controllers BaseItem? item, Guid itemId, int? index, + int? width, int? height, - int? maxHeight, int? maxWidth, + int? maxHeight, + int? fillWidth, + int? fillHeight, int? quality, - int? width, bool? addPlayedIndicator, double? percentPlayed, int? unplayedCount, @@ -1959,9 +1961,7 @@ namespace Jellyfin.Api.Controllers IReadOnlyCollection supportedFormats, TimeSpan? cacheDuration, IDictionary headers, - bool isHeadRequest, - int? fillHeight, - int? fillWidth) + bool isHeadRequest) { if (!imageInfo.IsLocalFile && item != null) { diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 4befb29c4..e1a2811ac 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -97,6 +97,16 @@ namespace MediaBrowser.Controller.Drawing return false; } + if (FillWidth.HasValue && sizeValue.Width > FillWidth.Value) + { + return false; + } + + if (FillHeight.HasValue && sizeValue.Height > FillHeight.Value) + { + return false; + } + return true; } diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs index 8fb9bdc0a..c2a144f81 100644 --- a/MediaBrowser.Model/Drawing/DrawingUtils.cs +++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Model.Drawing } /// - /// Resizes to fill box. + /// Scale down to fill box. /// Returns original size if both width and height are null or zero. /// /// The original size object. @@ -71,9 +71,8 @@ namespace MediaBrowser.Model.Drawing int? fillHeight) { // Return original size if input is invalid. - if ( - (fillWidth == null && fillHeight == null) - || (fillWidth == 0 || fillHeight == 0)) + if ((fillWidth == null || fillWidth == 0) + && (fillHeight == null || fillHeight == 0)) { return size; } @@ -89,9 +88,8 @@ namespace MediaBrowser.Model.Drawing } double widthRatio = (double)size.Width / (double)fillWidth; - double heightRatio = (double)size.Height / (double)fillHeight!; - // min() - double scaleRatio = widthRatio > heightRatio ? heightRatio : widthRatio; + double heightRatio = (double)size.Height / (double)fillHeight; + double scaleRatio = Math.Min(widthRatio, heightRatio); // Clamp to current size. if (scaleRatio < 1) -- cgit v1.2.3 From cc59abd54e7be6a58187bfb3d01dbe0ec7ea9a1d Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 12 Apr 2021 07:50:24 -0600 Subject: Mark cropWhitespace parameter as obsolete (#5751) --- Jellyfin.Api/Controllers/ImageController.cs | 45 +++++++++-------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 55c2fe735..36facf75a 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -524,7 +524,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery] string? tag, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, [FromQuery] bool? addPlayedIndicator, [FromQuery] double? percentPlayed, @@ -555,7 +555,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -610,7 +609,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromQuery] string? tag, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] ImageFormat? format, [FromQuery] bool? addPlayedIndicator, [FromQuery] double? percentPlayed, @@ -640,7 +639,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -694,7 +692,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, [FromRoute, Required] string tag, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromRoute, Required] ImageFormat format, [FromQuery] bool? addPlayedIndicator, [FromRoute, Required] double percentPlayed, @@ -725,7 +723,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -782,7 +779,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -810,7 +807,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -867,7 +863,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -895,7 +891,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -953,7 +948,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -980,7 +975,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1037,7 +1031,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1065,7 +1059,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1123,7 +1116,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1150,7 +1143,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1207,7 +1199,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1235,7 +1227,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1293,7 +1284,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1320,7 +1311,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1377,7 +1367,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1405,7 +1395,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1463,7 +1452,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1490,7 +1479,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1547,7 +1535,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1592,7 +1580,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1651,7 +1638,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? quality, [FromQuery] int? fillWidth, [FromQuery] int? fillHeight, - [FromQuery] bool? cropWhitespace, + [FromQuery, ParameterObsolete] bool? cropWhitespace, [FromQuery] bool? addPlayedIndicator, [FromQuery] int? blur, [FromQuery] string? backgroundColor, @@ -1695,7 +1682,6 @@ namespace Jellyfin.Api.Controllers quality, fillWidth, fillHeight, - cropWhitespace, addPlayedIndicator, blur, backgroundColor, @@ -1781,7 +1767,6 @@ namespace Jellyfin.Api.Controllers int? quality, int? fillWidth, int? fillHeight, - bool? cropWhitespace, // TODO: Remove bool? addPlayedIndicator, int? blur, string? backgroundColor, @@ -1823,8 +1808,6 @@ namespace Jellyfin.Api.Controllers } } - cropWhitespace ??= imageType == ImageType.Logo || imageType == ImageType.Art; - var outputFormats = GetOutputFormats(format); TimeSpan? cacheDuration = null; -- cgit v1.2.3 From dc4714fe4098eed42114adc3455f4a2982cc18d6 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 12 Apr 2021 19:54:32 +0200 Subject: fix webp compatibility testing (#5787) --- Jellyfin.Api/Controllers/ImageController.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'Jellyfin.Api/Controllers/ImageController.cs') diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 36facf75a..8f7500ac6 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -1859,17 +1859,15 @@ namespace Jellyfin.Api.Controllers private ImageFormat[] GetClientSupportedFormats() { - var acceptTypes = Request.Headers[HeaderNames.Accept]; - var supportedFormats = new List(); - if (acceptTypes.Count > 0) + var supportedFormats = Request.Headers.GetCommaSeparatedValues(HeaderNames.Accept); + for (var i = 0; i < supportedFormats.Length; i++) { - foreach (var type in acceptTypes) + // Remove charsets etc. (anything after semi-colon) + var type = supportedFormats[i]; + int index = type.IndexOf(';', StringComparison.Ordinal); + if (index != -1) { - int index = type.IndexOf(';', StringComparison.Ordinal); - if (index != -1) - { - supportedFormats.Add(type.Substring(0, index)); - } + supportedFormats[i] = type.Substring(0, index); } } -- cgit v1.2.3