From 638cfa32abc3ffd61119f774ffc5a0f5a490d3e9 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 2 Jun 2020 15:07:07 +0200 Subject: Move SearchService to new API endpoint --- Jellyfin.Api/Controllers/SearchController.cs | 266 +++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 Jellyfin.Api/Controllers/SearchController.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs new file mode 100644 index 000000000..15a650bf9 --- /dev/null +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -0,0 +1,266 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Linq; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Search; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// + /// Search controller. + /// + [Route("/Search/Hints")] + [Authenticated] + public class SearchController : BaseJellyfinApiController + { + private readonly ISearchEngine _searchEngine; + private readonly ILibraryManager _libraryManager; + private readonly IDtoService _dtoService; + private readonly IImageProcessor _imageProcessor; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of interface. + /// Instance of interface. + /// Instance of interface. + /// Instance of interface. + public SearchController( + ISearchEngine searchEngine, + ILibraryManager libraryManager, + IDtoService dtoService, + IImageProcessor imageProcessor) + { + _searchEngine = searchEngine; + _libraryManager = libraryManager; + _dtoService = dtoService; + _imageProcessor = imageProcessor; + } + + /// + /// Gets the search hint result. + /// + /// The record index to start at. All items with a lower index will be dropped from the results. + /// The maximum number of records to return. + /// Supply a user id to search within a user's library or omit to search all. + /// The search term to filter on. + /// Optional filter whether to include people. + /// Optional filter whether to include media. + /// Optional filter whether to include genres. + /// Optional filter whether to include studios. + /// Optional filter whether to include artists. + /// If specified, only results with the specified item types are returned. This allows multiple, comma delimeted. + /// If specified, results with these item types are filtered out. This allows multiple, comma delimeted. + /// If specified, only results with the specified media types are returned. This allows multiple, comma delimeted. + /// If specified, only children of the parent are returned. + /// Optional filter for movies. + /// Optional filter for series. + /// Optional filter for news. + /// Optional filter for kids. + /// Optional filter for sports. + /// An with the results of the search. + [HttpGet] + [Description("Gets search hints based on a search term")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult Get( + [FromQuery] int? startIndex, + [FromQuery] int? limit, + [FromQuery] Guid userId, + [FromQuery, Required] string searchTerm, + [FromQuery] bool includePeople, + [FromQuery] bool includeMedia, + [FromQuery] bool includeGenres, + [FromQuery] bool includeStudios, + [FromQuery] bool includeArtists, + [FromQuery] string includeItemTypes, + [FromQuery] string excludeItemTypes, + [FromQuery] string mediaTypes, + [FromQuery] string parentId, + [FromQuery] bool? isMovie, + [FromQuery] bool? isSeries, + [FromQuery] bool? isNews, + [FromQuery] bool? isKids, + [FromQuery] bool? isSports) + { + var result = _searchEngine.GetSearchHints(new SearchQuery + { + Limit = limit, + SearchTerm = searchTerm, + IncludeArtists = includeArtists, + IncludeGenres = includeGenres, + IncludeMedia = includeMedia, + IncludePeople = includePeople, + IncludeStudios = includeStudios, + StartIndex = startIndex, + UserId = userId, + IncludeItemTypes = Split(includeItemTypes, ',', true), + ExcludeItemTypes = Split(excludeItemTypes, ',', true), + MediaTypes = Split(mediaTypes, ',', true), + ParentId = parentId, + + IsKids = isKids, + IsMovie = isMovie, + IsNews = isNews, + IsSeries = isSeries, + IsSports = isSports + }); + + return Ok(new SearchHintResult + { + TotalRecordCount = result.TotalRecordCount, + SearchHints = result.Items.Select(GetSearchHintResult).ToArray() + }); + } + + /// + /// Gets the search hint result. + /// + /// The hint info. + /// SearchHintResult. + private SearchHint GetSearchHintResult(SearchHintInfo hintInfo) + { + var item = hintInfo.Item; + + var result = new SearchHint + { + Name = item.Name, + IndexNumber = item.IndexNumber, + ParentIndexNumber = item.ParentIndexNumber, + Id = item.Id, + Type = item.GetClientTypeName(), + MediaType = item.MediaType, + MatchedTerm = hintInfo.MatchedTerm, + RunTimeTicks = item.RunTimeTicks, + ProductionYear = item.ProductionYear, + ChannelId = item.ChannelId, + EndDate = item.EndDate + }; + + // legacy + result.ItemId = result.Id; + + if (item.IsFolder) + { + result.IsFolder = true; + } + + var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); + + if (primaryImageTag != null) + { + result.PrimaryImageTag = primaryImageTag; + result.PrimaryImageAspectRatio = _dtoService.GetPrimaryImageAspectRatio(item); + } + + SetThumbImageInfo(result, item); + SetBackdropImageInfo(result, item); + + switch (item) + { + case IHasSeries hasSeries: + result.Series = hasSeries.SeriesName; + break; + case LiveTvProgram program: + result.StartDate = program.StartDate; + break; + case Series series: + if (series.Status.HasValue) + { + result.Status = series.Status.Value.ToString(); + } + + break; + case MusicAlbum album: + result.Artists = album.Artists; + result.AlbumArtist = album.AlbumArtist; + break; + case Audio song: + result.AlbumArtist = song.AlbumArtists?[0]; + result.Artists = song.Artists; + + MusicAlbum musicAlbum = song.AlbumEntity; + + if (musicAlbum != null) + { + result.Album = musicAlbum.Name; + result.AlbumId = musicAlbum.Id; + } + else + { + result.Album = song.Album; + } + + break; + } + + if (!item.ChannelId.Equals(Guid.Empty)) + { + var channel = _libraryManager.GetItemById(item.ChannelId); + result.ChannelName = channel?.Name; + } + + return result; + } + + private void SetThumbImageInfo(SearchHint hint, BaseItem item) + { + var itemWithImage = item.HasImage(ImageType.Thumb) ? item : null; + + if (itemWithImage == null && item is Episode) + { + itemWithImage = GetParentWithImage(item, ImageType.Thumb); + } + + if (itemWithImage == null) + { + itemWithImage = GetParentWithImage(item, ImageType.Thumb); + } + + if (itemWithImage != null) + { + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb); + + if (tag != null) + { + hint.ThumbImageTag = tag; + hint.ThumbImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture); + } + } + } + + private void SetBackdropImageInfo(SearchHint hint, BaseItem item) + { + var itemWithImage = (item.HasImage(ImageType.Backdrop) ? item : null) + ?? GetParentWithImage(item, ImageType.Backdrop); + + if (itemWithImage != null) + { + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop); + + if (tag != null) + { + hint.BackdropImageTag = tag; + hint.BackdropImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture); + } + } + } + + private T GetParentWithImage(BaseItem item, ImageType type) + where T : BaseItem + { + return item.GetParents().OfType().FirstOrDefault(i => i.HasImage(type)); + } + } +} -- cgit v1.2.3 From f3029428cd118b34d73706fdd85cc3918b312a86 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 15:33:54 +0200 Subject: Fix suggestions --- Jellyfin.Api/Controllers/SearchController.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 15a650bf9..2ee3ef25b 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -10,9 +10,9 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -22,7 +22,7 @@ namespace Jellyfin.Api.Controllers /// Search controller. /// [Route("/Search/Hints")] - [Authenticated] + [Authorize] public class SearchController : BaseJellyfinApiController { private readonly ISearchEngine _searchEngine; @@ -52,9 +52,9 @@ namespace Jellyfin.Api.Controllers /// /// Gets the search hint result. /// - /// The record index to start at. All items with a lower index will be dropped from the results. - /// The maximum number of records to return. - /// Supply a user id to search within a user's library or omit to search all. + /// Optional. The record index to start at. All items with a lower index will be dropped from the results. + /// Optional. The maximum number of records to return. + /// Optional. Supply a user id to search within a user's library or omit to search all. /// The search term to filter on. /// Optional filter whether to include people. /// Optional filter whether to include media. @@ -117,11 +117,11 @@ namespace Jellyfin.Api.Controllers IsSports = isSports }); - return Ok(new SearchHintResult + return new SearchHintResult { TotalRecordCount = result.TotalRecordCount, SearchHints = result.Items.Select(GetSearchHintResult).ToArray() - }); + }; } /// -- cgit v1.2.3 From 7fa374f8a2560cd1c58584b3d5b0567c91ef4138 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 15:41:49 +0200 Subject: Move Split method from BaseJellyfinApiController.cs to RequestHelpers.cs --- Jellyfin.Api/BaseJellyfinApiController.cs | 18 ----------------- Jellyfin.Api/Controllers/SearchController.cs | 7 ++++--- Jellyfin.Api/Helpers/RequestHelpers.cs | 29 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 Jellyfin.Api/Helpers/RequestHelpers.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs index 6a9e48f8d..22b9c3fd6 100644 --- a/Jellyfin.Api/BaseJellyfinApiController.cs +++ b/Jellyfin.Api/BaseJellyfinApiController.cs @@ -10,23 +10,5 @@ namespace Jellyfin.Api [Route("[controller]")] public class BaseJellyfinApiController : ControllerBase { - /// - /// Splits a string at a seperating character into an array of substrings. - /// - /// The string to split. - /// The char that seperates the substrings. - /// Option to remove empty substrings from the array. - /// An array of the substrings. - internal static string[] Split(string value, char separator, bool removeEmpty) - { - if (string.IsNullOrWhiteSpace(value)) - { - return Array.Empty(); - } - - return removeEmpty - ? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries) - : value.Split(separator); - } } } diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 2ee3ef25b..b6178e121 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -105,9 +106,9 @@ namespace Jellyfin.Api.Controllers IncludeStudios = includeStudios, StartIndex = startIndex, UserId = userId, - IncludeItemTypes = Split(includeItemTypes, ',', true), - ExcludeItemTypes = Split(excludeItemTypes, ',', true), - MediaTypes = Split(mediaTypes, ',', true), + IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), + ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), + MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), ParentId = parentId, IsKids = isKids, diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs new file mode 100644 index 000000000..6c661e2d3 --- /dev/null +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -0,0 +1,29 @@ +using System; + +namespace Jellyfin.Api.Helpers +{ + /// + /// Request Extensions. + /// + public static class RequestHelpers + { + /// + /// Splits a string at a seperating character into an array of substrings. + /// + /// The string to split. + /// The char that seperates the substrings. + /// Option to remove empty substrings from the array. + /// An array of the substrings. + internal static string[] Split(string value, char separator, bool removeEmpty) + { + if (string.IsNullOrWhiteSpace(value)) + { + return Array.Empty(); + } + + return removeEmpty + ? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries) + : value.Split(separator); + } + } +} -- cgit v1.2.3 From cefa9d3c086fd01b6f05080fa272fcf1f76158f2 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 18:10:08 +0200 Subject: Add default values for parameters and fix spelling --- Jellyfin.Api/Controllers/SearchController.cs | 22 +++++++++++----------- Jellyfin.Api/Helpers/RequestHelpers.cs | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index b6178e121..411c19a59 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -57,11 +57,6 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of records to return. /// Optional. Supply a user id to search within a user's library or omit to search all. /// The search term to filter on. - /// Optional filter whether to include people. - /// Optional filter whether to include media. - /// Optional filter whether to include genres. - /// Optional filter whether to include studios. - /// Optional filter whether to include artists. /// If specified, only results with the specified item types are returned. This allows multiple, comma delimeted. /// If specified, results with these item types are filtered out. This allows multiple, comma delimeted. /// If specified, only results with the specified media types are returned. This allows multiple, comma delimeted. @@ -71,6 +66,11 @@ namespace Jellyfin.Api.Controllers /// Optional filter for news. /// Optional filter for kids. /// Optional filter for sports. + /// Optional filter whether to include people. + /// Optional filter whether to include media. + /// Optional filter whether to include genres. + /// Optional filter whether to include studios. + /// Optional filter whether to include artists. /// An with the results of the search. [HttpGet] [Description("Gets search hints based on a search term")] @@ -80,11 +80,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? limit, [FromQuery] Guid userId, [FromQuery, Required] string searchTerm, - [FromQuery] bool includePeople, - [FromQuery] bool includeMedia, - [FromQuery] bool includeGenres, - [FromQuery] bool includeStudios, - [FromQuery] bool includeArtists, [FromQuery] string includeItemTypes, [FromQuery] string excludeItemTypes, [FromQuery] string mediaTypes, @@ -93,7 +88,12 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? isSeries, [FromQuery] bool? isNews, [FromQuery] bool? isKids, - [FromQuery] bool? isSports) + [FromQuery] bool? isSports, + [FromQuery] bool includePeople = true, + [FromQuery] bool includeMedia = true, + [FromQuery] bool includeGenres = true, + [FromQuery] bool includeStudios = true, + [FromQuery] bool includeArtists = true) { var result = _searchEngine.GetSearchHints(new SearchQuery { diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index 6c661e2d3..9f4d34f9c 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -8,10 +8,10 @@ namespace Jellyfin.Api.Helpers public static class RequestHelpers { /// - /// Splits a string at a seperating character into an array of substrings. + /// Splits a string at a separating character into an array of substrings. /// /// The string to split. - /// The char that seperates the substrings. + /// The char that separates the substrings. /// Option to remove empty substrings from the array. /// An array of the substrings. internal static string[] Split(string value, char separator, bool removeEmpty) -- cgit v1.2.3 From 1491e93d841a8c40ea1a9fed9d99427a64ccd66c Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Tue, 9 Jun 2020 11:00:37 +0200 Subject: Add response code documentation --- Jellyfin.Api/Controllers/SearchController.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 411c19a59..ec05e4fb4 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -71,6 +71,7 @@ namespace Jellyfin.Api.Controllers /// Optional filter whether to include genres. /// Optional filter whether to include studios. /// Optional filter whether to include artists. + /// Search hint returned. /// An with the results of the search. [HttpGet] [Description("Gets search hints based on a search term")] -- cgit v1.2.3 From c24666253c48ef17402bd8ddb7688821616ec6ba Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 16 Jun 2020 14:15:58 -0600 Subject: Add Default authorization policy --- Jellyfin.Api/Controllers/ConfigurationController.cs | 2 +- Jellyfin.Api/Controllers/DevicesController.cs | 2 +- Jellyfin.Api/Controllers/PackageController.cs | 2 +- Jellyfin.Api/Controllers/SearchController.cs | 3 ++- Jellyfin.Api/Controllers/SubtitleController.cs | 8 ++++---- Jellyfin.Api/Controllers/VideoAttachmentsController.cs | 3 ++- 6 files changed, 11 insertions(+), 9 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index 780a38aa8..5d37c9ade 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -18,7 +18,7 @@ namespace Jellyfin.Api.Controllers /// Configuration Controller. /// [Route("System")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] public class ConfigurationController : BaseJellyfinApiController { private readonly IServerConfigurationManager _configurationManager; diff --git a/Jellyfin.Api/Controllers/DevicesController.cs b/Jellyfin.Api/Controllers/DevicesController.cs index 1754b0cbd..2f5362851 100644 --- a/Jellyfin.Api/Controllers/DevicesController.cs +++ b/Jellyfin.Api/Controllers/DevicesController.cs @@ -17,7 +17,7 @@ namespace Jellyfin.Api.Controllers /// /// Devices Controller. /// - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] public class DevicesController : BaseJellyfinApiController { private readonly IDeviceManager _deviceManager; diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 8200f891c..b5b21fdee 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -18,7 +18,7 @@ namespace Jellyfin.Api.Controllers /// Package Controller. /// [Route("Packages")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] public class PackageController : BaseJellyfinApiController { private readonly IInstallationManager _installationManager; diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index ec05e4fb4..d971889db 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -23,7 +24,7 @@ namespace Jellyfin.Api.Controllers /// Search controller. /// [Route("/Search/Hints")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] public class SearchController : BaseJellyfinApiController { private readonly ISearchEngine _searchEngine; diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 97df8c60d..9aff35996 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -110,7 +110,7 @@ namespace Jellyfin.Api.Controllers /// Subtitles retrieved. /// An array of . [HttpGet("/Items/{id}/RemoteSearch/Subtitles/{language}")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> SearchRemoteSubtitles( [FromRoute] Guid id, @@ -130,7 +130,7 @@ namespace Jellyfin.Api.Controllers /// Subtitle downloaded. /// A . [HttpPost("/Items/{id}/RemoteSearch/Subtitles/{subtitleId}")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task DownloadRemoteSubtitles( [FromRoute] Guid id, @@ -160,7 +160,7 @@ namespace Jellyfin.Api.Controllers /// File returned. /// A with the subtitle file. [HttpGet("/Providers/Subtitles/Subtitles/{id}")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [Produces(MediaTypeNames.Application.Octet)] public async Task GetRemoteSubtitles([FromRoute] string id) @@ -250,7 +250,7 @@ namespace Jellyfin.Api.Controllers /// Subtitle playlist retrieved. /// A with the HLS subtitle playlist. [HttpGet("/Videos/{id}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetSubtitlePlaylist( [FromRoute] Guid id, diff --git a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs index 86d9322fe..32e26ff0b 100644 --- a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs +++ b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs @@ -4,6 +4,7 @@ using System; using System.Net.Mime; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Constants; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -17,7 +18,7 @@ namespace Jellyfin.Api.Controllers /// Attachments controller. /// [Route("Videos")] - [Authorize] + [Authorize(Policy = Policies.DefaultAuthorization)] public class VideoAttachmentsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; -- cgit v1.2.3 From 73bcda7eac6d0785745179fe4b7f58b6bc4ec488 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 27 Jun 2020 10:50:44 -0600 Subject: Make all optional strings nullable --- Jellyfin.Api/Controllers/AlbumsController.cs | 4 +- Jellyfin.Api/Controllers/ApiKeyController.cs | 4 +- Jellyfin.Api/Controllers/CollectionController.cs | 8 ++-- .../Controllers/ConfigurationController.cs | 4 +- Jellyfin.Api/Controllers/DashboardController.cs | 2 +- Jellyfin.Api/Controllers/DevicesController.cs | 8 ++-- .../Controllers/DisplayPreferencesController.cs | 12 +++--- Jellyfin.Api/Controllers/ImageByNameController.cs | 12 +++--- Jellyfin.Api/Controllers/InstantMixController.cs | 16 ++++---- Jellyfin.Api/Controllers/ItemUpdateController.cs | 2 +- Jellyfin.Api/Controllers/LibraryController.cs | 16 ++++---- .../Controllers/LibraryStructureController.cs | 22 +++++------ .../Controllers/NotificationsController.cs | 4 +- Jellyfin.Api/Controllers/PackageController.cs | 8 ++-- Jellyfin.Api/Controllers/PlaylistsController.cs | 14 +++---- Jellyfin.Api/Controllers/PluginsController.cs | 4 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- .../Controllers/ScheduledTasksController.cs | 8 ++-- Jellyfin.Api/Controllers/SearchController.cs | 10 ++--- Jellyfin.Api/Controllers/SessionController.cs | 46 +++++++++++----------- Jellyfin.Api/Controllers/StartupController.cs | 6 +-- Jellyfin.Api/Controllers/SubtitleController.cs | 14 +++---- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 8 ++-- Jellyfin.Api/Controllers/UserController.cs | 8 ++-- Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +-- Jellyfin.Api/Controllers/UserViewsController.cs | 2 +- .../Controllers/VideoAttachmentsController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 2 +- Jellyfin.Api/Controllers/YearsController.cs | 16 ++++---- Jellyfin.Api/Extensions/DtoExtensions.cs | 4 +- Jellyfin.Api/Helpers/RequestHelpers.cs | 10 ++--- Jellyfin.Api/Helpers/SimilarItemsHelper.cs | 2 +- 33 files changed, 143 insertions(+), 145 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs index 622123873..70315b0a3 100644 --- a/Jellyfin.Api/Controllers/AlbumsController.cs +++ b/Jellyfin.Api/Controllers/AlbumsController.cs @@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetSimilarAlbums( [FromRoute] string albumId, [FromQuery] Guid userId, - [FromQuery] string excludeArtistIds, + [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) { var dtoOptions = new DtoOptions().AddClientFields(Request); @@ -85,7 +85,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetSimilarArtists( [FromRoute] string artistId, [FromQuery] Guid userId, - [FromQuery] string excludeArtistIds, + [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) { var dtoOptions = new DtoOptions().AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index ed521c1fc..fef4d7262 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 { @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Keys/{key}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RevokeKey([FromRoute] string key) + public ActionResult RevokeKey([FromRoute] string? key) { _sessionManager.RevokeToken(key); return NoContent(); diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 29db0b178..7ff98b251 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -51,8 +51,8 @@ namespace Jellyfin.Api.Controllers [HttpPost] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult CreateCollection( - [FromQuery] string name, - [FromQuery] string ids, + [FromQuery] string? name, + [FromQuery] string? ids, [FromQuery] bool isLocked, [FromQuery] Guid? parentId) { @@ -86,7 +86,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult AddToCollection([FromRoute] Guid collectionId, [FromQuery] string itemIds) + public ActionResult AddToCollection([FromRoute] Guid collectionId, [FromQuery] string? itemIds) { _collectionManager.AddToCollection(collectionId, RequestHelpers.Split(itemIds, ',', true)); return NoContent(); @@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpDelete("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery] string itemIds) + public ActionResult RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery] string? itemIds) { _collectionManager.RemoveFromCollection(collectionId, RequestHelpers.Split(itemIds, ',', true)); return NoContent(); diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index d275ed2eb..13933cb33 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -70,7 +70,7 @@ namespace Jellyfin.Api.Controllers /// Configuration. [HttpGet("Configuration/{key}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetNamedConfiguration([FromRoute] string key) + public ActionResult GetNamedConfiguration([FromRoute] string? key) { return _configurationManager.GetConfiguration(key); } @@ -84,7 +84,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] string? key) { var configurationType = _configurationManager.GetConfigurationType(key); var configuration = await JsonSerializer.DeserializeAsync(Request.Body, configurationType).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index 6cfee2463..699ef6bf7 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -122,7 +122,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("/web/ConfigurationPage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetDashboardConfigurationPage([FromQuery] string name) + public ActionResult GetDashboardConfigurationPage([FromQuery] string? name) { IPlugin? plugin = null; Stream? stream = null; diff --git a/Jellyfin.Api/Controllers/DevicesController.cs b/Jellyfin.Api/Controllers/DevicesController.cs index 55ca7b7c0..3cf7b3378 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, BindRequired] string id) + public ActionResult GetDeviceInfo([FromQuery, BindRequired] 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, BindRequired] string id) + public ActionResult GetDeviceOptions([FromQuery, BindRequired] 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, BindRequired] string id, + [FromQuery, BindRequired] string? id, [FromBody, BindRequired] 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, BindRequired] string id) + public ActionResult DeleteDevice([FromQuery, BindRequired] 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 3f946d9d2..1255e6dab 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -39,9 +39,9 @@ namespace Jellyfin.Api.Controllers [HttpGet("{displayPreferencesId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetDisplayPreferences( - [FromRoute] string displayPreferencesId, - [FromQuery] [Required] string userId, - [FromQuery] [Required] string client) + [FromRoute] string? displayPreferencesId, + [FromQuery] [Required] string? userId, + [FromQuery] [Required] string? client) { return _displayPreferencesRepository.GetDisplayPreferences(displayPreferencesId, userId, client); } @@ -59,9 +59,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] public ActionResult UpdateDisplayPreferences( - [FromRoute] string displayPreferencesId, - [FromQuery, BindRequired] string userId, - [FromQuery, BindRequired] string client, + [FromRoute] string? displayPreferencesId, + [FromQuery, BindRequired] string? userId, + [FromQuery, BindRequired] string? client, [FromBody, BindRequired] DisplayPreferences displayPreferences) { _displayPreferencesRepository.SaveDisplayPreferences( diff --git a/Jellyfin.Api/Controllers/ImageByNameController.cs b/Jellyfin.Api/Controllers/ImageByNameController.cs index 4800c0608..5244c35b8 100644 --- a/Jellyfin.Api/Controllers/ImageByNameController.cs +++ b/Jellyfin.Api/Controllers/ImageByNameController.cs @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers [Produces(MediaTypeNames.Application.Octet)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetGeneralImage([FromRoute] string name, [FromRoute] string type) + public ActionResult GetGeneralImage([FromRoute] string? name, [FromRoute] string? type) { var filename = string.Equals(type, "primary", StringComparison.OrdinalIgnoreCase) ? "folder" @@ -110,8 +110,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetRatingImage( - [FromRoute] string theme, - [FromRoute] string name) + [FromRoute] string? theme, + [FromRoute] string? name) { return GetImageFile(_applicationPaths.RatingsPath, theme, name); } @@ -143,8 +143,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetMediaInfoImage( - [FromRoute] string theme, - [FromRoute] string name) + [FromRoute] string? theme, + [FromRoute] string? name) { return GetImageFile(_applicationPaths.MediaInfoImagesPath, theme, name); } @@ -156,7 +156,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/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index f1ff770a4..9d945fe2b 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -100,7 +100,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -135,7 +135,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -167,10 +167,10 @@ namespace Jellyfin.Api.Controllers [HttpGet("/MusicGenres/{name}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenre( - [FromRoute] string name, + [FromRoute] string? name, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -204,7 +204,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -239,7 +239,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -274,7 +274,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid id, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? enableImages, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 384f250ec..c9b2aafcc 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Items/{itemId}/ContentType")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UpdateItemContentType([FromRoute] Guid itemId, [FromQuery, BindRequired] string contentType) + public ActionResult UpdateItemContentType([FromRoute] Guid itemId, [FromQuery, BindRequired] 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 1ecf2ac73..f1106cda6 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -524,7 +524,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Library/Series/Updated")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult PostUpdatedSeries([FromQuery] string tvdbId) + public ActionResult PostUpdatedSeries([FromQuery] string? tvdbId) { var series = _libraryManager.GetItemList(new InternalItemsQuery { @@ -554,7 +554,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] string? tmdbId, [FromRoute] string? imdbId) { var movies = _libraryManager.GetItemList(new InternalItemsQuery { @@ -687,10 +687,10 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarItems( [FromRoute] Guid itemId, - [FromQuery] string excludeArtistIds, + [FromQuery] string? excludeArtistIds, [FromQuery] Guid userId, [FromQuery] int? limit, - [FromQuery] string fields) + [FromQuery] string? fields) { var item = itemId.Equals(Guid.Empty) ? (!userId.Equals(Guid.Empty) @@ -737,7 +737,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("/Libraries/AvailableOptions")] [Authorize(Policy = Policies.FirstTimeSetupOrElevated)] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetLibraryOptionsInfo([FromQuery] string libraryContentType, [FromQuery] bool isNewLibrary) + public ActionResult GetLibraryOptionsInfo([FromQuery] string? libraryContentType, [FromQuery] bool isNewLibrary) { var result = new LibraryOptionsResultDto(); @@ -877,10 +877,10 @@ namespace Jellyfin.Api.Controllers private QueryResult GetSimilarItemsResult( BaseItem item, - string excludeArtistIds, + string? excludeArtistIds, Guid userId, int? limit, - string fields, + string? fields, string[] includeItemTypes, bool isMovie) { @@ -942,7 +942,7 @@ namespace Jellyfin.Api.Controllers return result; } - private static string[] GetRepresentativeItemTypes(string contentType) + private static string[] GetRepresentativeItemTypes(string? contentType) { return contentType switch { diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index e4ac019c9..0c91f8447 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -72,8 +72,8 @@ namespace Jellyfin.Api.Controllers [HttpPost] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task AddVirtualFolder( - [FromQuery] string name, - [FromQuery] string collectionType, + [FromQuery] string? name, + [FromQuery] string? collectionType, [FromQuery] bool refreshLibrary, [FromQuery] string[] paths, [FromQuery] LibraryOptions libraryOptions) @@ -100,7 +100,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RemoveVirtualFolder( - [FromQuery] string name, + [FromQuery] string? name, [FromQuery] bool refreshLibrary) { await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false); @@ -123,8 +123,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status409Conflict)] public ActionResult RenameVirtualFolder( - [FromQuery] string name, - [FromQuery] string newName, + [FromQuery] string? name, + [FromQuery] string? newName, [FromQuery] bool refreshLibrary) { if (string.IsNullOrWhiteSpace(name)) @@ -205,8 +205,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("Paths")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddMediaPath( - [FromQuery] string name, - [FromQuery] string path, + [FromQuery] string? name, + [FromQuery] string? path, [FromQuery] MediaPathInfo pathInfo, [FromQuery] bool refreshLibrary) { @@ -256,7 +256,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Paths/Update")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult UpdateMediaPath( - [FromQuery] string name, + [FromQuery] string? name, [FromQuery] MediaPathInfo pathInfo) { if (string.IsNullOrWhiteSpace(name)) @@ -280,8 +280,8 @@ namespace Jellyfin.Api.Controllers [HttpDelete("Paths")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RemoveMediaPath( - [FromQuery] string name, - [FromQuery] string path, + [FromQuery] string? name, + [FromQuery] string? path, [FromQuery] bool refreshLibrary) { if (string.IsNullOrWhiteSpace(name)) @@ -327,7 +327,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("LibraryOptions")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult UpdateLibraryOptions( - [FromQuery] string id, + [FromQuery] string? id, [FromQuery] LibraryOptions libraryOptions) { var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(id); diff --git a/Jellyfin.Api/Controllers/NotificationsController.cs b/Jellyfin.Api/Controllers/NotificationsController.cs index cfa7545c9..02aa39b24 100644 --- a/Jellyfin.Api/Controllers/NotificationsController.cs +++ b/Jellyfin.Api/Controllers/NotificationsController.cs @@ -93,8 +93,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("Admin")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult CreateAdminNotification( - [FromQuery] string name, - [FromQuery] string description, + [FromQuery] string? name, + [FromQuery] string? description, [FromQuery] string? url, [FromQuery] NotificationLevel? level) { diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 486575d23..68ae05658 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("/{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); @@ -80,9 +80,9 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] [Authorize(Policy = Policies.RequiresElevation)] public async Task InstallPackage( - [FromRoute] [Required] string name, - [FromQuery] string assemblyGuid, - [FromQuery] string version) + [FromRoute] [Required] string? name, + [FromQuery] string? assemblyGuid, + [FromQuery] string? version) { var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); var package = _installationManager.GetCompatibleVersions( diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 2dc0d2dc7..d62404fc9 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -84,8 +84,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddToPlaylist( - [FromRoute] string playlistId, - [FromQuery] string ids, + [FromRoute] string? playlistId, + [FromQuery] string? ids, [FromQuery] Guid userId) { _playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId); @@ -103,8 +103,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult MoveItem( - [FromRoute] string playlistId, - [FromRoute] string itemId, + [FromRoute] string? playlistId, + [FromRoute] string? itemId, [FromRoute] int newIndex) { _playlistManager.MoveItem(playlistId, itemId, newIndex); @@ -120,7 +120,7 @@ namespace Jellyfin.Api.Controllers /// An on success. [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RemoveFromPlaylist([FromRoute] string playlistId, [FromQuery] string entryIds) + public ActionResult RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds) { _playlistManager.RemoveFromPlaylist(playlistId, RequestHelpers.Split(entryIds, ',', true)); return NoContent(); @@ -147,11 +147,11 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid userId, [FromRoute] int? startIndex, [FromRoute] int? limit, - [FromRoute] string fields, + [FromRoute] string? fields, [FromRoute] bool? enableImages, [FromRoute] bool? enableUserData, [FromRoute] int? imageTypeLimit, - [FromRoute] string enableImageTypes) + [FromRoute] 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 fd48983ea..056395a51 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -166,7 +166,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] string? name) { return new MBRegistrationRecord { @@ -188,7 +188,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] 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 a0d14be7a..6fff30129 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -208,7 +208,7 @@ namespace Jellyfin.Api.Controllers public async Task DownloadRemoteImage( [FromRoute] Guid itemId, [FromQuery, BindRequired] ImageType type, - [FromQuery] string imageUrl) + [FromQuery] string? imageUrl) { var item = _libraryManager.GetItemById(itemId); if (item == null) diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs index bf5c3076e..3df325e3b 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] string taskId) + public ActionResult GetTask([FromRoute] 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] string taskId) + public ActionResult StartTask([FromRoute] 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] string taskId) + public ActionResult StopTask([FromRoute] 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] string taskId, + [FromRoute] string? taskId, [FromBody, BindRequired] TaskTriggerInfo[] triggerInfos) { var task = _taskManager.ScheduledTasks.FirstOrDefault(o => diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index d971889db..14dc0815c 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -81,11 +81,11 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] Guid userId, - [FromQuery, Required] string searchTerm, - [FromQuery] string includeItemTypes, - [FromQuery] string excludeItemTypes, - [FromQuery] string mediaTypes, - [FromQuery] string parentId, + [FromQuery, Required] string? searchTerm, + [FromQuery] string? includeItemTypes, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? mediaTypes, + [FromQuery] string? parentId, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, [FromQuery] bool? isNews, diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index 39da4178d..bd738aa38 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -62,7 +62,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSessions( [FromQuery] Guid controllableByUserId, - [FromQuery] string deviceId, + [FromQuery] string? deviceId, [FromQuery] int? activeWithinSeconds) { var result = _sessionManager.Sessions; @@ -123,10 +123,10 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Viewing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult DisplayContent( - [FromRoute] string sessionId, - [FromQuery] string itemType, - [FromQuery] string itemId, - [FromQuery] string itemName) + [FromRoute] string? sessionId, + [FromQuery] string? itemType, + [FromQuery] string? itemId, + [FromQuery] string? itemName) { var command = new BrowseRequest { @@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Playing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult Play( - [FromRoute] string sessionId, + [FromRoute] string? sessionId, [FromQuery] Guid[] itemIds, [FromQuery] long? startPositionTicks, [FromQuery] PlayCommand playCommand, @@ -191,7 +191,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Playing/{command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendPlaystateCommand( - [FromRoute] string sessionId, + [FromRoute] string? sessionId, [FromBody] PlaystateRequest playstateRequest) { _sessionManager.SendPlaystateCommand( @@ -213,8 +213,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/System/{command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendSystemCommand( - [FromRoute] string sessionId, - [FromRoute] string command) + [FromRoute] string? sessionId, + [FromRoute] string? command) { var name = command; if (Enum.TryParse(name, true, out GeneralCommandType commandType)) @@ -244,8 +244,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Command/{Command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendGeneralCommand( - [FromRoute] string sessionId, - [FromRoute] string command) + [FromRoute] string? sessionId, + [FromRoute] string? command) { var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -270,7 +270,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Command")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendFullGeneralCommand( - [FromRoute] string sessionId, + [FromRoute] string? sessionId, [FromBody, Required] GeneralCommand command) { var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); @@ -303,9 +303,9 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/Message")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendMessageCommand( - [FromRoute] string sessionId, - [FromQuery] string text, - [FromQuery] string header, + [FromRoute] string? sessionId, + [FromQuery] string? text, + [FromQuery] string? header, [FromQuery] long? timeoutMs) { var command = new MessageCommand @@ -330,7 +330,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/{sessionId}/User/{userId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddUserToSession( - [FromRoute] string sessionId, + [FromRoute] string? sessionId, [FromRoute] Guid userId) { _sessionManager.AddAdditionalUser(sessionId, userId); @@ -347,7 +347,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("/Sessions/{sessionId}/User/{userId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RemoveUserFromSession( - [FromRoute] string sessionId, + [FromRoute] string? sessionId, [FromRoute] Guid userId) { _sessionManager.RemoveAdditionalUser(sessionId, userId); @@ -368,9 +368,9 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/Capabilities")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostCapabilities( - [FromQuery] string id, - [FromQuery] string playableMediaTypes, - [FromQuery] string supportedCommands, + [FromQuery] string? id, + [FromQuery] string? playableMediaTypes, + [FromQuery] string? supportedCommands, [FromQuery] bool supportsMediaControl, [FromQuery] bool supportsSync, [FromQuery] bool supportsPersistentIdentifier = true) @@ -401,7 +401,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/Capabilities/Full")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostFullCapabilities( - [FromQuery] string id, + [FromQuery] string? id, [FromBody, Required] ClientCapabilities capabilities) { if (string.IsNullOrWhiteSpace(id)) @@ -424,8 +424,8 @@ namespace Jellyfin.Api.Controllers [HttpPost("/Sessions/Viewing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult ReportViewing( - [FromQuery] string sessionId, - [FromQuery] string itemId) + [FromQuery] string? sessionId, + [FromQuery] string? itemId) { string session = RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id; diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index d96b0f993..cc1f797b1 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -75,9 +75,9 @@ namespace Jellyfin.Api.Controllers [HttpPost("Configuration")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult UpdateInitialConfiguration( - [FromForm] string uiCulture, - [FromForm] string metadataCountryCode, - [FromForm] string preferredMetadataLanguage) + [FromForm] string? uiCulture, + [FromForm] string? metadataCountryCode, + [FromForm] string? preferredMetadataLanguage) { _config.Configuration.UICulture = uiCulture; _config.Configuration.MetadataCountryCode = metadataCountryCode; diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 95cc39524..baedafaa6 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -112,7 +112,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> SearchRemoteSubtitles( [FromRoute] Guid itemId, - [FromRoute] string language, + [FromRoute] string? language, [FromQuery] bool? isPerfectMatch) { var video = (Video)_libraryManager.GetItemById(itemId); @@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task DownloadRemoteSubtitles( [FromRoute] Guid itemId, - [FromRoute] string subtitleId) + [FromRoute] string? subtitleId) { var video = (Video)_libraryManager.GetItemById(itemId); @@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [Produces(MediaTypeNames.Application.Octet)] - public async Task GetRemoteSubtitles([FromRoute] string id) + public async Task GetRemoteSubtitles([FromRoute] string? id) { var result = await _subtitleManager.GetRemoteSubtitles(id, CancellationToken.None).ConfigureAwait(false); @@ -186,9 +186,9 @@ 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, [FromQuery] bool addVttTimeMap, @@ -254,7 +254,7 @@ namespace Jellyfin.Api.Controllers public async Task GetSubtitlePlaylist( [FromRoute] Guid itemId, [FromRoute] int index, - [FromRoute] string mediaSourceId, + [FromRoute] string? mediaSourceId, [FromQuery, Required] int segmentLength) { var item = (Video)_libraryManager.GetItemById(itemId); @@ -324,7 +324,7 @@ namespace Jellyfin.Api.Controllers /// A with the new subtitle file. private Task EncodeSubtitles( Guid id, - string mediaSourceId, + string? mediaSourceId, int index, string format, long startPositionTicks, diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e33821b24..bc606f7aa 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Logs/Log")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] - 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 6738dd8c8..80b6a2488 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -190,7 +190,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetEpisodes( - [FromRoute] string seriesId, + [FromRoute] string? seriesId, [FromQuery] Guid userId, [FromQuery] string? fields, [FromQuery] int? season, @@ -311,12 +311,12 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetSeasons( - [FromRoute] string seriesId, + [FromRoute] string? seriesId, [FromQuery] Guid userId, - [FromQuery] string fields, + [FromQuery] string? fields, [FromQuery] bool? isSpecialSeason, [FromQuery] bool? isMissing, - [FromQuery] string adjacentTo, + [FromQuery] string? adjacentTo, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, [FromQuery] string? enableImageTypes, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 9f8d564a7..24194dcc2 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -164,8 +164,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> AuthenticateUser( [FromRoute, Required] Guid userId, - [FromQuery, BindRequired] string pw, - [FromQuery, BindRequired] string password) + [FromQuery, BindRequired] string? pw, + [FromQuery, BindRequired] string? password) { var user = _userManager.GetUserById(userId); @@ -483,7 +483,7 @@ namespace Jellyfin.Api.Controllers /// A containing a . [HttpPost("ForgotPassword")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> ForgotPassword([FromBody] string enteredUsername) + public async Task> ForgotPassword([FromBody] string? enteredUsername) { var isLocal = HttpContext.Connection.RemoteIpAddress.Equals(HttpContext.Connection.LocalIpAddress) || _networkManager.IsInLocalNetwork(HttpContext.Connection.RemoteIpAddress.ToString()); @@ -501,7 +501,7 @@ namespace Jellyfin.Api.Controllers /// A containing a . [HttpPost("ForgotPassword/Pin")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> ForgotPasswordPin([FromBody] string pin) + public async Task> ForgotPasswordPin([FromBody] string? pin) { var result = await _userManager.RedeemPasswordResetPin(pin).ConfigureAwait(false); return result; diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 597e70469..ca804ebc9 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -265,12 +265,12 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetLatestMedia( [FromRoute] Guid userId, [FromQuery] Guid parentId, - [FromQuery] string fields, - [FromQuery] string includeItemTypes, + [FromQuery] string? fields, + [FromQuery] string? includeItemTypes, [FromQuery] bool? isPlayed, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, + [FromQuery] string? enableImageTypes, [FromQuery] bool? enableUserData, [FromQuery] int limit = 20, [FromQuery] bool groupItems = true) diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index 38bf94087..ad8927262 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -66,7 +66,7 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid userId, [FromQuery] bool? includeExternalContent, [FromQuery] bool includeHidden, - [FromQuery] string presetViews) + [FromQuery] string? presetViews) { var query = new UserViewQuery { diff --git a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs index 943ba8af3..eef0a93cd 100644 --- a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs +++ b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs @@ -50,7 +50,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetAttachment( [FromRoute] Guid videoId, - [FromRoute] string mediaSourceId, + [FromRoute] string? mediaSourceId, [FromRoute] int index) { try diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index effe630a9..fb1141984 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -133,7 +133,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public ActionResult MergeVersions([FromQuery] string itemIds) + public ActionResult MergeVersions([FromQuery] string? itemIds) { var items = RequestHelpers.Split(itemIds, ',', true) .Select(i => _libraryManager.GetItemById(i)) diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index a036c818c..a66a3951e 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -64,16 +64,16 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetYears( [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string sortOrder, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string mediaTypes, - [FromQuery] string sortBy, + [FromQuery] string? sortOrder, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? mediaTypes, + [FromQuery] string? sortBy, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, + [FromQuery] string? enableImageTypes, [FromQuery] Guid userId, [FromQuery] bool recursive = true, [FromQuery] bool? enableImages = true) diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs index ac248109d..e61e9c29d 100644 --- a/Jellyfin.Api/Extensions/DtoExtensions.cs +++ b/Jellyfin.Api/Extensions/DtoExtensions.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Api.Extensions /// DtoOptions object. /// Comma delimited string of fields. /// Modified DtoOptions object. - internal static DtoOptions AddItemFields(this DtoOptions dtoOptions, string fields) + internal static DtoOptions AddItemFields(this DtoOptions dtoOptions, string? fields) { if (string.IsNullOrEmpty(fields)) { @@ -126,7 +126,7 @@ namespace Jellyfin.Api.Extensions bool? enableImages, bool? enableUserData, int? imageTypeLimit, - string enableImageTypes) + string? enableImageTypes) { dtoOptions.EnableImages = enableImages ?? true; diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index a8ba98f1f..fd86feb8b 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -20,7 +20,7 @@ namespace Jellyfin.Api.Helpers /// The char that separates the substrings. /// Option to remove empty substrings from the array. /// An array of the substrings. - internal static string[] Split(string value, char separator, bool removeEmpty) + internal static string[] Split(string? value, char separator, bool removeEmpty) { if (string.IsNullOrWhiteSpace(value)) { @@ -99,16 +99,14 @@ namespace Jellyfin.Api.Helpers /// Sort by. /// Sort order. /// Resulting order by. - internal static ValueTuple[] GetOrderBy(string sortBy, string requestedSortOrder) + internal static ValueTuple[] GetOrderBy(string? sortBy, string? requestedSortOrder) { - var val = sortBy; - - if (string.IsNullOrEmpty(val)) + if (string.IsNullOrEmpty(sortBy)) { return Array.Empty>(); } - var vals = val.Split(','); + var vals = sortBy.Split(','); if (string.IsNullOrWhiteSpace(requestedSortOrder)) { requestedSortOrder = "Ascending"; diff --git a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs index 751e3c481..fd0c31504 100644 --- a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs +++ b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Api.Helpers IDtoService dtoService, Guid userId, string id, - string excludeArtistIds, + string? excludeArtistIds, int? limit, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) -- cgit v1.2.3 From 5d34b07d1ff7239c7961381fc71559d377e7a96b Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 7 Jul 2020 09:10:51 -0600 Subject: Make query parameters nullable or set default value --- Jellyfin.Api/Auth/BaseAuthorizationHandler.cs | 2 +- Jellyfin.Api/Controllers/AlbumsController.cs | 4 +- Jellyfin.Api/Controllers/ArtistsController.cs | 102 +++++++------- Jellyfin.Api/Controllers/ChannelsController.cs | 22 +-- Jellyfin.Api/Controllers/CollectionController.cs | 6 +- Jellyfin.Api/Controllers/FilterController.cs | 12 +- Jellyfin.Api/Controllers/GenresController.cs | 54 +++---- Jellyfin.Api/Controllers/InstantMixController.cs | 44 ++++-- Jellyfin.Api/Controllers/ItemsController.cs | 10 +- Jellyfin.Api/Controllers/LibraryController.cs | 56 ++++---- .../Controllers/LibraryStructureController.cs | 20 +-- Jellyfin.Api/Controllers/LiveTvController.cs | 156 +++++++++++---------- Jellyfin.Api/Controllers/MediaInfoController.cs | 40 +++--- Jellyfin.Api/Controllers/MoviesController.cs | 26 ++-- Jellyfin.Api/Controllers/MusicGenresController.cs | 54 +++---- Jellyfin.Api/Controllers/PersonsController.cs | 54 +++---- Jellyfin.Api/Controllers/PlaylistsController.cs | 4 +- Jellyfin.Api/Controllers/PlaystateController.cs | 32 ++--- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- Jellyfin.Api/Controllers/SearchController.cs | 4 +- Jellyfin.Api/Controllers/SessionController.cs | 12 +- Jellyfin.Api/Controllers/StudiosController.cs | 54 +++---- Jellyfin.Api/Controllers/SubtitleController.cs | 4 +- Jellyfin.Api/Controllers/SuggestionsController.cs | 6 +- Jellyfin.Api/Controllers/TrailersController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 26 ++-- Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +- Jellyfin.Api/Controllers/UserViewsController.cs | 6 +- Jellyfin.Api/Controllers/VideosController.cs | 6 +- Jellyfin.Api/Controllers/YearsController.cs | 12 +- Jellyfin.Api/Helpers/SimilarItemsHelper.cs | 12 +- 31 files changed, 442 insertions(+), 408 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs index 50b6468db..9fde175d0 100644 --- a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs @@ -52,7 +52,7 @@ namespace Jellyfin.Api.Auth { // Ensure claim has userId. var userId = ClaimHelpers.GetUserId(claimsPrincipal); - if (userId == null) + if (!userId.HasValue) { return false; } diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs index 70315b0a3..01ba7fc32 100644 --- a/Jellyfin.Api/Controllers/AlbumsController.cs +++ b/Jellyfin.Api/Controllers/AlbumsController.cs @@ -52,7 +52,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarAlbums( [FromRoute] string albumId, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) { @@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarArtists( [FromRoute] string artistId, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] string? excludeArtistIds, [FromQuery] int? limit) { diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 6b2084170..d39021446 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -83,31 +83,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -119,9 +119,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -292,31 +292,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -328,9 +328,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -469,15 +469,15 @@ 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] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); var item = _libraryManager.GetArtist(name, dtoOptions); - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index a293a78a0..bdd7dfd96 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetChannels( - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? supportsLatestItems, @@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers { Limit = limit, StartIndex = startIndex, - UserId = userId, + UserId = userId ?? Guid.Empty, SupportsLatestItems = supportsLatestItems, SupportsMediaDeletion = supportsMediaDeletion, IsFavorite = isFavorite @@ -124,9 +124,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? sortBy, [FromQuery] string? fields) { - var user = userId == null - ? null - : _userManager.GetUserById(userId.Value); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var query = new InternalItemsQuery(user) { @@ -195,13 +195,13 @@ namespace Jellyfin.Api.Controllers [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string filters, - [FromQuery] string fields, - [FromQuery] string channelIds) + [FromQuery] string? filters, + [FromQuery] string? fields, + [FromQuery] string? channelIds) { - var user = userId == null || userId == Guid.Empty - ? null - : _userManager.GetUserById(userId.Value); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var query = new InternalItemsQuery(user) { diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 7ff98b251..6f78a7d84 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -44,8 +44,8 @@ namespace Jellyfin.Api.Controllers /// /// The name of the collection. /// Item Ids to add to the collection. - /// Whether or not to lock the new collection. /// Optional. Create the collection within a specific folder. + /// Whether or not to lock the new collection. /// Collection created. /// A with information about the new collection. [HttpPost] @@ -53,8 +53,8 @@ namespace Jellyfin.Api.Controllers public ActionResult CreateCollection( [FromQuery] string? name, [FromQuery] string? ids, - [FromQuery] bool isLocked, - [FromQuery] Guid? parentId) + [FromQuery] Guid? parentId, + [FromQuery] bool isLocked = false) { var userId = _authContext.GetAuthorizationInfo(Request).UserId; diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index 8a0a6ad86..288d4c545 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -57,9 +57,9 @@ namespace Jellyfin.Api.Controllers ? null : _libraryManager.GetItemById(parentId); - var user = userId == null || userId == Guid.Empty - ? null - : _userManager.GetUserById(userId.Value); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) @@ -152,9 +152,9 @@ namespace Jellyfin.Api.Controllers ? null : _libraryManager.GetItemById(parentId); - var user = userId == null || userId == Guid.Empty - ? null - : _userManager.GetUserById(userId.Value); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index d57989a8a..55ad71200 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -84,31 +84,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -120,9 +120,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -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] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); @@ -280,9 +280,9 @@ namespace Jellyfin.Api.Controllers item = _libraryManager.GetGenre(genreName); } - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 9d945fe2b..bb980af3e 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -63,7 +63,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromSong( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -72,7 +72,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var item = _libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -98,7 +100,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromAlbum( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -107,7 +109,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var album = _libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -133,7 +137,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromPlaylist( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -142,7 +146,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var playlist = (Playlist)_libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -168,7 +174,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenre( [FromRoute] string? name, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -176,7 +182,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? imageTypeLimit, [FromQuery] string? enableImageTypes) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -202,7 +210,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromArtists( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -211,7 +219,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var item = _libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -237,7 +247,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenres( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -246,7 +256,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var item = _libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -272,7 +284,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromItem( [FromRoute] Guid id, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields, [FromQuery] bool? enableImages, @@ -281,7 +293,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes) { var item = _libraryManager.GetItemById(id); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) @@ -290,7 +304,7 @@ namespace Jellyfin.Api.Controllers return GetResult(items, user, limit, dtoOptions); } - private QueryResult GetResult(List items, User user, int? limit, DtoOptions dtoOptions) + private QueryResult GetResult(List items, User? user, int? limit, DtoOptions dtoOptions) { var list = items; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index e1dd4af10..41fe47db1 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -143,8 +143,8 @@ namespace Jellyfin.Api.Controllers [HttpGet("/Users/{uId}/Items")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( - [FromRoute] Guid uId, - [FromQuery] Guid userId, + [FromRoute] Guid? uId, + [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeVideo, @@ -226,9 +226,11 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableImages = true) { // use user id route parameter over query parameter - userId = (uId != null) ? uId : userId; + userId = uId ?? userId; - var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index f1106cda6..2466b2ac8 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -146,11 +146,11 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetThemeSongs( [FromRoute] Guid itemId, - [FromQuery] Guid userId, - [FromQuery] bool inheritFromParent) + [FromQuery] Guid? userId, + [FromQuery] bool inheritFromParent = false) { - var user = !userId.Equals(Guid.Empty) - ? _userManager.GetUserById(userId) + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) : null; var item = itemId.Equals(Guid.Empty) @@ -212,11 +212,11 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetThemeVideos( [FromRoute] Guid itemId, - [FromQuery] Guid userId, - [FromQuery] bool inheritFromParent) + [FromQuery] Guid? userId, + [FromQuery] bool inheritFromParent = false) { - var user = !userId.Equals(Guid.Empty) - ? _userManager.GetUserById(userId) + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) : null; var item = itemId.Equals(Guid.Empty) @@ -277,8 +277,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetThemeMedia( [FromRoute] Guid itemId, - [FromQuery] Guid userId, - [FromQuery] bool inheritFromParent) + [FromQuery] Guid? userId, + [FromQuery] bool inheritFromParent = false) { var themeSongs = GetThemeSongs( itemId, @@ -361,12 +361,14 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] - public ActionResult DeleteItems([FromQuery] string ids) + public ActionResult DeleteItems([FromQuery] string? ids) { - var itemIds = string.IsNullOrWhiteSpace(ids) - ? Array.Empty() - : RequestHelpers.Split(ids, ',', true); + if (string.IsNullOrEmpty(ids)) + { + return NoContent(); + } + var itemIds = RequestHelpers.Split(ids, ',', true); foreach (var i in itemIds) { var item = _libraryManager.GetItemById(i); @@ -403,12 +405,12 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetItemCounts( - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] bool? isFavorite) { - var user = userId.Equals(Guid.Empty) - ? null - : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var counts = new ItemCounts { @@ -437,7 +439,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] Guid itemId, [FromQuery] Guid? userId) { var item = _libraryManager.GetItemById(itemId); @@ -448,8 +450,8 @@ namespace Jellyfin.Api.Controllers var baseItemDtos = new List(); - var user = !userId.Equals(Guid.Empty) - ? _userManager.GetUserById(userId) + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) : null; var dtoOptions = new DtoOptions().AddClientFields(Request); @@ -688,7 +690,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetSimilarItems( [FromRoute] Guid itemId, [FromQuery] string? excludeArtistIds, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] string? fields) { @@ -737,7 +739,9 @@ namespace Jellyfin.Api.Controllers [HttpGet("/Libraries/AvailableOptions")] [Authorize(Policy = Policies.FirstTimeSetupOrElevated)] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetLibraryOptionsInfo([FromQuery] string? libraryContentType, [FromQuery] bool isNewLibrary) + public ActionResult GetLibraryOptionsInfo( + [FromQuery] string? libraryContentType, + [FromQuery] bool isNewLibrary = false) { var result = new LibraryOptionsResultDto(); @@ -878,13 +882,15 @@ namespace Jellyfin.Api.Controllers private QueryResult GetSimilarItemsResult( BaseItem item, string? excludeArtistIds, - Guid userId, + Guid? userId, int? limit, string? fields, string[] includeItemTypes, bool isMovie) { - var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null; + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request); diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index 0c91f8447..881d3f192 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -64,9 +64,9 @@ namespace Jellyfin.Api.Controllers /// /// The name of the virtual folder. /// The type of the collection. - /// Whether to refresh the library. /// The paths of the virtual folder. /// The library options. + /// Whether to refresh the library. /// Folder added. /// A . [HttpPost] @@ -74,9 +74,9 @@ namespace Jellyfin.Api.Controllers public async Task AddVirtualFolder( [FromQuery] string? name, [FromQuery] string? collectionType, - [FromQuery] bool refreshLibrary, [FromQuery] string[] paths, - [FromQuery] LibraryOptions libraryOptions) + [FromQuery] LibraryOptions? libraryOptions, + [FromQuery] bool refreshLibrary = false) { libraryOptions ??= new LibraryOptions(); @@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RemoveVirtualFolder( [FromQuery] string? name, - [FromQuery] bool refreshLibrary) + [FromQuery] bool refreshLibrary = false) { await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false); return NoContent(); @@ -125,7 +125,7 @@ namespace Jellyfin.Api.Controllers public ActionResult RenameVirtualFolder( [FromQuery] string? name, [FromQuery] string? newName, - [FromQuery] bool refreshLibrary) + [FromQuery] bool refreshLibrary = false) { if (string.IsNullOrWhiteSpace(name)) { @@ -207,8 +207,8 @@ namespace Jellyfin.Api.Controllers public ActionResult AddMediaPath( [FromQuery] string? name, [FromQuery] string? path, - [FromQuery] MediaPathInfo pathInfo, - [FromQuery] bool refreshLibrary) + [FromQuery] MediaPathInfo? pathInfo, + [FromQuery] bool refreshLibrary = false) { if (string.IsNullOrWhiteSpace(name)) { @@ -257,7 +257,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult UpdateMediaPath( [FromQuery] string? name, - [FromQuery] MediaPathInfo pathInfo) + [FromQuery] MediaPathInfo? pathInfo) { if (string.IsNullOrWhiteSpace(name)) { @@ -282,7 +282,7 @@ namespace Jellyfin.Api.Controllers public ActionResult RemoveMediaPath( [FromQuery] string? name, [FromQuery] string? path, - [FromQuery] bool refreshLibrary) + [FromQuery] bool refreshLibrary = false) { if (string.IsNullOrWhiteSpace(name)) { @@ -328,7 +328,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult UpdateLibraryOptions( [FromQuery] string? id, - [FromQuery] LibraryOptions libraryOptions) + [FromQuery] LibraryOptions? libraryOptions) { var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(id); diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 325837ce3..bc5446510 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -113,7 +113,6 @@ namespace Jellyfin.Api.Controllers /// Optional. Filter by channels that are favorites, or not. /// Optional. Filter by channels that are liked, or not. /// Optional. Filter by channels that are disliked, or not. - /// Optional. Incorporate favorite and like status into channel sorting. /// Optional. Include image information in output. /// Optional. The max number of images to return, per image type. /// "Optional. The image types to include in the output. @@ -121,6 +120,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Include user data. /// Optional. Key to sort by. /// Optional. Sort order. + /// Optional. Incorporate favorite and like status into channel sorting. /// Optional. Adds current program info to each channel. /// Available live tv channels returned. /// @@ -131,7 +131,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] public ActionResult> GetChannels( [FromQuery] ChannelType? type, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, @@ -142,14 +142,14 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? isFavorite, [FromQuery] bool? isLiked, [FromQuery] bool? isDisliked, - [FromQuery] bool enableFavoriteSorting, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string fields, + [FromQuery] string? enableImageTypes, + [FromQuery] string? fields, [FromQuery] bool? enableUserData, - [FromQuery] string sortBy, + [FromQuery] string? sortBy, [FromQuery] SortOrder? sortOrder, + [FromQuery] bool enableFavoriteSorting = false, [FromQuery] bool addCurrentProgram = true) { var dtoOptions = new DtoOptions() @@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers new LiveTvChannelQuery { ChannelType = type, - UserId = userId, + UserId = userId ?? Guid.Empty, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, @@ -180,9 +180,9 @@ namespace Jellyfin.Api.Controllers dtoOptions, CancellationToken.None); - var user = userId.Equals(Guid.Empty) - ? null - : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var fieldsList = dtoOptions.Fields.ToList(); fieldsList.Remove(ItemFields.CanDelete); @@ -210,9 +210,11 @@ 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] Guid channelId, [FromQuery] Guid? userId) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var item = channelId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(channelId); @@ -250,17 +252,17 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] public ActionResult> GetRecordings( - [FromQuery] string channelId, - [FromQuery] Guid userId, + [FromQuery] string? channelId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] RecordingStatus? status, [FromQuery] bool? isInProgress, - [FromQuery] string seriesTimerId, + [FromQuery] string? seriesTimerId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string fields, + [FromQuery] string? enableImageTypes, + [FromQuery] string? fields, [FromQuery] bool? enableUserData, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, @@ -279,7 +281,7 @@ namespace Jellyfin.Api.Controllers new RecordingQuery { ChannelId = channelId, - UserId = userId, + UserId = userId ?? Guid.Empty, StartIndex = startIndex, Limit = limit, Status = status, @@ -336,18 +338,18 @@ namespace Jellyfin.Api.Controllers [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableUserData", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableTotalRecordCount", Justification = "Imported from ServiceStack")] public ActionResult> GetRecordingsSeries( - [FromQuery] string channelId, - [FromQuery] Guid userId, - [FromQuery] string groupId, + [FromQuery] string? channelId, + [FromQuery] Guid? userId, + [FromQuery] string? groupId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] RecordingStatus? status, [FromQuery] bool? isInProgress, - [FromQuery] string seriesTimerId, + [FromQuery] string? seriesTimerId, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string fields, + [FromQuery] string? enableImageTypes, + [FromQuery] string? fields, [FromQuery] bool? enableUserData, [FromQuery] bool enableTotalRecordCount = true) { @@ -365,7 +367,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [Obsolete("This endpoint is obsolete.")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")] - public ActionResult> GetRecordingGroups([FromQuery] Guid userId) + public ActionResult> GetRecordingGroups([FromQuery] Guid? userId) { return new QueryResult(); } @@ -379,9 +381,11 @@ namespace Jellyfin.Api.Controllers [HttpGet("Recordings/Folders")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult> GetRecordingFolders([FromQuery] Guid userId) + public ActionResult> GetRecordingFolders([FromQuery] Guid? userId) { - var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var folders = _liveTvManager.GetRecordingFolders(user); var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user); @@ -403,9 +407,11 @@ 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] Guid recordingId, [FromQuery] Guid? userId) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var item = recordingId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId); var dtoOptions = new DtoOptions() @@ -457,7 +463,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Timers/Defaults")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public async Task> GetDefaultTimer([FromQuery] string programId) + public async Task> GetDefaultTimer([FromQuery] string? programId) { return string.IsNullOrEmpty(programId) ? await _liveTvManager.GetNewTimerDefaults(CancellationToken.None).ConfigureAwait(false) @@ -478,8 +484,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] public async Task>> GetTimers( - [FromQuery] string channelId, - [FromQuery] string seriesTimerId, + [FromQuery] string? channelId, + [FromQuery] string? seriesTimerId, [FromQuery] bool? isActive, [FromQuery] bool? isScheduled) { @@ -532,8 +538,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] public async Task>> GetPrograms( - [FromQuery] string channelIds, - [FromQuery] Guid userId, + [FromQuery] string? channelIds, + [FromQuery] Guid? userId, [FromQuery] DateTime? minStartDate, [FromQuery] bool? hasAired, [FromQuery] bool? isAiring, @@ -547,20 +553,22 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? isSports, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string sortBy, - [FromQuery] string sortOrder, - [FromQuery] string genres, - [FromQuery] string genreIds, + [FromQuery] string? sortBy, + [FromQuery] string? sortOrder, + [FromQuery] string? genres, + [FromQuery] string? genreIds, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, + [FromQuery] string? enableImageTypes, [FromQuery] bool? enableUserData, - [FromQuery] string seriesTimerId, - [FromQuery] Guid librarySeriesId, - [FromQuery] string fields, + [FromQuery] string? seriesTimerId, + [FromQuery] Guid? librarySeriesId, + [FromQuery] string? fields, [FromQuery] bool enableTotalRecordCount = true) { - var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var query = new InternalItemsQuery(user) { @@ -590,7 +598,7 @@ namespace Jellyfin.Api.Controllers { query.IsSeries = true; - if (_libraryManager.GetItemById(librarySeriesId) is Series series) + if (_libraryManager.GetItemById(librarySeriesId ?? Guid.Empty) is Series series) { query.Name = series.Name; } @@ -684,7 +692,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetRecommendedPrograms( - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery] bool? isAiring, [FromQuery] bool? hasAired, @@ -695,13 +703,15 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? isSports, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string genreIds, - [FromQuery] string fields, + [FromQuery] string? enableImageTypes, + [FromQuery] string? genreIds, + [FromQuery] string? fields, [FromQuery] bool? enableUserData, [FromQuery] bool enableTotalRecordCount = true) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var query = new InternalItemsQuery(user) { @@ -736,11 +746,11 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProgram( [FromRoute] string programId, - [FromQuery] Guid userId) + [FromQuery] Guid? userId) { - var user = userId.Equals(Guid.Empty) - ? null - : _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; return await _liveTvManager.GetProgram(programId, CancellationToken.None, user).ConfigureAwait(false); } @@ -856,12 +866,12 @@ namespace Jellyfin.Api.Controllers [HttpGet("SeriesTimers")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetSeriesTimers([FromQuery] string sortBy, [FromQuery] SortOrder sortOrder) + public async Task>> GetSeriesTimers([FromQuery] string? sortBy, [FromQuery] SortOrder? sortOrder) { return await _liveTvManager.GetSeriesTimers( new SeriesTimerQuery { - SortOrder = sortOrder, + SortOrder = sortOrder ?? SortOrder.Ascending, SortBy = sortBy }, CancellationToken.None).ConfigureAwait(false); } @@ -925,7 +935,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Obsolete("This endpoint is obsolete.")] - public ActionResult GetRecordingGroup([FromQuery] Guid groupId) + public ActionResult GetRecordingGroup([FromQuery] Guid? groupId) { return NotFound(); } @@ -966,7 +976,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("TunerHosts")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult DeleteTunerHost([FromQuery] string id) + public ActionResult DeleteTunerHost([FromQuery] string? id) { var config = _configurationManager.GetConfiguration("livetv"); config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray(); @@ -990,10 +1000,10 @@ namespace Jellyfin.Api.Controllers /// /// Adds a listings provider. /// - /// Validate login. - /// Validate listings. /// Password. /// New listings info. + /// Validate listings. + /// Validate login. /// Created listings provider returned. /// A containing the created listings provider. [HttpGet("ListingProviders")] @@ -1001,10 +1011,10 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA5350:RemoveSha1", MessageId = "AddListingProvider", Justification = "Imported from ServiceStack")] public async Task> AddListingProvider( - [FromQuery] bool validateLogin, - [FromQuery] bool validateListings, - [FromQuery] string pw, - [FromBody] ListingsProviderInfo listingsProviderInfo) + [FromQuery] string? pw, + [FromBody] ListingsProviderInfo listingsProviderInfo, + [FromQuery] bool validateListings = false, + [FromQuery] bool validateLogin = false) { using var sha = SHA1.Create(); if (!string.IsNullOrEmpty(pw)) @@ -1024,7 +1034,7 @@ namespace Jellyfin.Api.Controllers [HttpDelete("ListingProviders")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult DeleteListingProvider([FromQuery] string id) + public ActionResult DeleteListingProvider([FromQuery] string? id) { _liveTvManager.DeleteListingsProvider(id); return NoContent(); @@ -1043,10 +1053,10 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetLineups( - [FromQuery] string id, - [FromQuery] string type, - [FromQuery] string location, - [FromQuery] string country) + [FromQuery] string? id, + [FromQuery] string? type, + [FromQuery] string? location, + [FromQuery] string? country) { return await _liveTvManager.GetLineups(type, id, country, location).ConfigureAwait(false); } @@ -1079,7 +1089,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("ChannelMappingOptions")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> GetChannelMappingOptions([FromQuery] string providerId) + public async Task> GetChannelMappingOptions([FromQuery] string? providerId) { var config = _configurationManager.GetConfiguration("livetv"); @@ -1120,9 +1130,9 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> SetChannelMapping( - [FromQuery] string providerId, - [FromQuery] string tunerChannelId, - [FromQuery] string providerChannelId) + [FromQuery] string? providerId, + [FromQuery] string? tunerChannelId, + [FromQuery] string? providerChannelId) { return await _liveTvManager.SetChannelMapping(providerId, tunerChannelId, providerChannelId).ConfigureAwait(false); } @@ -1149,7 +1159,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Tuners/Discvover")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> DiscoverTuners([FromQuery] bool newDevicesOnly) + public async Task>> DiscoverTuners([FromQuery] bool newDevicesOnly = false) { return await _liveTvManager.DiscoverTuners(newDevicesOnly, CancellationToken.None).ConfigureAwait(false); } diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index daf4bf419..da400f510 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -88,7 +88,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] Guid userId) + public async Task> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery] Guid? userId) { return await GetPlaybackInfoInternal(itemId, userId, null, null).ConfigureAwait(false); } @@ -118,16 +118,16 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPostedPlaybackInfo( [FromRoute] Guid itemId, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] long? maxStreamingBitrate, [FromQuery] long? startTimeTicks, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, [FromQuery] int? maxAudioChannels, - [FromQuery] string mediaSourceId, - [FromQuery] string liveStreamId, - [FromQuery] DeviceProfile deviceProfile, - [FromQuery] bool autoOpenLiveStream, + [FromQuery] string? mediaSourceId, + [FromQuery] string? liveStreamId, + [FromQuery] DeviceProfile? deviceProfile, + [FromQuery] bool autoOpenLiveStream = false, [FromQuery] bool enableDirectPlay = true, [FromQuery] bool enableDirectStream = true, [FromQuery] bool enableTranscoding = true, @@ -165,12 +165,12 @@ namespace Jellyfin.Api.Controllers authInfo, maxStreamingBitrate ?? profile.MaxStreamingBitrate, startTimeTicks ?? 0, - mediaSourceId, + mediaSourceId ?? string.Empty, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, info!.PlaySessionId!, - userId, + userId ?? Guid.Empty, enableDirectPlay, enableDirectStream, enableTranscoding, @@ -199,7 +199,7 @@ namespace Jellyfin.Api.Controllers PlaySessionId = info.PlaySessionId, StartTimeTicks = startTimeTicks, SubtitleStreamIndex = subtitleStreamIndex, - UserId = userId, + UserId = userId ?? Guid.Empty, OpenToken = mediaSource.OpenToken }).ConfigureAwait(false); @@ -239,16 +239,16 @@ namespace Jellyfin.Api.Controllers [HttpPost("/LiveStreams/Open")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> OpenLiveStream( - [FromQuery] string openToken, - [FromQuery] Guid userId, - [FromQuery] string playSessionId, + [FromQuery] string? openToken, + [FromQuery] Guid? userId, + [FromQuery] string? playSessionId, [FromQuery] long? maxStreamingBitrate, [FromQuery] long? startTimeTicks, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, [FromQuery] int? maxAudioChannels, - [FromQuery] Guid itemId, - [FromQuery] DeviceProfile deviceProfile, + [FromQuery] Guid? itemId, + [FromQuery] DeviceProfile? deviceProfile, [FromQuery] MediaProtocol[] directPlayProtocols, [FromQuery] bool enableDirectPlay = true, [FromQuery] bool enableDirectStream = true) @@ -256,14 +256,14 @@ namespace Jellyfin.Api.Controllers var request = new LiveStreamRequest { OpenToken = openToken, - UserId = userId, + UserId = userId ?? Guid.Empty, PlaySessionId = playSessionId, MaxStreamingBitrate = maxStreamingBitrate, StartTimeTicks = startTimeTicks, AudioStreamIndex = audioStreamIndex, SubtitleStreamIndex = subtitleStreamIndex, MaxAudioChannels = maxAudioChannels, - ItemId = itemId, + ItemId = itemId ?? Guid.Empty, DeviceProfile = deviceProfile, EnableDirectPlay = enableDirectPlay, EnableDirectStream = enableDirectStream, @@ -280,7 +280,7 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("/LiveStreams/Close")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult CloseLiveStream([FromQuery] string liveStreamId) + public ActionResult CloseLiveStream([FromQuery] string? liveStreamId) { _mediaSourceManager.CloseLiveStream(liveStreamId).GetAwaiter().GetResult(); return NoContent(); @@ -325,11 +325,13 @@ namespace Jellyfin.Api.Controllers private async Task GetPlaybackInfoInternal( Guid id, - Guid userId, + Guid? userId, string? mediaSourceId = null, string? liveStreamId = null) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var item = _libraryManager.GetItemById(id); var result = new PlaybackInfoResponse(); diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index 4dd3613c6..144a7b554 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -55,32 +55,22 @@ namespace Jellyfin.Api.Controllers /// /// Optional. Filter by user id, and attach user data. /// Specify this to localize the search to a specific item or folder. Omit to use the root. - /// (Unused) Optional. include image information in output. - /// (Unused) Optional. include user data. - /// (Unused) Optional. the max number of images to return, per image type. - /// (Unused) Optional. The image types to include in the output. /// Optional. The fields to return. /// The max number of categories to return. /// The max number of items to return per category. /// Movie recommendations returned. /// The list of movie recommendations. [HttpGet("Recommendations")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImages", Justification = "Imported from ServiceStack")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableUserData", Justification = "Imported from ServiceStack")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageTypeLimit", Justification = "Imported from ServiceStack")] - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImageTypes", Justification = "Imported from ServiceStack")] public ActionResult> GetMovieRecommendations( - [FromQuery] Guid userId, - [FromQuery] string parentId, - [FromQuery] bool? enableImages, - [FromQuery] bool? enableUserData, - [FromQuery] int? imageTypeLimit, - [FromQuery] string? enableImageTypes, + [FromQuery] Guid? userId, + [FromQuery] string? parentId, [FromQuery] string? fields, [FromQuery] int categoryLimit = 5, [FromQuery] int itemLimit = 8) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request); @@ -185,7 +175,7 @@ namespace Jellyfin.Api.Controllers } private IEnumerable GetWithDirector( - User user, + User? user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, @@ -230,7 +220,7 @@ namespace Jellyfin.Api.Controllers } } - private IEnumerable GetWithActor(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetWithActor(User? user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List { nameof(Movie) }; if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) @@ -270,7 +260,7 @@ namespace Jellyfin.Api.Controllers } } - private IEnumerable GetSimilarTo(User user, IEnumerable baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetSimilarTo(User? user, IEnumerable baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List { nameof(Movie) }; if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 9ac74f199..0d319137a 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -83,31 +83,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -119,9 +119,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -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] string genreName, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); @@ -273,9 +273,9 @@ namespace Jellyfin.Api.Controllers item = _libraryManager.GetMusicGenre(genreName); } - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 03478a20a..23cc23ce7 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -80,31 +80,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -116,9 +116,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -259,7 +259,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] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions() .AddClientFields(Request); @@ -270,9 +270,9 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index d62404fc9..cf4660494 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -86,9 +86,9 @@ namespace Jellyfin.Api.Controllers public ActionResult AddToPlaylist( [FromRoute] string? playlistId, [FromQuery] string? ids, - [FromQuery] Guid userId) + [FromQuery] Guid? userId) { - _playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId); + _playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 05a6edf4e..9fcf04199 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -188,12 +188,12 @@ namespace Jellyfin.Api.Controllers /// User id. /// Item id. /// The id of the MediaSource. - /// Indicates if the client can seek. /// The audio stream index. /// The subtitle stream index. /// The play method. /// The live stream id. /// The play session id. + /// Indicates if the client can seek. /// Play start recorded. /// A . [HttpPost("/Users/{userId}/PlayingItems/{itemId}")] @@ -202,13 +202,13 @@ namespace Jellyfin.Api.Controllers public async Task OnPlaybackStart( [FromRoute] Guid userId, [FromRoute] Guid itemId, - [FromQuery] string mediaSourceId, - [FromQuery] bool canSeek, + [FromQuery] string? mediaSourceId, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, [FromQuery] PlayMethod playMethod, - [FromQuery] string liveStreamId, - [FromQuery] string playSessionId) + [FromQuery] string? liveStreamId, + [FromQuery] string playSessionId, + [FromQuery] bool canSeek = false) { var playbackStartInfo = new PlaybackStartInfo { @@ -235,8 +235,6 @@ namespace Jellyfin.Api.Controllers /// Item id. /// The id of the MediaSource. /// Optional. The current position, in ticks. 1 tick = 10000 ms. - /// Indicates if the player is paused. - /// Indicates if the player is muted. /// The audio stream index. /// The subtitle stream index. /// Scale of 0-100. @@ -244,6 +242,8 @@ namespace Jellyfin.Api.Controllers /// The live stream id. /// The play session id. /// The repeat mode. + /// Indicates if the player is paused. + /// Indicates if the player is muted. /// Play progress recorded. /// A . [HttpPost("/Users/{userId}/PlayingItems/{itemId}/Progress")] @@ -252,17 +252,17 @@ namespace Jellyfin.Api.Controllers public async Task OnPlaybackProgress( [FromRoute] Guid userId, [FromRoute] Guid itemId, - [FromQuery] string mediaSourceId, + [FromQuery] string? mediaSourceId, [FromQuery] long? positionTicks, - [FromQuery] bool isPaused, - [FromQuery] bool isMuted, [FromQuery] int? audioStreamIndex, [FromQuery] int? subtitleStreamIndex, [FromQuery] int? volumeLevel, [FromQuery] PlayMethod playMethod, - [FromQuery] string liveStreamId, + [FromQuery] string? liveStreamId, [FromQuery] string playSessionId, - [FromQuery] RepeatMode repeatMode) + [FromQuery] RepeatMode repeatMode, + [FromQuery] bool isPaused = false, + [FromQuery] bool isMuted = false) { var playbackProgressInfo = new PlaybackProgressInfo { @@ -304,11 +304,11 @@ namespace Jellyfin.Api.Controllers public async Task OnPlaybackStopped( [FromRoute] Guid userId, [FromRoute] Guid itemId, - [FromQuery] string mediaSourceId, - [FromQuery] string nextMediaType, + [FromQuery] string? mediaSourceId, + [FromQuery] string? nextMediaType, [FromQuery] long? positionTicks, - [FromQuery] string liveStreamId, - [FromQuery] string playSessionId) + [FromQuery] string? liveStreamId, + [FromQuery] string? playSessionId) { var playbackStopInfo = new PlaybackStopInfo { diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 6fff30129..1b26163cf 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string providerName, - [FromQuery] bool includeAllLanguages) + [FromQuery] bool includeAllLanguages = false) { var item = _libraryManager.GetItemById(itemId); if (item == null) diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 14dc0815c..2cbd32d2f 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -80,7 +80,7 @@ namespace Jellyfin.Api.Controllers public ActionResult Get( [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery, Required] string? searchTerm, [FromQuery] string? includeItemTypes, [FromQuery] string? excludeItemTypes, @@ -107,7 +107,7 @@ namespace Jellyfin.Api.Controllers IncludePeople = includePeople, IncludeStudios = includeStudios, StartIndex = startIndex, - UserId = userId, + UserId = userId ?? Guid.Empty, IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index bd738aa38..0c98a8e71 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -61,7 +61,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSessions( - [FromQuery] Guid controllableByUserId, + [FromQuery] Guid? controllableByUserId, [FromQuery] string? deviceId, [FromQuery] int? activeWithinSeconds) { @@ -72,15 +72,15 @@ namespace Jellyfin.Api.Controllers result = result.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase)); } - if (!controllableByUserId.Equals(Guid.Empty)) + if (controllableByUserId.HasValue && !controllableByUserId.Equals(Guid.Empty)) { result = result.Where(i => i.SupportsRemoteControl); - var user = _userManager.GetUserById(controllableByUserId); + var user = _userManager.GetUserById(controllableByUserId.Value); if (!user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) { - result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(controllableByUserId)); + result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(controllableByUserId.Value)); } if (!user.HasPermission(PermissionKind.EnableSharedDeviceControl)) @@ -371,8 +371,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? id, [FromQuery] string? playableMediaTypes, [FromQuery] string? supportedCommands, - [FromQuery] bool supportsMediaControl, - [FromQuery] bool supportsSync, + [FromQuery] bool supportsMediaControl = false, + [FromQuery] bool supportsSync = false, [FromQuery] bool supportsPersistentIdentifier = true) { if (string.IsNullOrWhiteSpace(id)) diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 76cf2febf..6f2787d93 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -82,31 +82,31 @@ namespace Jellyfin.Api.Controllers [FromQuery] double? minCommunityRating, [FromQuery] int? startIndex, [FromQuery] int? limit, - [FromQuery] string searchTerm, - [FromQuery] string parentId, - [FromQuery] string fields, - [FromQuery] string excludeItemTypes, - [FromQuery] string includeItemTypes, - [FromQuery] string filters, + [FromQuery] string? searchTerm, + [FromQuery] string? parentId, + [FromQuery] string? fields, + [FromQuery] string? excludeItemTypes, + [FromQuery] string? includeItemTypes, + [FromQuery] string? filters, [FromQuery] bool? isFavorite, - [FromQuery] string mediaTypes, - [FromQuery] string genres, - [FromQuery] string genreIds, - [FromQuery] string officialRatings, - [FromQuery] string tags, - [FromQuery] string years, + [FromQuery] string? mediaTypes, + [FromQuery] string? genres, + [FromQuery] string? genreIds, + [FromQuery] string? officialRatings, + [FromQuery] string? tags, + [FromQuery] string? years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, - [FromQuery] string enableImageTypes, - [FromQuery] string person, - [FromQuery] string personIds, - [FromQuery] string personTypes, - [FromQuery] string studios, - [FromQuery] string studioIds, - [FromQuery] Guid userId, - [FromQuery] string nameStartsWithOrGreater, - [FromQuery] string nameStartsWith, - [FromQuery] string nameLessThan, + [FromQuery] string? enableImageTypes, + [FromQuery] string? person, + [FromQuery] string? personIds, + [FromQuery] string? personTypes, + [FromQuery] string? studios, + [FromQuery] string? studioIds, + [FromQuery] Guid? userId, + [FromQuery] string? nameStartsWithOrGreater, + [FromQuery] string? nameStartsWith, + [FromQuery] string? nameLessThan, [FromQuery] bool? enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { @@ -118,9 +118,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -259,14 +259,14 @@ 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] string name, [FromQuery] Guid? userId) { var dtoOptions = new DtoOptions().AddClientFields(Request); var item = _libraryManager.GetStudio(name); - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index baedafaa6..1c38b8de5 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -190,8 +190,8 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] int index, [FromRoute, Required] string? format, [FromQuery] long? endPositionTicks, - [FromQuery] bool copyTimestamps, - [FromQuery] bool addVttTimeMap, + [FromQuery] bool copyTimestamps = false, + [FromQuery] bool addVttTimeMap = false, [FromRoute] long startPositionTicks = 0) { if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index e1a99a138..bf3c1e2b1 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -44,9 +44,9 @@ namespace Jellyfin.Api.Controllers /// The user id. /// The media types. /// The type. - /// Whether to enable the total record count. /// Optional. The start index. /// Optional. The limit. + /// Whether to enable the total record count. /// Suggestions returned. /// A with the suggestions. [HttpGet("/Users/{userId}/Suggestions")] @@ -55,9 +55,9 @@ namespace Jellyfin.Api.Controllers [FromRoute] Guid userId, [FromQuery] string? mediaType, [FromQuery] string? type, - [FromQuery] bool enableTotalRecordCount, [FromQuery] int? startIndex, - [FromQuery] int? limit) + [FromQuery] int? limit, + [FromQuery] bool enableTotalRecordCount = false) { var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null; diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index bd65abd50..645495551 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("/Trailers")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetTrailers( - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeVideo, diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 80b6a2488..e5b043621 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] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? fields, @@ -93,12 +93,14 @@ namespace Jellyfin.Api.Controllers ParentId = parentId, SeriesId = seriesId, StartIndex = startIndex, - UserId = userId, + UserId = userId ?? Guid.Empty, EnableTotalRecordCount = enableTotalRecordCount }, options); - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user); @@ -125,7 +127,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Upcoming")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetUpcomingEpisodes( - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] string? fields, @@ -135,7 +137,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes, [FromQuery] bool? enableUserData) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1); @@ -191,7 +195,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetEpisodes( [FromRoute] string? seriesId, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] string? fields, [FromQuery] int? season, [FromQuery] string? seasonId, @@ -206,7 +210,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableUserData, [FromQuery] string? sortBy) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; List episodes; @@ -312,7 +318,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetSeasons( [FromRoute] string? seriesId, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] string? fields, [FromQuery] bool? isSpecialSeason, [FromQuery] bool? isMissing, @@ -322,7 +328,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? enableImageTypes, [FromQuery] bool? enableUserData) { - var user = _userManager.GetUserById(userId); + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; if (!(_libraryManager.GetItemById(seriesId) is Series series)) { diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index ca804ebc9..cedda3b9d 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -180,7 +180,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] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool? likes) { return UpdateUserItemRatingInternal(userId, itemId, likes); } @@ -264,7 +264,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetLatestMedia( [FromRoute] Guid userId, - [FromQuery] Guid parentId, + [FromQuery] Guid? parentId, [FromQuery] string? fields, [FromQuery] string? includeItemTypes, [FromQuery] bool? isPlayed, @@ -297,7 +297,7 @@ namespace Jellyfin.Api.Controllers IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), IsPlayed = isPlayed, Limit = limit, - ParentId = parentId, + ParentId = parentId ?? Guid.Empty, UserId = userId, }, dtoOptions); diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index ad8927262..f4bd451ef 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -56,8 +56,8 @@ namespace Jellyfin.Api.Controllers /// /// User id. /// Whether or not to include external views such as channels or live tv. - /// Whether or not to include hidden content. /// Preset views. + /// Whether or not to include hidden content. /// User views returned. /// An containing the user views. [HttpGet("/Users/{userId}/Views")] @@ -65,8 +65,8 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetUserViews( [FromRoute] Guid userId, [FromQuery] bool? includeExternalContent, - [FromQuery] bool includeHidden, - [FromQuery] string? presetViews) + [FromQuery] string? presetViews, + [FromQuery] bool includeHidden = false) { var query = new UserViewQuery { diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index fb1141984..e2a44427b 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -53,9 +53,11 @@ 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] Guid itemId, [FromQuery] Guid? userId) { - var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null; + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; var item = itemId.Equals(Guid.Empty) ? (!userId.Equals(Guid.Empty) diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index a66a3951e..d09b016a9 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery] string? enableImageTypes, - [FromQuery] Guid userId, + [FromQuery] Guid? userId, [FromQuery] bool recursive = true, [FromQuery] bool? enableImages = true) { @@ -86,9 +86,9 @@ namespace Jellyfin.Api.Controllers User? user = null; BaseItem parentItem; - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - user = _userManager.GetUserById(userId); + user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else @@ -176,7 +176,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] int year, [FromQuery] Guid? userId) { var item = _libraryManager.GetYear(year); if (item == null) @@ -187,9 +187,9 @@ namespace Jellyfin.Api.Controllers var dtoOptions = new DtoOptions() .AddClientFields(Request); - if (!userId.Equals(Guid.Empty)) + if (userId.HasValue && !userId.Equals(Guid.Empty)) { - var user = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId.Value); return _dtoService.GetBaseItemDto(item, dtoOptions, user); } diff --git a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs index fd0c31504..b922e76cf 100644 --- a/Jellyfin.Api/Helpers/SimilarItemsHelper.cs +++ b/Jellyfin.Api/Helpers/SimilarItemsHelper.cs @@ -4,7 +4,6 @@ using System.Linq; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; @@ -21,14 +20,16 @@ namespace Jellyfin.Api.Helpers IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService, - Guid userId, + Guid? userId, string id, string? excludeArtistIds, int? limit, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) { - var user = !userId.Equals(Guid.Empty) ? userManager.GetUserById(userId) : null; + var user = userId.HasValue && !userId.Equals(Guid.Empty) + ? userManager.GetUserById(userId.Value) + : null; var item = string.IsNullOrEmpty(id) ? (!userId.Equals(Guid.Empty) ? libraryManager.GetUserRootFolder() : @@ -38,11 +39,10 @@ namespace Jellyfin.Api.Helpers { IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(), Recursive = true, - DtoOptions = dtoOptions + DtoOptions = dtoOptions, + ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds) }; - query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds); - var inputItems = libraryManager.GetItemList(query); var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore) -- cgit v1.2.3 From 8f6c2e767906c1d4c62d51ae2e66af1a78edde9a Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 4 Aug 2020 08:27:54 -0600 Subject: Remove leading slash from route attributes --- .../Services/SwaggerService.cs | 287 --------------------- Jellyfin.Api/Controllers/ActivityLogController.cs | 2 +- Jellyfin.Api/Controllers/ApiKeyController.cs | 2 +- Jellyfin.Api/Controllers/ArtistsController.cs | 2 +- Jellyfin.Api/Controllers/CollectionController.cs | 2 +- Jellyfin.Api/Controllers/ItemRefreshController.cs | 3 +- .../Controllers/LibraryStructureController.cs | 2 +- Jellyfin.Api/Controllers/SearchController.cs | 2 +- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Controllers/TimeSyncController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 2 +- Jellyfin.Api/Controllers/UserController.cs | 2 +- 12 files changed, 11 insertions(+), 299 deletions(-) delete mode 100644 Emby.Server.Implementations/Services/SwaggerService.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs deleted file mode 100644 index 4f011a678..000000000 --- a/Emby.Server.Implementations/Services/SwaggerService.cs +++ /dev/null @@ -1,287 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Linq; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Services; - -namespace Emby.Server.Implementations.Services -{ - [Route("/swagger", "GET", Summary = "Gets the swagger specifications")] - [Route("/swagger.json", "GET", Summary = "Gets the swagger specifications")] - public class GetSwaggerSpec : IReturn - { - } - - public class SwaggerSpec - { - public string swagger { get; set; } - - public string[] schemes { get; set; } - - public SwaggerInfo info { get; set; } - - public string host { get; set; } - - public string basePath { get; set; } - - public SwaggerTag[] tags { get; set; } - - public IDictionary> paths { get; set; } - - public Dictionary definitions { get; set; } - - public SwaggerComponents components { get; set; } - } - - public class SwaggerComponents - { - public Dictionary securitySchemes { get; set; } - } - - public class SwaggerSecurityScheme - { - public string name { get; set; } - - public string type { get; set; } - - public string @in { get; set; } - } - - public class SwaggerInfo - { - public string description { get; set; } - - public string version { get; set; } - - public string title { get; set; } - - public string termsOfService { get; set; } - - public SwaggerConcactInfo contact { get; set; } - } - - public class SwaggerConcactInfo - { - public string email { get; set; } - - public string name { get; set; } - - public string url { get; set; } - } - - public class SwaggerTag - { - public string description { get; set; } - - public string name { get; set; } - } - - public class SwaggerMethod - { - public string summary { get; set; } - - public string description { get; set; } - - public string[] tags { get; set; } - - public string operationId { get; set; } - - public string[] consumes { get; set; } - - public string[] produces { get; set; } - - public SwaggerParam[] parameters { get; set; } - - public Dictionary responses { get; set; } - - public Dictionary[] security { get; set; } - } - - public class SwaggerParam - { - public string @in { get; set; } - - public string name { get; set; } - - public string description { get; set; } - - public bool required { get; set; } - - public string type { get; set; } - - public string collectionFormat { get; set; } - } - - public class SwaggerResponse - { - public string description { get; set; } - - // ex. "$ref":"#/definitions/Pet" - public Dictionary schema { get; set; } - } - - public class SwaggerDefinition - { - public string type { get; set; } - - public Dictionary properties { get; set; } - } - - public class SwaggerProperty - { - public string type { get; set; } - - public string format { get; set; } - - public string description { get; set; } - - public string[] @enum { get; set; } - - public string @default { get; set; } - } - - public class SwaggerService : IService, IRequiresRequest - { - private readonly IHttpServer _httpServer; - private SwaggerSpec _spec; - - public IRequest Request { get; set; } - - public SwaggerService(IHttpServer httpServer) - { - _httpServer = httpServer; - } - - public object Get(GetSwaggerSpec request) - { - return _spec ?? (_spec = GetSpec()); - } - - private SwaggerSpec GetSpec() - { - string host = null; - Uri uri; - if (Uri.TryCreate(Request.RawUrl, UriKind.Absolute, out uri)) - { - host = uri.Host; - } - - var securitySchemes = new Dictionary(); - - securitySchemes["api_key"] = new SwaggerSecurityScheme - { - name = "api_key", - type = "apiKey", - @in = "query" - }; - - var spec = new SwaggerSpec - { - schemes = new[] { "http" }, - tags = GetTags(), - swagger = "2.0", - info = new SwaggerInfo - { - title = "Jellyfin Server API", - version = "1.0.0", - description = "Explore the Jellyfin Server API", - contact = new SwaggerConcactInfo - { - name = "Jellyfin Community", - url = "https://jellyfin.readthedocs.io/en/latest/user-docs/getting-help/" - } - }, - paths = GetPaths(), - definitions = GetDefinitions(), - basePath = "/jellyfin", - host = host, - - components = new SwaggerComponents - { - securitySchemes = securitySchemes - } - }; - - return spec; - } - - - private SwaggerTag[] GetTags() - { - return Array.Empty(); - } - - private Dictionary GetDefinitions() - { - return new Dictionary(); - } - - private IDictionary> GetPaths() - { - var paths = new SortedDictionary>(); - - // REVIEW: this can be done better - var all = ((HttpListenerHost)_httpServer).ServiceController.RestPathMap.OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase).ToList(); - - foreach (var current in all) - { - foreach (var info in current.Value) - { - if (info.IsHidden) - { - continue; - } - - if (info.Path.StartsWith("/mediabrowser", StringComparison.OrdinalIgnoreCase) - || info.Path.StartsWith("/jellyfin", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - paths[info.Path] = GetPathInfo(info); - } - } - - return paths; - } - - private Dictionary GetPathInfo(RestPath info) - { - var result = new Dictionary(); - - foreach (var verb in info.Verbs) - { - var responses = new Dictionary - { - { "200", new SwaggerResponse { description = "OK" } } - }; - - var apiKeySecurity = new Dictionary - { - { "api_key", Array.Empty() } - }; - - result[verb.ToLowerInvariant()] = new SwaggerMethod - { - summary = info.Summary, - description = info.Description, - produces = new[] { "application/json" }, - consumes = new[] { "application/json" }, - operationId = info.RequestType.Name, - tags = Array.Empty(), - - parameters = Array.Empty(), - - responses = responses, - - security = new[] { apiKeySecurity } - }; - } - - return result; - } - } -} diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs index 12ea24973..a07cea9c0 100644 --- a/Jellyfin.Api/Controllers/ActivityLogController.cs +++ b/Jellyfin.Api/Controllers/ActivityLogController.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Api.Controllers /// /// Activity log controller. /// - [Route("/System/ActivityLog")] + [Route("System/ActivityLog")] [Authorize(Policy = Policies.RequiresElevation)] public class ActivityLogController : BaseJellyfinApiController { diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index fef4d7262..ccb7f47f0 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Api.Controllers /// /// Authentication controller. /// - [Route("/Auth")] + [Route("Auth")] public class ApiKeyController : BaseJellyfinApiController { private readonly ISessionManager _sessionManager; diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index d39021446..9d1010803 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -19,7 +19,7 @@ namespace Jellyfin.Api.Controllers /// The artists controller. /// [Authorize(Policy = Policies.DefaultAuthorization)] - [Route("/Artists")] + [Route("Artists")] public class ArtistsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 6f78a7d84..1e8426df4 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -16,7 +16,7 @@ namespace Jellyfin.Api.Controllers /// The collection controller. /// [Authorize(Policy = Policies.DefaultAuthorization)] - [Route("/Collections")] + [Route("Collections")] public class CollectionController : BaseJellyfinApiController { private readonly ICollectionManager _collectionManager; diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs index 4697d869d..3f5d305c1 100644 --- a/Jellyfin.Api/Controllers/ItemRefreshController.cs +++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs @@ -13,8 +13,7 @@ namespace Jellyfin.Api.Controllers /// /// Item Refresh Controller. /// - /// [Authenticated] - [Route("/Items")] + [Route("Items")] [Authorize(Policy = Policies.DefaultAuthorization)] public class ItemRefreshController : BaseJellyfinApiController { diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index 827879e0a..ca150f3f2 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Api.Controllers /// /// The library structure controller. /// - [Route("/Library/VirtualFolders")] + [Route("Library/VirtualFolders")] [Authorize(Policy = Policies.FirstTimeSetupOrElevated)] public class LibraryStructureController : BaseJellyfinApiController { diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 2cbd32d2f..e159a9666 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Api.Controllers /// /// Search controller. /// - [Route("/Search/Hints")] + [Route("Search/Hints")] [Authorize(Policy = Policies.DefaultAuthorization)] public class SearchController : BaseJellyfinApiController { diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e0bce3a41..6f9a75e2f 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Api.Controllers /// /// The system controller. /// - [Route("/System")] + [Route("System")] public class SystemController : BaseJellyfinApiController { private readonly IServerApplicationHost _appHost; diff --git a/Jellyfin.Api/Controllers/TimeSyncController.cs b/Jellyfin.Api/Controllers/TimeSyncController.cs index 57a720b26..bbabcd6e6 100644 --- a/Jellyfin.Api/Controllers/TimeSyncController.cs +++ b/Jellyfin.Api/Controllers/TimeSyncController.cs @@ -9,7 +9,7 @@ namespace Jellyfin.Api.Controllers /// /// The time sync controller. /// - [Route("/GetUtcTime")] + [Route("GetUtcTime")] public class TimeSyncController : BaseJellyfinApiController { /// diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 508b5e24e..d4560dfa2 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -22,7 +22,7 @@ namespace Jellyfin.Api.Controllers /// /// The tv shows controller. /// - [Route("/Shows")] + [Route("Shows")] [Authorize(Policy = Policies.DefaultAuthorization)] public class TvShowsController : BaseJellyfinApiController { diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index ce0c9281b..482baf641 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -27,7 +27,7 @@ namespace Jellyfin.Api.Controllers /// /// User controller. /// - [Route("/Users")] + [Route("Users")] public class UserController : BaseJellyfinApiController { private readonly IUserManager _userManager; -- 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/SearchController.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 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/SearchController.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 3cc0dd7e12380a7e4a0ef86591890ece8421b14c Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 16 Nov 2020 20:29:46 -0700 Subject: Reduce RequestHelpers.Split usage and remove RequestHelpers.GetGuids usage. --- .../Channels/ChannelManager.cs | 2 +- .../Data/SqliteItemRepository.cs | 8 +- .../Library/LibraryManager.cs | 2 +- .../Playlists/PlaylistManager.cs | 6 +- Jellyfin.Api/Controllers/ArtistsController.cs | 100 +++++---- Jellyfin.Api/Controllers/CollectionController.cs | 17 +- Jellyfin.Api/Controllers/GenresController.cs | 10 +- Jellyfin.Api/Controllers/ItemsController.cs | 103 +++++----- Jellyfin.Api/Controllers/LibraryController.cs | 13 +- Jellyfin.Api/Controllers/LiveTvController.cs | 28 ++- Jellyfin.Api/Controllers/MusicGenresController.cs | 10 +- Jellyfin.Api/Controllers/PersonsController.cs | 8 +- Jellyfin.Api/Controllers/PlaylistsController.cs | 13 +- Jellyfin.Api/Controllers/SearchController.cs | 13 +- Jellyfin.Api/Controllers/SessionController.cs | 8 +- Jellyfin.Api/Controllers/StudiosController.cs | 13 +- Jellyfin.Api/Controllers/SuggestionsController.cs | 9 +- Jellyfin.Api/Controllers/TrailersController.cs | 38 ++-- .../Controllers/UniversalAudioController.cs | 8 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 4 +- Jellyfin.Api/Controllers/UserViewsController.cs | 7 +- Jellyfin.Api/Controllers/VideosController.cs | 5 +- Jellyfin.Api/Controllers/YearsController.cs | 18 +- Jellyfin.Api/Helpers/RequestHelpers.cs | 43 ---- .../ModelBinders/PipeDelimitedArrayModelBinder.cs | 90 ++++++++ Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs | 9 +- .../Models/PlaylistDtos/CreatePlaylistDto.cs | 6 +- .../Converters/JsonPipeDelimitedArrayConverter.cs | 74 +++++++ .../JsonPipeDelimitedArrayConverterFactory.cs | 28 +++ MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 6 +- .../Entities/InternalItemsQuery.cs | 6 +- .../Entities/UserViewBuilder.cs | 4 +- .../Playlists/IPlaylistManager.cs | 2 +- .../Playlists/PlaylistCreationRequest.cs | 8 +- .../PipeDelimitedArrayModelBinderTests.cs | 226 +++++++++++++++++++++ 36 files changed, 659 insertions(+), 288 deletions(-) create mode 100644 Jellyfin.Api/ModelBinders/PipeDelimitedArrayModelBinder.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverter.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonPipeDelimitedArrayConverterFactory.cs create mode 100644 tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 19045b72b..3d97a6ca8 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -634,7 +634,7 @@ namespace Emby.Server.Implementations.Channels { var channels = GetAllChannels().Where(i => i is ISupportsLatestMedia).ToArray(); - if (query.ChannelIds.Length > 0) + if (query.ChannelIds.Count > 0) { // Avoid implicitly captured closure var ids = query.ChannelIds; diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 638c7a9b4..7e01bd4b6 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -3611,12 +3611,12 @@ namespace Emby.Server.Implementations.Data whereClauses.Add($"type in ({inClause})"); } - if (query.ChannelIds.Length == 1) + if (query.ChannelIds.Count == 1) { whereClauses.Add("ChannelId=@ChannelId"); statement?.TryBind("@ChannelId", query.ChannelIds[0].ToString("N", CultureInfo.InvariantCulture)); } - else if (query.ChannelIds.Length > 1) + else if (query.ChannelIds.Count > 1) { var inClause = string.Join(",", query.ChannelIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'")); whereClauses.Add($"ChannelId in ({inClause})"); @@ -4076,7 +4076,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add(clause); } - if (query.GenreIds.Length > 0) + if (query.GenreIds.Count > 0) { var clauses = new List(); var index = 0; @@ -4097,7 +4097,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add(clause); } - if (query.Genres.Length > 0) + if (query.Genres.Count > 0) { var clauses = new List(); var index = 0; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 8ab5e4aef..03bf1c874 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1503,7 +1503,7 @@ namespace Emby.Server.Implementations.Library { if (query.AncestorIds.Length == 0 && query.ParentId.Equals(Guid.Empty) && - query.ChannelIds.Length == 0 && + query.ChannelIds.Count == 0 && query.TopParentIds.Length == 0 && string.IsNullOrEmpty(query.AncestorWithPresentationUniqueKey) && string.IsNullOrEmpty(query.SeriesPresentationUniqueKey) && diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index d3b64fb31..932f721ab 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -150,7 +150,7 @@ namespace Emby.Server.Implementations.Playlists await playlist.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ForceSave = true }, CancellationToken.None) .ConfigureAwait(false); - if (options.ItemIdList.Length > 0) + if (options.ItemIdList.Count > 0) { await AddToPlaylistInternal(playlist.Id, options.ItemIdList, user, new DtoOptions(false) { @@ -184,7 +184,7 @@ namespace Emby.Server.Implementations.Playlists return Playlist.GetPlaylistItems(playlistMediaType, items, user, options); } - public Task AddToPlaylistAsync(Guid playlistId, ICollection itemIds, Guid userId) + public Task AddToPlaylistAsync(Guid playlistId, IReadOnlyCollection itemIds, Guid userId) { var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); @@ -194,7 +194,7 @@ namespace Emby.Server.Implementations.Playlists }); } - private async Task AddToPlaylistInternal(Guid playlistId, ICollection newItemIds, User user, DtoOptions options) + private async Task AddToPlaylistInternal(Guid playlistId, IReadOnlyCollection newItemIds, User user, DtoOptions options) { // Retrieve the existing playlist var playlist = _libraryManager.GetItemById(playlistId) as Playlist diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 9bad206e0..0123bb8fa 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -89,24 +89,24 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery] string? mediaTypes, - [FromQuery] string? genres, - [FromQuery] string? genreIds, - [FromQuery] string? officialRatings, - [FromQuery] string? tags, - [FromQuery] string? years, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery] string? personIds, - [FromQuery] string? personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery] string? studios, - [FromQuery] string? studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, @@ -131,30 +131,26 @@ namespace Jellyfin.Api.Controllers parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.RootFolder : _libraryManager.GetItemById(parentId); } - var excludeItemTypesArr = RequestHelpers.Split(excludeItemTypes, ',', true); - var includeItemTypesArr = RequestHelpers.Split(includeItemTypes, ',', true); - var mediaTypesArr = RequestHelpers.Split(mediaTypes, ',', true); - var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypesArr, - IncludeItemTypes = includeItemTypesArr, - MediaTypes = mediaTypesArr, + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, + MediaTypes = mediaTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, NameLessThan = nameLessThan, NameStartsWith = nameStartsWith, NameStartsWithOrGreater = nameStartsWithOrGreater, - Tags = RequestHelpers.Split(tags, '|', true), - OfficialRatings = RequestHelpers.Split(officialRatings, '|', true), - Genres = RequestHelpers.Split(genres, '|', true), - GenreIds = RequestHelpers.GetGuids(genreIds), - StudioIds = RequestHelpers.GetGuids(studioIds), + Tags = tags, + OfficialRatings = officialRatings, + Genres = genres, + GenreIds = genreIds, + StudioIds = studioIds, Person = person, - PersonIds = RequestHelpers.GetGuids(personIds), - PersonTypes = RequestHelpers.Split(personTypes, ',', true), - Years = RequestHelpers.Split(years, ',', true).Select(int.Parse).ToArray(), + PersonIds = personIds, + PersonTypes = personTypes, + Years = years, MinCommunityRating = minCommunityRating, DtoOptions = dtoOptions, SearchTerm = searchTerm, @@ -230,7 +226,7 @@ namespace Jellyfin.Api.Controllers var (baseItem, itemCounts) = i; var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user); - if (!string.IsNullOrWhiteSpace(includeItemTypes)) + if (includeItemTypes.Length != 0) { dto.ChildCount = itemCounts.ItemCount; dto.ProgramCount = itemCounts.ProgramCount; @@ -297,24 +293,24 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery] string? mediaTypes, - [FromQuery] string? genres, - [FromQuery] string? genreIds, - [FromQuery] string? officialRatings, - [FromQuery] string? tags, - [FromQuery] string? years, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery] string? personIds, - [FromQuery] string? personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery] string? studios, - [FromQuery] string? studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, [FromQuery] Guid? userId, [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, @@ -339,30 +335,26 @@ namespace Jellyfin.Api.Controllers parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.RootFolder : _libraryManager.GetItemById(parentId); } - var excludeItemTypesArr = RequestHelpers.Split(excludeItemTypes, ',', true); - var includeItemTypesArr = RequestHelpers.Split(includeItemTypes, ',', true); - var mediaTypesArr = RequestHelpers.Split(mediaTypes, ',', true); - var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypesArr, - IncludeItemTypes = includeItemTypesArr, - MediaTypes = mediaTypesArr, + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, + MediaTypes = mediaTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, NameLessThan = nameLessThan, NameStartsWith = nameStartsWith, NameStartsWithOrGreater = nameStartsWithOrGreater, - Tags = RequestHelpers.Split(tags, '|', true), - OfficialRatings = RequestHelpers.Split(officialRatings, '|', true), - Genres = RequestHelpers.Split(genres, '|', true), - GenreIds = RequestHelpers.GetGuids(genreIds), - StudioIds = RequestHelpers.GetGuids(studioIds), + Tags = tags, + OfficialRatings = officialRatings, + Genres = genres, + GenreIds = genreIds, + StudioIds = studioIds, Person = person, - PersonIds = RequestHelpers.GetGuids(personIds), - PersonTypes = RequestHelpers.Split(personTypes, ',', true), - Years = RequestHelpers.Split(years, ',', true).Select(int.Parse).ToArray(), + PersonIds = personIds, + PersonTypes = personTypes, + Years = years, MinCommunityRating = minCommunityRating, DtoOptions = dtoOptions, SearchTerm = searchTerm, @@ -438,7 +430,7 @@ namespace Jellyfin.Api.Controllers var (baseItem, itemCounts) = i; var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user); - if (!string.IsNullOrWhiteSpace(includeItemTypes)) + if (includeItemTypes.Length != 0) { dto.ChildCount = itemCounts.ItemCount; dto.ProgramCount = itemCounts.ProgramCount; diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index eae06b767..2a342c2cb 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Net; @@ -54,7 +55,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateCollection( [FromQuery] string? name, - [FromQuery] string? ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] ids, [FromQuery] Guid? parentId, [FromQuery] bool isLocked = false) { @@ -65,7 +66,7 @@ namespace Jellyfin.Api.Controllers IsLocked = isLocked, Name = name, ParentId = parentId, - ItemIdList = RequestHelpers.Split(ids, ',', true), + ItemIdList = ids, UserIds = new[] { userId } }).ConfigureAwait(false); @@ -88,9 +89,11 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpPost("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task AddToCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string ids) + public async Task AddToCollection( + [FromRoute, Required] Guid collectionId, + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) { - await _collectionManager.AddToCollectionAsync(collectionId, RequestHelpers.GetGuids(ids)).ConfigureAwait(true); + await _collectionManager.AddToCollectionAsync(collectionId, ids).ConfigureAwait(true); return NoContent(); } @@ -103,9 +106,11 @@ namespace Jellyfin.Api.Controllers /// A indicating success. [HttpDelete("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task RemoveFromCollection([FromRoute, Required] Guid collectionId, [FromQuery, Required] string ids) + public async Task RemoveFromCollection( + [FromRoute, Required] Guid collectionId, + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids) { - await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(ids)).ConfigureAwait(false); + await _collectionManager.RemoveFromCollectionAsync(collectionId, ids).ConfigureAwait(false); return NoContent(); } } diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 9c222135d..2dd504770 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -74,8 +74,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, @@ -96,8 +96,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, @@ -133,7 +133,7 @@ namespace Jellyfin.Api.Controllers result = _libraryManager.GetGenres(query); } - var shouldIncludeItemTypes = !string.IsNullOrEmpty(includeItemTypes); + var shouldIncludeItemTypes = includeItemTypes.Length != 0; return RequestHelpers.CreateQueryResult(result, dtoOptions, _dtoService, shouldIncludeItemTypes, user); } diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index d8d371ebc..cff06aafe 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -173,7 +173,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? hasImdbId, [FromQuery] bool? hasTmdbId, [FromQuery] bool? hasTvdbId, - [FromQuery] string? excludeItemIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeItemIds, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? recursive, @@ -181,34 +181,34 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? sortOrder, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery] string? mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery] string? personIds, - [FromQuery] string? personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery] string? studios, [FromQuery] string? artists, - [FromQuery] string? excludeArtistIds, - [FromQuery] string? artistIds, - [FromQuery] string? albumArtistIds, - [FromQuery] string? contributingArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] artistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] contributingArtistIds, [FromQuery] string? albums, - [FromQuery] string? albumIds, - [FromQuery] string? ids, - [FromQuery] string? videoTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] VideoType[] videoTypes, [FromQuery] string? minOfficialRating, [FromQuery] bool? isLocked, [FromQuery] bool? isPlaceHolder, @@ -223,8 +223,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery] string? studioIds, - [FromQuery] string? genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { @@ -238,8 +238,9 @@ namespace Jellyfin.Api.Controllers .AddClientFields(Request) .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); - if (string.Equals(includeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) + if (includeItemTypes.Length == 1 + && (includeItemTypes[0].Equals("Playlist", StringComparison.OrdinalIgnoreCase) + || includeItemTypes[0].Equals("BoxSet", StringComparison.OrdinalIgnoreCase))) { parentId = null; } @@ -262,7 +263,7 @@ namespace Jellyfin.Api.Controllers && string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) { recursive = true; - includeItemTypes = "Playlist"; + includeItemTypes = new[] { "Playlist" }; } bool isInEnabledFolder = user!.GetPreference(PreferenceKind.EnabledFolders).Any(i => new Guid(i) == item.Id) @@ -291,14 +292,14 @@ namespace Jellyfin.Api.Controllers return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}."); } - if ((recursive.HasValue && recursive.Value) || !string.IsNullOrEmpty(ids) || !(item is UserRootFolder)) + if ((recursive.HasValue && recursive.Value) || ids.Length != 0 || !(item is UserRootFolder)) { var query = new InternalItemsQuery(user!) { IsPlayed = isPlayed, - MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), - ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), + MediaTypes = mediaTypes, + IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = excludeItemTypes, Recursive = recursive ?? false, OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder), IsFavorite = isFavorite, @@ -330,28 +331,28 @@ namespace Jellyfin.Api.Controllers HasTrailer = hasTrailer, IsHD = isHd, Is4K = is4K, - Tags = RequestHelpers.Split(tags, '|', true), - OfficialRatings = RequestHelpers.Split(officialRatings, '|', true), - Genres = RequestHelpers.Split(genres, '|', true), - ArtistIds = RequestHelpers.GetGuids(artistIds), - AlbumArtistIds = RequestHelpers.GetGuids(albumArtistIds), - ContributingArtistIds = RequestHelpers.GetGuids(contributingArtistIds), - GenreIds = RequestHelpers.GetGuids(genreIds), - StudioIds = RequestHelpers.GetGuids(studioIds), + Tags = tags, + OfficialRatings = officialRatings, + Genres = genres, + ArtistIds = artistIds, + AlbumArtistIds = albumArtistIds, + ContributingArtistIds = contributingArtistIds, + GenreIds = genreIds, + StudioIds = studioIds, Person = person, - PersonIds = RequestHelpers.GetGuids(personIds), - PersonTypes = RequestHelpers.Split(personTypes, ',', true), - Years = RequestHelpers.Split(years, ',', true).Select(int.Parse).ToArray(), + PersonIds = personIds, + PersonTypes = personTypes, + Years = years, ImageTypes = imageTypes, - VideoTypes = RequestHelpers.Split(videoTypes, ',', true).Select(v => Enum.Parse(v, true)).ToArray(), + VideoTypes = videoTypes, AdjacentTo = adjacentTo, - ItemIds = RequestHelpers.GetGuids(ids), + ItemIds = ids, MinCommunityRating = minCommunityRating, MinCriticRating = minCriticRating, ParentId = string.IsNullOrWhiteSpace(parentId) ? Guid.Empty : new Guid(parentId), ParentIndexNumber = parentIndexNumber, EnableTotalRecordCount = enableTotalRecordCount, - ExcludeItemIds = RequestHelpers.GetGuids(excludeItemIds), + ExcludeItemIds = excludeItemIds, DtoOptions = dtoOptions, SearchTerm = searchTerm, MinDateLastSaved = minDateLastSaved?.ToUniversalTime(), @@ -360,7 +361,7 @@ namespace Jellyfin.Api.Controllers MaxPremiereDate = maxPremiereDate?.ToUniversalTime(), }; - if (!string.IsNullOrWhiteSpace(ids) || !string.IsNullOrWhiteSpace(searchTerm)) + if (ids.Length != 0 || !string.IsNullOrWhiteSpace(searchTerm)) { query.CollapseBoxSetItems = false; } @@ -449,14 +450,14 @@ namespace Jellyfin.Api.Controllers } // ExcludeArtistIds - if (!string.IsNullOrWhiteSpace(excludeArtistIds)) + if (excludeArtistIds.Length != 0) { - query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds); + query.ExcludeArtistIds = excludeArtistIds; } - if (!string.IsNullOrWhiteSpace(albumIds)) + if (albumIds.Length != 0) { - query.AlbumIds = RequestHelpers.GetGuids(albumIds); + query.AlbumIds = albumIds; } // Albums @@ -533,12 +534,12 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { @@ -569,13 +570,13 @@ namespace Jellyfin.Api.Controllers ParentId = parentIdGuid, Recursive = true, DtoOptions = dtoOptions, - MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), + MediaTypes = mediaTypes, IsVirtualItem = false, CollapseBoxSetItems = false, EnableTotalRecordCount = enableTotalRecordCount, AncestorIds = ancestorIds, - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), - ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), + IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = excludeItemTypes, SearchTerm = searchTerm }); diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 1b115d800..3ff77e8e0 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -362,15 +362,14 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] - public ActionResult DeleteItems([FromQuery] string? ids) + public ActionResult DeleteItems([FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] ids) { - if (string.IsNullOrEmpty(ids)) + if (ids.Length == 0) { return NoContent(); } - var itemIds = RequestHelpers.Split(ids, ',', true); - foreach (var i in itemIds) + foreach (var i in ids) { var item = _libraryManager.GetItemById(i); var auth = _authContext.GetAuthorizationInfo(Request); @@ -691,7 +690,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarItems( [FromRoute, Required] Guid itemId, - [FromQuery] string? excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, [FromQuery] Guid? userId, [FromQuery] int? limit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields) @@ -753,9 +752,9 @@ namespace Jellyfin.Api.Controllers }; // ExcludeArtistIds - if (!string.IsNullOrEmpty(excludeArtistIds)) + if (excludeArtistIds.Length != 0) { - query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds); + query.ExcludeArtistIds = excludeArtistIds; } List itemsResult = _libraryManager.GetItemList(query); diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 29c0f1df4..eb8b42b34 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -150,7 +150,7 @@ namespace Jellyfin.Api.Controllers [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, - [FromQuery] string? sortBy, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy, [FromQuery] SortOrder? sortOrder, [FromQuery] bool enableFavoriteSorting = false, [FromQuery] bool addCurrentProgram = true) @@ -175,7 +175,7 @@ namespace Jellyfin.Api.Controllers IsNews = isNews, IsKids = isKids, IsSports = isSports, - SortBy = RequestHelpers.Split(sortBy, ',', true), + SortBy = sortBy, SortOrder = sortOrder ?? SortOrder.Ascending, AddCurrentProgram = addCurrentProgram }, @@ -539,7 +539,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] public async Task>> GetLiveTvPrograms( - [FromQuery] string? channelIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] channelIds, [FromQuery] Guid? userId, [FromQuery] DateTime? minStartDate, [FromQuery] bool? hasAired, @@ -556,8 +556,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? limit, [FromQuery] string? sortBy, [FromQuery] string? sortOrder, - [FromQuery] string? genres, - [FromQuery] string? genreIds, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, @@ -573,8 +573,7 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ChannelIds = RequestHelpers.Split(channelIds, ',', true) - .Select(i => new Guid(i)).ToArray(), + ChannelIds = channelIds, HasAired = hasAired, IsAiring = isAiring, EnableTotalRecordCount = enableTotalRecordCount, @@ -591,8 +590,8 @@ namespace Jellyfin.Api.Controllers IsKids = isKids, IsSports = isSports, SeriesTimerId = seriesTimerId, - Genres = RequestHelpers.Split(genres, '|', true), - GenreIds = RequestHelpers.GetGuids(genreIds) + Genres = genres, + GenreIds = genreIds }; if (librarySeriesId != null && !librarySeriesId.Equals(Guid.Empty)) @@ -628,8 +627,7 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ChannelIds = RequestHelpers.Split(body.ChannelIds, ',', true) - .Select(i => new Guid(i)).ToArray(), + ChannelIds = body.ChannelIds, HasAired = body.HasAired, IsAiring = body.IsAiring, EnableTotalRecordCount = body.EnableTotalRecordCount, @@ -646,8 +644,8 @@ namespace Jellyfin.Api.Controllers IsKids = body.IsKids, IsSports = body.IsSports, SeriesTimerId = body.SeriesTimerId, - Genres = RequestHelpers.Split(body.Genres, '|', true), - GenreIds = RequestHelpers.GetGuids(body.GenreIds) + Genres = body.Genres, + GenreIds = body.GenreIds }; if (!body.LibrarySeriesId.Equals(Guid.Empty)) @@ -703,7 +701,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery] string? genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery] bool? enableUserData, [FromQuery] bool enableTotalRecordCount = true) @@ -723,7 +721,7 @@ namespace Jellyfin.Api.Controllers IsNews = isNews, IsSports = isSports, EnableTotalRecordCount = enableTotalRecordCount, - GenreIds = RequestHelpers.GetGuids(genreIds) + GenreIds = genreIds }; var dtoOptions = new DtoOptions { Fields = fields } diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 229d9ff02..8c6104302 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -74,8 +74,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, @@ -96,8 +96,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, @@ -123,7 +123,7 @@ namespace Jellyfin.Api.Controllers var result = _libraryManager.GetMusicGenres(query); - var shouldIncludeItemTypes = !string.IsNullOrWhiteSpace(includeItemTypes); + var shouldIncludeItemTypes = includeItemTypes.Length != 0; return RequestHelpers.CreateQueryResult(result, dtoOptions, _dtoService, shouldIncludeItemTypes, user); } diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 6ac3e6417..9dc79b388 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -77,8 +77,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery] string? excludePersonTypes, - [FromQuery] string? personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludePersonTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery] string? appearsInItemId, [FromQuery] Guid? userId, [FromQuery] bool? enableImages = true) @@ -97,8 +97,8 @@ namespace Jellyfin.Api.Controllers var isFavoriteInFilters = filters.Any(f => f == ItemFilter.IsFavorite); var peopleItems = _libraryManager.GetPeopleItems(new InternalPeopleQuery { - PersonTypes = RequestHelpers.Split(personTypes, ',', true), - ExcludePersonTypes = RequestHelpers.Split(excludePersonTypes, ',', true), + PersonTypes = personTypes, + ExcludePersonTypes = excludePersonTypes, NameContains = searchTerm, User = user, IsFavorite = !isFavorite.HasValue && isFavoriteInFilters ? true : isFavorite, diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 4b3d8d3d3..bc47ecbd1 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -63,11 +63,10 @@ namespace Jellyfin.Api.Controllers public async Task> CreatePlaylist( [FromBody, Required] CreatePlaylistDto createPlaylistRequest) { - Guid[] idGuidArray = RequestHelpers.GetGuids(createPlaylistRequest.Ids); var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest { Name = createPlaylistRequest.Name, - ItemIdList = idGuidArray, + ItemIdList = createPlaylistRequest.Ids, UserId = createPlaylistRequest.UserId, MediaType = createPlaylistRequest.MediaType }).ConfigureAwait(false); @@ -87,10 +86,10 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task AddToPlaylist( [FromRoute, Required] Guid playlistId, - [FromQuery] string? ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, [FromQuery] Guid? userId) { - await _playlistManager.AddToPlaylistAsync(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty).ConfigureAwait(false); + await _playlistManager.AddToPlaylistAsync(playlistId, ids, userId ?? Guid.Empty).ConfigureAwait(false); return NoContent(); } @@ -122,9 +121,11 @@ 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, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] entryIds) { - await _playlistManager.RemoveFromPlaylistAsync(playlistId, RequestHelpers.Split(entryIds, ',', true)).ConfigureAwait(false); + await _playlistManager.RemoveFromPlaylistAsync(playlistId, entryIds).ConfigureAwait(false); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index e75f0d06b..076fe58f1 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -82,9 +83,9 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? limit, [FromQuery] Guid? userId, [FromQuery, Required] string searchTerm, - [FromQuery] string? includeItemTypes, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery] string? parentId, [FromQuery] bool? isMovie, [FromQuery] bool? isSeries, @@ -108,9 +109,9 @@ namespace Jellyfin.Api.Controllers IncludeStudios = includeStudios, StartIndex = startIndex, UserId = userId ?? Guid.Empty, - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), - ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), - MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), + IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = excludeItemTypes, + MediaTypes = mediaTypes, ParentId = parentId, IsKids = isKids, diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index e506ac7bf..6c9b9050e 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -160,12 +160,12 @@ namespace Jellyfin.Api.Controllers public ActionResult Play( [FromRoute, Required] string sessionId, [FromQuery, Required] PlayCommand playCommand, - [FromQuery, Required] string itemIds, + [FromQuery, Required, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] itemIds, [FromQuery] long? startPositionTicks) { var playRequest = new PlayRequest { - ItemIds = RequestHelpers.GetGuids(itemIds), + ItemIds = itemIds, StartPositionTicks = startPositionTicks, PlayCommand = playCommand }; @@ -378,7 +378,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostCapabilities( [FromQuery] string? id, - [FromQuery] string? playableMediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] playableMediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] GeneralCommandType[] supportedCommands, [FromQuery] bool supportsMediaControl = false, [FromQuery] bool supportsSync = false, @@ -391,7 +391,7 @@ namespace Jellyfin.Api.Controllers _sessionManager.ReportCapabilities(id, new ClientCapabilities { - PlayableMediaTypes = RequestHelpers.Split(playableMediaTypes, ',', true), + PlayableMediaTypes = playableMediaTypes, SupportedCommands = supportedCommands, SupportsMediaControl = supportsMediaControl, SupportsSync = supportsSync, diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index 27dcd51bc..af28b4f59 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -73,8 +73,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -94,13 +94,10 @@ namespace Jellyfin.Api.Controllers var parentItem = _libraryManager.GetParentItem(parentId, userId); - var excludeItemTypesArr = RequestHelpers.Split(excludeItemTypes, ',', true); - var includeItemTypesArr = RequestHelpers.Split(includeItemTypes, ',', true); - var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypesArr, - IncludeItemTypes = includeItemTypesArr, + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, @@ -125,7 +122,7 @@ namespace Jellyfin.Api.Controllers } var result = _libraryManager.GetStudios(query); - var shouldIncludeItemTypes = !string.IsNullOrEmpty(includeItemTypes); + var shouldIncludeItemTypes = includeItemTypes.Length != 0; return RequestHelpers.CreateQueryResult(result, dtoOptions, _dtoService, shouldIncludeItemTypes, user); } diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index ad64adfba..69292186e 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -4,6 +4,7 @@ using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -58,8 +59,8 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSuggestions( [FromRoute, Required] Guid userId, - [FromQuery] string? mediaType, - [FromQuery] string? type, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaType, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] type, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool enableTotalRecordCount = false) @@ -70,8 +71,8 @@ namespace Jellyfin.Api.Controllers var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(), - MediaTypes = RequestHelpers.Split(mediaType!, ',', true), - IncludeItemTypes = RequestHelpers.Split(type!, ',', true), + MediaTypes = mediaType, + IncludeItemTypes = type, IsVirtualItem = false, StartIndex = startIndex, Limit = limit, diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index d78adcbcd..f09a6a91a 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -139,7 +139,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? hasImdbId, [FromQuery] bool? hasTmdbId, [FromQuery] bool? hasTvdbId, - [FromQuery] string? excludeItemIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeItemIds, [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] bool? recursive, @@ -147,33 +147,33 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? sortOrder, [FromQuery] string? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, - [FromQuery] string? mediaTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] 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, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, + [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery] string? person, - [FromQuery] string? personIds, - [FromQuery] string? personTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery] string? studios, [FromQuery] string? artists, - [FromQuery] string? excludeArtistIds, - [FromQuery] string? artistIds, - [FromQuery] string? albumArtistIds, - [FromQuery] string? contributingArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] excludeArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] artistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumArtistIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] contributingArtistIds, [FromQuery] string? albums, - [FromQuery] string? albumIds, - [FromQuery] string? ids, - [FromQuery] string? videoTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] albumIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] ids, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] VideoType[] videoTypes, [FromQuery] string? minOfficialRating, [FromQuery] bool? isLocked, [FromQuery] bool? isPlaceHolder, @@ -188,12 +188,12 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? nameStartsWithOrGreater, [FromQuery] string? nameStartsWith, [FromQuery] string? nameLessThan, - [FromQuery] string? studioIds, - [FromQuery] string? genreIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { - var includeItemTypes = "Trailer"; + var includeItemTypes = new[] { "Trailer" }; return _itemsController .GetItems( diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index e10f1fe91..5141aebca 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Devices; @@ -96,7 +97,7 @@ namespace Jellyfin.Api.Controllers [ProducesAudioFile] public async Task GetUniversalAudioStream( [FromRoute, Required] Guid itemId, - [FromQuery] string? container, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] container, [FromQuery] string? mediaSourceId, [FromQuery] string? deviceId, [FromQuery] Guid? userId, @@ -258,7 +259,7 @@ namespace Jellyfin.Api.Controllers } private DeviceProfile GetDeviceProfile( - string? container, + string[] containers, string? transcodingContainer, string? audioCodec, string? transcodingProtocol, @@ -270,7 +271,6 @@ namespace Jellyfin.Api.Controllers { var deviceProfile = new DeviceProfile(); - var containers = RequestHelpers.Split(container, ',', true); int len = containers.Length; var directPlayProfiles = new DirectPlayProfile[len]; for (int i = 0; i < len; i++) @@ -327,7 +327,7 @@ namespace Jellyfin.Api.Controllers if (conditions.Count > 0) { // codec profile - codecProfiles.Add(new CodecProfile { Type = CodecType.Audio, Container = container, Conditions = conditions.ToArray() }); + codecProfiles.Add(new CodecProfile { Type = CodecType.Audio, Container = string.Join(',', containers), Conditions = conditions.ToArray() }); } deviceProfile.CodecProfiles = codecProfiles.ToArray(); diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index cfd851129..a7fb4f116 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -269,7 +269,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid userId, [FromQuery] Guid? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery] string? includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, [FromQuery] bool? isPlayed, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, @@ -296,7 +296,7 @@ namespace Jellyfin.Api.Controllers new LatestItemsQuery { GroupItems = groupItems, - IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), + IncludeItemTypes = includeItemTypes, IsPlayed = isPlayed, Limit = limit, ParentId = parentId ?? Guid.Empty, diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index d575bfc3b..60fd1df01 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.UserViewDtos; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -67,7 +68,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetUserViews( [FromRoute, Required] Guid userId, [FromQuery] bool? includeExternalContent, - [FromQuery] string? presetViews, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] presetViews, [FromQuery] bool includeHidden = false) { var query = new UserViewQuery @@ -81,9 +82,9 @@ namespace Jellyfin.Api.Controllers query.IncludeExternalContent = includeExternalContent.Value; } - if (!string.IsNullOrWhiteSpace(presetViews)) + if (presetViews.Length != 0) { - query.PresetViews = RequestHelpers.Split(presetViews, ',', true); + query.PresetViews = presetViews; } var app = _authContext.GetAuthorizationInfo(Request).Client ?? string.Empty; diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 4de7aac71..dd5e70a50 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -10,6 +10,7 @@ using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; @@ -203,9 +204,9 @@ 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, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] itemIds) { - var items = RequestHelpers.Split(itemIds, ',', true) + var items = itemIds .Select(i => _libraryManager.GetItemById(i)) .OfType