From f17d198eb5643f551973b1e54405a472fe0b55b2 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 19 Jun 2020 22:18:46 +0200 Subject: Move SuggestionsService to Jellyfin.Api --- Jellyfin.Api/Controllers/SuggestionsController.cs | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Jellyfin.Api/Controllers/SuggestionsController.cs (limited to 'Jellyfin.Api/Controllers/SuggestionsController.cs') diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs new file mode 100644 index 000000000..2d6445c30 --- /dev/null +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -0,0 +1,86 @@ +using System; +using System.Linq; +using Jellyfin.Api.Extensions; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// + /// The suggestions controller. + /// + public class SuggestionsController : BaseJellyfinApiController + { + private readonly IDtoService _dtoService; + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public SuggestionsController( + IDtoService dtoService, + IUserManager userManager, + ILibraryManager libraryManager) + { + _dtoService = dtoService; + _userManager = userManager; + _libraryManager = libraryManager; + } + + /// + /// Gets suggestions. + /// + /// The user id. + /// The media types. + /// The type. + /// Whether to enable the total record count. + /// Optional. The start index. + /// Optional. The limit. + /// Suggestions returned. + /// A with the suggestions. + [HttpGet("/Users/{userId}/Suggestions")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult> GetSuggestions( + [FromRoute] Guid userId, + [FromQuery] string? mediaType, + [FromQuery] string? type, + [FromQuery] bool enableTotalRecordCount, + [FromQuery] int? startIndex, + [FromQuery] int? limit) + { + var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null; + + var dtoOptions = new DtoOptions().AddClientFields(Request); + var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user) + { + OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(), + MediaTypes = (mediaType ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), + IncludeItemTypes = (type ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), + IsVirtualItem = false, + StartIndex = startIndex, + Limit = limit, + DtoOptions = dtoOptions, + EnableTotalRecordCount = enableTotalRecordCount, + Recursive = true + }); + + var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user); + + return new QueryResult + { + TotalRecordCount = result.TotalRecordCount, + Items = dtoList + }; + } + } +} -- cgit v1.2.3 From 33de0ac10880a941a10f28c64f18253cc711b8da Mon Sep 17 00:00:00 2001 From: David Date: Sat, 20 Jun 2020 12:10:45 +0200 Subject: Use RequestHelpers.Split --- Jellyfin.Api/Controllers/SuggestionsController.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Api/Controllers/SuggestionsController.cs') diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 2d6445c30..e1a99a138 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -64,8 +65,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 = (mediaType ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), - IncludeItemTypes = (type ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), + MediaTypes = RequestHelpers.Split(mediaType!, ',', true), + IncludeItemTypes = RequestHelpers.Split(type!, ',', true), IsVirtualItem = false, StartIndex = startIndex, Limit = limit, -- 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/SuggestionsController.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 dbeeb7cf4a715580432232c7098e4d86afccb37c Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 3 Aug 2020 12:01:24 -0600 Subject: fix merge conflicts --- .../Controllers/DisplayPreferencesController.cs | 133 +++++++++++++-- Jellyfin.Api/Controllers/MoviesController.cs | 1 + Jellyfin.Api/Controllers/SubtitleController.cs | 15 +- Jellyfin.Api/Controllers/SuggestionsController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 2 +- Jellyfin.Api/Controllers/UserController.cs | 2 +- .../DisplayPreferencesDto.cs | 106 ++++++++++++ MediaBrowser.Api/DisplayPreferencesService.cs | 189 --------------------- 8 files changed, 236 insertions(+), 214 deletions(-) create mode 100644 Jellyfin.Api/Models/DisplayPreferencesDtos/DisplayPreferencesDto.cs delete mode 100644 MediaBrowser.Api/DisplayPreferencesService.cs (limited to 'Jellyfin.Api/Controllers/SuggestionsController.cs') diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 1255e6dab..62f6097f3 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -1,8 +1,12 @@ +using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; -using System.Threading; +using System.Globalization; +using System.Linq; using Jellyfin.Api.Constants; -using MediaBrowser.Controller.Persistence; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller; using MediaBrowser.Model.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -17,15 +21,15 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] public class DisplayPreferencesController : BaseJellyfinApiController { - private readonly IDisplayPreferencesRepository _displayPreferencesRepository; + private readonly IDisplayPreferencesManager _displayPreferencesManager; /// /// Initializes a new instance of the class. /// - /// Instance of interface. - public DisplayPreferencesController(IDisplayPreferencesRepository displayPreferencesRepository) + /// Instance of interface. + public DisplayPreferencesController(IDisplayPreferencesManager displayPreferencesManager) { - _displayPreferencesRepository = displayPreferencesRepository; + _displayPreferencesManager = displayPreferencesManager; } /// @@ -38,12 +42,47 @@ namespace Jellyfin.Api.Controllers /// An containing the display preferences on success, or a if the display preferences could not be found. [HttpGet("{displayPreferencesId}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult GetDisplayPreferences( + [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] + public ActionResult GetDisplayPreferences( [FromRoute] string? displayPreferencesId, - [FromQuery] [Required] string? userId, + [FromQuery] [Required] Guid userId, [FromQuery] [Required] string? client) { - return _displayPreferencesRepository.GetDisplayPreferences(displayPreferencesId, userId, client); + var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, client); + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client); + + var dto = new DisplayPreferencesDto + { + Client = displayPreferences.Client, + Id = displayPreferences.UserId.ToString(), + ViewType = itemPreferences.ViewType.ToString(), + SortBy = itemPreferences.SortBy, + SortOrder = itemPreferences.SortOrder, + IndexBy = displayPreferences.IndexBy?.ToString(), + RememberIndexing = itemPreferences.RememberIndexing, + RememberSorting = itemPreferences.RememberSorting, + ScrollDirection = displayPreferences.ScrollDirection, + ShowBackdrop = displayPreferences.ShowBackdrop, + ShowSidebar = displayPreferences.ShowSidebar + }; + + foreach (var homeSection in displayPreferences.HomeSections) + { + dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); + } + + foreach (var itemDisplayPreferences in _displayPreferencesManager.ListItemDisplayPreferences(displayPreferences.UserId, displayPreferences.Client)) + { + dto.CustomPrefs["landing-" + itemDisplayPreferences.ItemId] = itemDisplayPreferences.ViewType.ToString().ToLowerInvariant(); + } + + dto.CustomPrefs["chromecastVersion"] = displayPreferences.ChromecastVersion.ToString().ToLowerInvariant(); + dto.CustomPrefs["skipForwardLength"] = displayPreferences.SkipForwardLength.ToString(CultureInfo.InvariantCulture); + dto.CustomPrefs["skipBackLength"] = displayPreferences.SkipBackwardLength.ToString(CultureInfo.InvariantCulture); + dto.CustomPrefs["enableNextVideoInfoOverlay"] = displayPreferences.EnableNextVideoInfoOverlay.ToString(CultureInfo.InvariantCulture); + dto.CustomPrefs["tvhome"] = displayPreferences.TvHome; + + return dto; } /// @@ -60,15 +99,77 @@ namespace Jellyfin.Api.Controllers [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")] public ActionResult UpdateDisplayPreferences( [FromRoute] string? displayPreferencesId, - [FromQuery, BindRequired] string? userId, + [FromQuery, BindRequired] Guid userId, [FromQuery, BindRequired] string? client, - [FromBody, BindRequired] DisplayPreferences displayPreferences) + [FromBody, BindRequired] DisplayPreferencesDto displayPreferences) { - _displayPreferencesRepository.SaveDisplayPreferences( - displayPreferences, - userId, - client, - CancellationToken.None); + HomeSectionType[] defaults = + { + HomeSectionType.SmallLibraryTiles, + HomeSectionType.Resume, + HomeSectionType.ResumeAudio, + HomeSectionType.LiveTv, + HomeSectionType.NextUp, + HomeSectionType.LatestMedia, HomeSectionType.None, + }; + + var existingDisplayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, client); + existingDisplayPreferences.IndexBy = Enum.TryParse(displayPreferences.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; + existingDisplayPreferences.ShowBackdrop = displayPreferences.ShowBackdrop; + existingDisplayPreferences.ShowSidebar = displayPreferences.ShowSidebar; + + existingDisplayPreferences.ScrollDirection = displayPreferences.ScrollDirection; + existingDisplayPreferences.ChromecastVersion = displayPreferences.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion) + ? Enum.Parse(chromecastVersion, true) + : ChromecastVersion.Stable; + existingDisplayPreferences.EnableNextVideoInfoOverlay = displayPreferences.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enableNextVideoInfoOverlay) + ? bool.Parse(enableNextVideoInfoOverlay) + : true; + existingDisplayPreferences.SkipBackwardLength = displayPreferences.CustomPrefs.TryGetValue("skipBackLength", out var skipBackLength) + ? int.Parse(skipBackLength, CultureInfo.InvariantCulture) + : 10000; + existingDisplayPreferences.SkipForwardLength = displayPreferences.CustomPrefs.TryGetValue("skipForwardLength", out var skipForwardLength) + ? int.Parse(skipForwardLength, CultureInfo.InvariantCulture) + : 30000; + existingDisplayPreferences.DashboardTheme = displayPreferences.CustomPrefs.TryGetValue("dashboardTheme", out var theme) + ? theme + : string.Empty; + existingDisplayPreferences.TvHome = displayPreferences.CustomPrefs.TryGetValue("tvhome", out var home) + ? home + : string.Empty; + existingDisplayPreferences.HomeSections.Clear(); + + foreach (var key in displayPreferences.CustomPrefs.Keys.Where(key => key.StartsWith("homesection", StringComparison.OrdinalIgnoreCase))) + { + var order = int.Parse(key.AsSpan().Slice("homesection".Length)); + if (!Enum.TryParse(displayPreferences.CustomPrefs[key], true, out var type)) + { + type = order < 7 ? defaults[order] : HomeSectionType.None; + } + + existingDisplayPreferences.HomeSections.Add(new HomeSection { Order = order, Type = type }); + } + + foreach (var key in displayPreferences.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.OrdinalIgnoreCase))) + { + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Parse(key.Substring("landing-".Length)), existingDisplayPreferences.Client); + itemPreferences.ViewType = Enum.Parse(displayPreferences.ViewType); + _displayPreferencesManager.SaveChanges(itemPreferences); + } + + var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Empty, existingDisplayPreferences.Client); + itemPrefs.SortBy = displayPreferences.SortBy; + itemPrefs.SortOrder = displayPreferences.SortOrder; + itemPrefs.RememberIndexing = displayPreferences.RememberIndexing; + itemPrefs.RememberSorting = displayPreferences.RememberSorting; + + if (Enum.TryParse(displayPreferences.ViewType, true, out var viewType)) + { + itemPrefs.ViewType = viewType; + } + + _displayPreferencesManager.SaveChanges(existingDisplayPreferences); + _displayPreferencesManager.SaveChanges(itemPrefs); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index a9af1a2c3..148d8a18e 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -5,6 +5,7 @@ using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 1c38b8de5..b62ff80fc 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -276,11 +276,12 @@ namespace Jellyfin.Api.Controllers throw new ArgumentException("segmentLength was not given, or it was given incorrectly. (It should be bigger than 0)"); } - builder.AppendLine("#EXTM3U"); - builder.AppendLine("#EXT-X-TARGETDURATION:" + segmentLength.ToString(CultureInfo.InvariantCulture)); - builder.AppendLine("#EXT-X-VERSION:3"); - builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0"); - builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD"); + builder.AppendLine("#EXTM3U") + .Append("#EXT-X-TARGETDURATION:") + .AppendLine(segmentLength.ToString(CultureInfo.InvariantCulture)) + .AppendLine("#EXT-X-VERSION:3") + .AppendLine("#EXT-X-MEDIA-SEQUENCE:0") + .AppendLine("#EXT-X-PLAYLIST-TYPE:VOD"); long positionTicks = 0; @@ -291,7 +292,9 @@ namespace Jellyfin.Api.Controllers var remaining = runtime - positionTicks; var lengthTicks = Math.Min(remaining, segmentLengthTicks); - builder.AppendLine("#EXTINF:" + TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture) + ","); + builder.Append("#EXTINF:") + .Append(TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture)) + .AppendLine(","); var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index bf3c1e2b1..55759f316 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -2,11 +2,11 @@ using System.Linq; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index d54bc10c0..508b5e24e 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -11,7 +12,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 8038ca044..ce0c9281b 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -455,7 +455,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateUserByName([FromBody] CreateUserByName request) { - var newUser = _userManager.CreateUser(request.Name); + var newUser = await _userManager.CreateUserAsync(request.Name).ConfigureAwait(false); // no need to authenticate password for new user if (request.Password != null) diff --git a/Jellyfin.Api/Models/DisplayPreferencesDtos/DisplayPreferencesDto.cs b/Jellyfin.Api/Models/DisplayPreferencesDtos/DisplayPreferencesDto.cs new file mode 100644 index 000000000..249d828d3 --- /dev/null +++ b/Jellyfin.Api/Models/DisplayPreferencesDtos/DisplayPreferencesDto.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Api.Models.DisplayPreferencesDtos +{ + /// + /// Defines the display preferences for any item that supports them (usually Folders). + /// + public class DisplayPreferencesDto + { + /// + /// Initializes a new instance of the class. + /// + public DisplayPreferencesDto() + { + RememberIndexing = false; + PrimaryImageHeight = 250; + PrimaryImageWidth = 250; + ShowBackdrop = true; + CustomPrefs = new Dictionary(); + } + + /// + /// Gets or sets the user id. + /// + /// The user id. + public string? Id { get; set; } + + /// + /// Gets or sets the type of the view. + /// + /// The type of the view. + public string? ViewType { get; set; } + + /// + /// Gets or sets the sort by. + /// + /// The sort by. + public string? SortBy { get; set; } + + /// + /// Gets or sets the index by. + /// + /// The index by. + public string? IndexBy { get; set; } + + /// + /// Gets or sets a value indicating whether [remember indexing]. + /// + /// true if [remember indexing]; otherwise, false. + public bool RememberIndexing { get; set; } + + /// + /// Gets or sets the height of the primary image. + /// + /// The height of the primary image. + public int PrimaryImageHeight { get; set; } + + /// + /// Gets or sets the width of the primary image. + /// + /// The width of the primary image. + public int PrimaryImageWidth { get; set; } + + /// + /// Gets the custom prefs. + /// + /// The custom prefs. + public Dictionary CustomPrefs { get; } + + /// + /// Gets or sets the scroll direction. + /// + /// The scroll direction. + public ScrollDirection ScrollDirection { get; set; } + + /// + /// Gets or sets a value indicating whether to show backdrops on this item. + /// + /// true if showing backdrops; otherwise, false. + public bool ShowBackdrop { get; set; } + + /// + /// Gets or sets a value indicating whether [remember sorting]. + /// + /// true if [remember sorting]; otherwise, false. + public bool RememberSorting { get; set; } + + /// + /// Gets or sets the sort order. + /// + /// The sort order. + public SortOrder SortOrder { get; set; } + + /// + /// Gets or sets a value indicating whether [show sidebar]. + /// + /// true if [show sidebar]; otherwise, false. + public bool ShowSidebar { get; set; } + + /// + /// Gets or sets the client. + /// + public string? Client { get; set; } + } +} diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs deleted file mode 100644 index 559b71efc..000000000 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System; -using System.Linq; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api -{ - /// - /// Class UpdateDisplayPreferences. - /// - [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")] - public class UpdateDisplayPreferences : DisplayPreferencesDto, IReturnVoid - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "DisplayPreferencesId", Description = "DisplayPreferences Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string DisplayPreferencesId { get; set; } - - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string UserId { get; set; } - } - - [Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")] - public class GetDisplayPreferences : IReturn - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string UserId { get; set; } - - [ApiMember(Name = "Client", Description = "Client", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string Client { get; set; } - } - - /// - /// Class DisplayPreferencesService. - /// - [Authenticated] - public class DisplayPreferencesService : BaseApiService - { - /// - /// The display preferences manager. - /// - private readonly IDisplayPreferencesManager _displayPreferencesManager; - - /// - /// Initializes a new instance of the class. - /// - /// The display preferences manager. - public DisplayPreferencesService( - ILogger logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - IDisplayPreferencesManager displayPreferencesManager) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _displayPreferencesManager = displayPreferencesManager; - } - - /// - /// Gets the specified request. - /// - /// The request. - public object Get(GetDisplayPreferences request) - { - var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client); - - var dto = new DisplayPreferencesDto - { - Client = displayPreferences.Client, - Id = displayPreferences.UserId.ToString(), - ViewType = itemPreferences.ViewType.ToString(), - SortBy = itemPreferences.SortBy, - SortOrder = itemPreferences.SortOrder, - IndexBy = displayPreferences.IndexBy?.ToString(), - RememberIndexing = itemPreferences.RememberIndexing, - RememberSorting = itemPreferences.RememberSorting, - ScrollDirection = displayPreferences.ScrollDirection, - ShowBackdrop = displayPreferences.ShowBackdrop, - ShowSidebar = displayPreferences.ShowSidebar - }; - - foreach (var homeSection in displayPreferences.HomeSections) - { - dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); - } - - foreach (var itemDisplayPreferences in _displayPreferencesManager.ListItemDisplayPreferences(displayPreferences.UserId, displayPreferences.Client)) - { - dto.CustomPrefs["landing-" + itemDisplayPreferences.ItemId] = itemDisplayPreferences.ViewType.ToString().ToLowerInvariant(); - } - - dto.CustomPrefs["chromecastVersion"] = displayPreferences.ChromecastVersion.ToString().ToLowerInvariant(); - dto.CustomPrefs["skipForwardLength"] = displayPreferences.SkipForwardLength.ToString(); - dto.CustomPrefs["skipBackLength"] = displayPreferences.SkipBackwardLength.ToString(); - dto.CustomPrefs["enableNextVideoInfoOverlay"] = displayPreferences.EnableNextVideoInfoOverlay.ToString(); - dto.CustomPrefs["tvhome"] = displayPreferences.TvHome; - - return ToOptimizedResult(dto); - } - - /// - /// Posts the specified request. - /// - /// The request. - public void Post(UpdateDisplayPreferences request) - { - HomeSectionType[] defaults = - { - HomeSectionType.SmallLibraryTiles, - HomeSectionType.Resume, - HomeSectionType.ResumeAudio, - HomeSectionType.LiveTv, - HomeSectionType.NextUp, - HomeSectionType.LatestMedia, - HomeSectionType.None, - }; - - var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - - prefs.IndexBy = Enum.TryParse(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; - prefs.ShowBackdrop = request.ShowBackdrop; - prefs.ShowSidebar = request.ShowSidebar; - - prefs.ScrollDirection = request.ScrollDirection; - prefs.ChromecastVersion = request.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion) - ? Enum.Parse(chromecastVersion, true) - : ChromecastVersion.Stable; - prefs.EnableNextVideoInfoOverlay = request.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enableNextVideoInfoOverlay) - ? bool.Parse(enableNextVideoInfoOverlay) - : true; - prefs.SkipBackwardLength = request.CustomPrefs.TryGetValue("skipBackLength", out var skipBackLength) ? int.Parse(skipBackLength) : 10000; - prefs.SkipForwardLength = request.CustomPrefs.TryGetValue("skipForwardLength", out var skipForwardLength) ? int.Parse(skipForwardLength) : 30000; - prefs.DashboardTheme = request.CustomPrefs.TryGetValue("dashboardTheme", out var theme) ? theme : string.Empty; - prefs.TvHome = request.CustomPrefs.TryGetValue("tvhome", out var home) ? home : string.Empty; - prefs.HomeSections.Clear(); - - foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("homesection"))) - { - var order = int.Parse(key.AsSpan().Slice("homesection".Length)); - if (!Enum.TryParse(request.CustomPrefs[key], true, out var type)) - { - type = order < 7 ? defaults[order] : HomeSectionType.None; - } - - prefs.HomeSections.Add(new HomeSection - { - Order = order, - Type = type - }); - } - - foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("landing-"))) - { - var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Parse(key.Substring("landing-".Length)), prefs.Client); - itemPreferences.ViewType = Enum.Parse(request.ViewType); - _displayPreferencesManager.SaveChanges(itemPreferences); - } - - var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Empty, prefs.Client); - itemPrefs.SortBy = request.SortBy; - itemPrefs.SortOrder = request.SortOrder; - itemPrefs.RememberIndexing = request.RememberIndexing; - itemPrefs.RememberSorting = request.RememberSorting; - - if (Enum.TryParse(request.ViewType, true, out var viewType)) - { - itemPrefs.ViewType = viewType; - } - - _displayPreferencesManager.SaveChanges(prefs); - _displayPreferencesManager.SaveChanges(itemPrefs); - } - } -} -- cgit v1.2.3 From 858aecd409914f6a9ca6f86445ec20c8bacc0b59 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 4 Aug 2020 12:48:53 -0600 Subject: Fix all route for base url support --- Jellyfin.Api/Controllers/AlbumsController.cs | 5 +- Jellyfin.Api/Controllers/DashboardController.cs | 11 +++-- Jellyfin.Api/Controllers/DynamicHlsController.cs | 17 ++++--- Jellyfin.Api/Controllers/FilterController.cs | 5 +- Jellyfin.Api/Controllers/HlsSegmentController.cs | 11 +++-- Jellyfin.Api/Controllers/ImageController.cs | 57 +++++++++++----------- Jellyfin.Api/Controllers/InstantMixController.cs | 15 +++--- Jellyfin.Api/Controllers/ItemLookupController.cs | 25 +++++----- Jellyfin.Api/Controllers/ItemUpdateController.cs | 7 +-- Jellyfin.Api/Controllers/ItemsController.cs | 7 +-- Jellyfin.Api/Controllers/LibraryController.cs | 51 +++++++++---------- Jellyfin.Api/Controllers/MediaInfoController.cs | 11 +++-- Jellyfin.Api/Controllers/PackageController.cs | 14 +++--- Jellyfin.Api/Controllers/PlaystateController.cs | 19 ++++---- Jellyfin.Api/Controllers/PluginsController.cs | 2 +- Jellyfin.Api/Controllers/SessionController.cs | 33 +++++++------ Jellyfin.Api/Controllers/SubtitleController.cs | 15 +++--- Jellyfin.Api/Controllers/SuggestionsController.cs | 3 +- Jellyfin.Api/Controllers/TrailersController.cs | 2 +- .../Controllers/UniversalAudioController.cs | 9 ++-- Jellyfin.Api/Controllers/UserController.cs | 2 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 21 ++++---- Jellyfin.Api/Controllers/UserViewsController.cs | 5 +- Jellyfin.Api/Controllers/VideoHlsController.cs | 5 +- 24 files changed, 186 insertions(+), 166 deletions(-) (limited to 'Jellyfin.Api/Controllers/SuggestionsController.cs') diff --git a/Jellyfin.Api/Controllers/AlbumsController.cs b/Jellyfin.Api/Controllers/AlbumsController.cs index 01ba7fc32..190d4bd07 100644 --- a/Jellyfin.Api/Controllers/AlbumsController.cs +++ b/Jellyfin.Api/Controllers/AlbumsController.cs @@ -17,6 +17,7 @@ namespace Jellyfin.Api.Controllers /// /// The albums controller. /// + [Route("")] public class AlbumsController : BaseJellyfinApiController { private readonly IUserManager _userManager; @@ -48,7 +49,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of records to return. /// Similar albums returned. /// A with similar albums. - [HttpGet("/Albums/{albumId}/Similar")] + [HttpGet("Albums/{albumId}/Similar")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarAlbums( [FromRoute] string albumId, @@ -80,7 +81,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of records to return. /// Similar artists returned. /// A with similar artists. - [HttpGet("/Artists/{artistId}/Similar")] + [HttpGet("Artists/{artistId}/Similar")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarArtists( [FromRoute] string artistId, diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index e033c50d5..a7bdb24f6 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -20,6 +20,7 @@ namespace Jellyfin.Api.Controllers /// /// The dashboard controller. /// + [Route("")] public class DashboardController : BaseJellyfinApiController { private readonly ILogger _logger; @@ -64,7 +65,7 @@ namespace Jellyfin.Api.Controllers /// ConfigurationPages returned. /// Server still loading. /// An with infos about the plugins. - [HttpGet("/web/ConfigurationPages")] + [HttpGet("web/ConfigurationPages")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetConfigurationPages( @@ -118,7 +119,7 @@ namespace Jellyfin.Api.Controllers /// ConfigurationPage returned. /// Plugin configuration page not found. /// The configuration page. - [HttpGet("/web/ConfigurationPage")] + [HttpGet("web/ConfigurationPage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetDashboardConfigurationPage([FromQuery] string? name) @@ -172,7 +173,7 @@ namespace Jellyfin.Api.Controllers /// /// Robots.txt returned. /// The robots.txt. - [HttpGet("/robots.txt")] + [HttpGet("robots.txt")] [ProducesResponseType(StatusCodes.Status200OK)] [ApiExplorerSettings(IgnoreApi = true)] public ActionResult GetRobotsTxt() @@ -187,7 +188,7 @@ namespace Jellyfin.Api.Controllers /// Web client returned. /// Server does not host a web client. /// The resource. - [HttpGet("/web/{*resourceName}")] + [HttpGet("web/{*resourceName}")] [ApiExplorerSettings(IgnoreApi = true)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -218,7 +219,7 @@ namespace Jellyfin.Api.Controllers /// /// Favicon.ico returned. /// The favicon. - [HttpGet("/favicon.ico")] + [HttpGet("favicon.ico")] [ProducesResponseType(StatusCodes.Status200OK)] [ApiExplorerSettings(IgnoreApi = true)] public ActionResult GetFavIcon() diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index c4f79ce95..ec65cb95a 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -37,6 +37,7 @@ namespace Jellyfin.Api.Controllers /// /// Dynamic hls controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class DynamicHlsController : BaseJellyfinApiController { @@ -164,8 +165,8 @@ namespace Jellyfin.Api.Controllers /// Enable adaptive bitrate streaming. /// Video stream returned. /// A containing the playlist file. - [HttpGet("/Videos/{itemId}/master.m3u8")] - [HttpHead("/Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")] + [HttpGet("Videos/{itemId}/master.m3u8")] + [HttpHead("Videos/{itemId}/master.m3u8", Name = "HeadMasterHlsVideoPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetMasterHlsVideoPlaylist( [FromRoute] Guid itemId, @@ -334,8 +335,8 @@ namespace Jellyfin.Api.Controllers /// Enable adaptive bitrate streaming. /// Audio stream returned. /// A containing the playlist file. - [HttpGet("/Audio/{itemId}/master.m3u8")] - [HttpHead("/Audio/{itemId}/master.m3u8", Name = "HeadMasterHlsAudioPlaylist")] + [HttpGet("Audio/{itemId}/master.m3u8")] + [HttpHead("Audio/{itemId}/master.m3u8", Name = "HeadMasterHlsAudioPlaylist")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetMasterHlsAudioPlaylist( [FromRoute] Guid itemId, @@ -503,7 +504,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Video stream returned. /// A containing the audio file. - [HttpGet("/Videos/{itemId}/main.m3u8")] + [HttpGet("Videos/{itemId}/main.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetVariantHlsVideoPlaylist( [FromRoute] Guid itemId, @@ -668,7 +669,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Audio stream returned. /// A containing the audio file. - [HttpGet("/Audio/{itemId}/main.m3u8")] + [HttpGet("Audio/{itemId}/main.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetVariantHlsAudioPlaylist( [FromRoute] Guid itemId, @@ -835,7 +836,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Video stream returned. /// A containing the audio file. - [HttpGet("/Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] + [HttpGet("Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")] public async Task GetHlsVideoSegment( @@ -1004,7 +1005,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The streaming options. /// Video stream returned. /// A containing the audio file. - [HttpGet("/Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] + [HttpGet("Audio/{itemId}/hls1/{playlistId}/{segmentId}.{container}")] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "playlistId", Justification = "Imported from ServiceStack")] public async Task GetHlsAudioSegment( diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index 9ba5e1161..2a567c846 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -18,6 +18,7 @@ namespace Jellyfin.Api.Controllers /// /// Filters controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class FilterController : BaseJellyfinApiController { @@ -44,7 +45,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Filter by MediaType. Allows multiple, comma delimited. /// Legacy filters retrieved. /// Legacy query filters. - [HttpGet("/Items/Filters")] + [HttpGet("Items/Filters")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetQueryFiltersLegacy( [FromQuery] Guid? userId, @@ -133,7 +134,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Search recursive. /// Filters retrieved. /// Query filters. - [HttpGet("/Items/Filters2")] + [HttpGet("Items/Filters2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetQueryFilters( [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 7bf9326a7..e4a6842bc 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers /// /// The hls segment controller. /// + [Route("")] public class HlsSegmentController : BaseJellyfinApiController { private readonly IFileSystem _fileSystem; @@ -50,8 +51,8 @@ namespace Jellyfin.Api.Controllers /// A containing the audio stream. // Can't require authentication just yet due to seeing some requests come from Chrome without full query string // [Authenticated] - [HttpGet("/Audio/{itemId}/hls/{segmentId}/stream.mp3", Name = "GetHlsAudioSegmentLegacyMp3")] - [HttpGet("/Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")] + [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.mp3", Name = "GetHlsAudioSegmentLegacyMp3")] + [HttpGet("Audio/{itemId}/hls/{segmentId}/stream.aac", Name = "GetHlsAudioSegmentLegacyAac")] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsAudioSegmentLegacy([FromRoute] string itemId, [FromRoute] string segmentId) @@ -70,7 +71,7 @@ namespace Jellyfin.Api.Controllers /// The playlist id. /// Hls video playlist returned. /// A containing the playlist. - [HttpGet("/Videos/{itemId}/hls/{playlistId}/stream.m3u8")] + [HttpGet("Videos/{itemId}/hls/{playlistId}/stream.m3u8")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] @@ -89,7 +90,7 @@ namespace Jellyfin.Api.Controllers /// The play session id. /// Encoding stopped successfully. /// A indicating success. - [HttpDelete("/Videos/ActiveEncodings")] + [HttpDelete("Videos/ActiveEncodings")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult StopEncodingProcess([FromQuery] string deviceId, [FromQuery] string playSessionId) @@ -109,7 +110,7 @@ namespace Jellyfin.Api.Controllers /// A containing the video segment. // Can't require authentication just yet due to seeing some requests come from Chrome without full query string // [Authenticated] - [HttpGet("/Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}")] + [HttpGet("Videos/{itemId}/hls/{playlistId}/{segmentId}.{segmentContainer}")] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "itemId", Justification = "Required for ServiceStack")] public ActionResult GetHlsVideoSegmentLegacy( diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 3a445b1b3..360164ad4 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -30,6 +30,7 @@ namespace Jellyfin.Api.Controllers /// /// Image controller. /// + [Route("")] public class ImageController : BaseJellyfinApiController { private readonly IUserManager _userManager; @@ -81,8 +82,8 @@ namespace Jellyfin.Api.Controllers /// Image updated. /// User does not have permission to delete the image. /// A . - [HttpPost("/Users/{userId}/Images/{imageType}")] - [HttpPost("/Users/{userId}/Images/{imageType}/{index?}", Name = "PostUserImage_2")] + [HttpPost("Users/{userId}/Images/{imageType}")] + [HttpPost("Users/{userId}/Images/{imageType}/{index?}", Name = "PostUserImage_2")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] @@ -127,8 +128,8 @@ namespace Jellyfin.Api.Controllers /// Image deleted. /// User does not have permission to delete the image. /// A . - [HttpDelete("/Users/{userId}/Images/{itemType}")] - [HttpDelete("/Users/{userId}/Images/{itemType}/{index?}", Name = "DeleteUserImage_2")] + [HttpDelete("Users/{userId}/Images/{itemType}")] + [HttpDelete("Users/{userId}/Images/{itemType}/{index?}", Name = "DeleteUserImage_2")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] [ProducesResponseType(StatusCodes.Status204NoContent)] @@ -166,8 +167,8 @@ namespace Jellyfin.Api.Controllers /// Image deleted. /// Item not found. /// A on success, or a if item not found. - [HttpDelete("/Items/{itemId}/Images/{imageType}")] - [HttpDelete("/Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "DeleteItemImage_2")] + [HttpDelete("Items/{itemId}/Images/{imageType}")] + [HttpDelete("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "DeleteItemImage_2")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -195,8 +196,8 @@ namespace Jellyfin.Api.Controllers /// Image saved. /// Item not found. /// A on success, or a if item not found. - [HttpPost("/Items/{itemId}/Images/{imageType}")] - [HttpPost("/Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "SetItemImage_2")] + [HttpPost("Items/{itemId}/Images/{imageType}")] + [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "SetItemImage_2")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -230,7 +231,7 @@ namespace Jellyfin.Api.Controllers /// Image index updated. /// Item not found. /// A on success, or a if item not found. - [HttpPost("/Items/{itemId}/Images/{imageType}/{imageIndex}/Index")] + [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}/Index")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -257,7 +258,7 @@ namespace Jellyfin.Api.Controllers /// Item images returned. /// Item not found. /// The list of image infos on success, or if item not found. - [HttpGet("/Items/{itemId}/Images")] + [HttpGet("Items/{itemId}/Images")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetItemImageInfos([FromRoute] Guid itemId) @@ -341,10 +342,10 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Items/{itemId}/Images/{imageType}")] - [HttpHead("/Items/{itemId}/Images/{imageType}", Name = "HeadItemImage")] - [HttpGet("/Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "GetItemImage_2")] - [HttpHead("/Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "HeadItemImage_2")] + [HttpGet("Items/{itemId}/Images/{imageType}")] + [HttpHead("Items/{itemId}/Images/{imageType}", Name = "HeadItemImage")] + [HttpGet("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "GetItemImage_2")] + [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex?}", Name = "HeadItemImage_2")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetItemImage( @@ -421,8 +422,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}")] - [HttpHead("/Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}", Name = "HeadItemImage2")] + [HttpGet("Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}")] + [HttpHead("Items/{itemId}/Images/{imageType}/{imageIndex}/{tag}/{format}/{maxWidth}/{maxHeight}/{percentPlayed}/{unplayedCount}", Name = "HeadItemImage2")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetItemImage2( @@ -499,8 +500,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Artists/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/Artists/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadArtistImage")] + [HttpGet("Artists/{name}/Images/{imageType}/{imageIndex?}")] + [HttpHead("Artists/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadArtistImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetArtistImage( @@ -577,8 +578,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Genres/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/Genres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadGenreImage")] + [HttpGet("Genres/{name}/Images/{imageType}/{imageIndex?}")] + [HttpHead("Genres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetGenreImage( @@ -655,8 +656,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/MusicGenres/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/MusicGenres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadMusicGenreImage")] + [HttpGet("MusicGenres/{name}/Images/{imageType}/{imageIndex?}")] + [HttpHead("MusicGenres/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadMusicGenreImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetMusicGenreImage( @@ -733,8 +734,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Persons/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/Persons/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadPersonImage")] + [HttpGet("Persons/{name}/Images/{imageType}/{imageIndex?}")] + [HttpHead("Persons/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadPersonImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetPersonImage( @@ -811,8 +812,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Studios/{name}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/Studios/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadStudioImage")] + [HttpGet("Studios/{name}/Images/{imageType}/{imageIndex?}")] + [HttpHead("Studios/{name}/Images/{imageType}/{imageIndex?}", Name = "HeadStudioImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetStudioImage( @@ -889,8 +890,8 @@ namespace Jellyfin.Api.Controllers /// A containing the file stream on success, /// or a if item not found. /// - [HttpGet("/Users/{userId}/Images/{imageType}/{imageIndex?}")] - [HttpHead("/Users/{userId}/Images/{imageType}/{imageIndex?}", Name = "HeadUserImage")] + [HttpGet("Users/{userId}/Images/{imageType}/{imageIndex?}")] + [HttpHead("Users/{userId}/Images/{imageType}/{imageIndex?}", Name = "HeadUserImage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetUserImage( diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index bb980af3e..8ca232cef 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers /// /// The instant mix controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class InstantMixController : BaseJellyfinApiController { @@ -59,7 +60,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/Songs/{id}/InstantMix")] + [HttpGet("Songs/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromSong( [FromRoute] Guid id, @@ -96,7 +97,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/Albums/{id}/InstantMix")] + [HttpGet("Albums/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromAlbum( [FromRoute] Guid id, @@ -133,7 +134,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/Playlists/{id}/InstantMix")] + [HttpGet("Playlists/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromPlaylist( [FromRoute] Guid id, @@ -170,7 +171,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/MusicGenres/{name}/InstantMix")] + [HttpGet("MusicGenres/{name}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenre( [FromRoute] string? name, @@ -206,7 +207,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/Artists/InstantMix")] + [HttpGet("Artists/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromArtists( [FromRoute] Guid id, @@ -243,7 +244,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/MusicGenres/InstantMix")] + [HttpGet("MusicGenres/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromMusicGenres( [FromRoute] Guid id, @@ -280,7 +281,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The image types to include in the output. /// Instant playlist returned. /// A with the playlist items. - [HttpGet("/Items/{id}/InstantMix")] + [HttpGet("Items/{id}/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetInstantMixFromItem( [FromRoute] Guid id, diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index 44709d0ee..0d9dffbfe 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -30,6 +30,7 @@ namespace Jellyfin.Api.Controllers /// /// Item lookup controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class ItemLookupController : BaseJellyfinApiController { @@ -68,7 +69,7 @@ namespace Jellyfin.Api.Controllers /// External id info retrieved. /// Item not found. /// List of external id info. - [HttpGet("/Items/{itemId}/ExternalIdInfos")] + [HttpGet("Items/{itemId}/ExternalIdInfos")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -92,7 +93,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/Movie")] + [HttpPost("Items/RemoteSearch/Movie")] public async Task>> GetMovieRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -109,7 +110,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/Trailer")] + [HttpPost("Items/RemoteSearch/Trailer")] public async Task>> GetTrailerRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -126,7 +127,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/MusicVideo")] + [HttpPost("Items/RemoteSearch/MusicVideo")] public async Task>> GetMusicVideoRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -143,7 +144,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/Series")] + [HttpPost("Items/RemoteSearch/Series")] public async Task>> GetSeriesRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -160,7 +161,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/BoxSet")] + [HttpPost("Items/RemoteSearch/BoxSet")] public async Task>> GetBoxSetRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -177,7 +178,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/MusicArtist")] + [HttpPost("Items/RemoteSearch/MusicArtist")] public async Task>> GetMusicArtistRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -194,7 +195,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/MusicAlbum")] + [HttpPost("Items/RemoteSearch/MusicAlbum")] public async Task>> GetMusicAlbumRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -211,7 +212,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/Person")] + [HttpPost("Items/RemoteSearch/Person")] [Authorize(Policy = Policies.RequiresElevation)] public async Task>> GetPersonRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { @@ -229,7 +230,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the list of remote search results. /// - [HttpPost("/Items/RemoteSearch/Book")] + [HttpPost("Items/RemoteSearch/Book")] public async Task>> GetBookRemoteSearchResults([FromBody, BindRequired] RemoteSearchQuery query) { var results = await _providerManager.GetRemoteSearchResults(query, CancellationToken.None) @@ -247,7 +248,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an containing the images file stream. /// - [HttpGet("/Items/RemoteSearch/Image")] + [HttpGet("Items/RemoteSearch/Image")] public async Task GetRemoteSearchImage( [FromQuery, Required] string imageUrl, [FromQuery, Required] string providerName) @@ -291,7 +292,7 @@ namespace Jellyfin.Api.Controllers /// A that represents the asynchronous operation to get the remote search results. /// The task result contains an . /// - [HttpPost("/Items/RemoteSearch/Apply/{id}")] + [HttpPost("Items/RemoteSearch/Apply/{id}")] [Authorize(Policy = Policies.RequiresElevation)] public async Task ApplySearchCriteria( [FromRoute] Guid itemId, diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index c9b2aafcc..a5d9d36a3 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -24,6 +24,7 @@ namespace Jellyfin.Api.Controllers /// /// Item update controller. /// + [Route("")] [Authorize(Policy = Policies.RequiresElevation)] public class ItemUpdateController : BaseJellyfinApiController { @@ -63,7 +64,7 @@ namespace Jellyfin.Api.Controllers /// Item updated. /// Item not found. /// An on success, or a if the item could not be found. - [HttpPost("/Items/{itemId}")] + [HttpPost("Items/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateItem([FromRoute] Guid itemId, [FromBody, BindRequired] BaseItemDto request) @@ -136,7 +137,7 @@ namespace Jellyfin.Api.Controllers /// Item metadata editor returned. /// Item not found. /// An on success containing the metadata editor, or a if the item could not be found. - [HttpGet("/Items/{itemId}/MetadataEditor")] + [HttpGet("Items/{itemId}/MetadataEditor")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetMetadataEditorInfo([FromRoute] Guid itemId) @@ -190,7 +191,7 @@ namespace Jellyfin.Api.Controllers /// Item content type updated. /// Item not found. /// An on success, or a if the item could not be found. - [HttpPost("/Items/{itemId}/ContentType")] + [HttpPost("Items/{itemId}/ContentType")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateItemContentType([FromRoute] Guid itemId, [FromQuery, BindRequired] string? contentType) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 354741ced..1b8b68313 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -23,6 +23,7 @@ namespace Jellyfin.Api.Controllers /// /// The items controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class ItemsController : BaseJellyfinApiController { @@ -139,8 +140,8 @@ namespace Jellyfin.Api.Controllers /// Optional. Enable the total record count. /// Optional, include image information in output. /// A with the items. - [HttpGet("/Items")] - [HttpGet("/Users/{uId}/Items", Name = "GetItems_2")] + [HttpGet("Items")] + [HttpGet("Users/{uId}/Items", Name = "GetItems_2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetItems( [FromRoute] Guid? uId, @@ -523,7 +524,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Include image information in output. /// Items returned. /// A with the items that are resumable. - [HttpGet("/Users/{userId}/Items/Resume")] + [HttpGet("Users/{userId}/Items/Resume")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetResumeItems( [FromRoute] Guid userId, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 0ec7e2b8c..a4637752d 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -43,6 +43,7 @@ namespace Jellyfin.Api.Controllers /// /// Library Controller. /// + [Route("")] public class LibraryController : BaseJellyfinApiController { private readonly IProviderManager _providerManager; @@ -100,7 +101,7 @@ namespace Jellyfin.Api.Controllers /// File stream returned. /// Item not found. /// A with the original file. - [HttpGet("/Items/{itemId}/File")] + [HttpGet("Items/{itemId}/File")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -121,7 +122,7 @@ namespace Jellyfin.Api.Controllers /// /// Critic reviews returned. /// The list of critic reviews. - [HttpGet("/Items/{itemId}/CriticReviews")] + [HttpGet("Items/{itemId}/CriticReviews")] [Authorize(Policy = Policies.DefaultAuthorization)] [Obsolete("This endpoint is obsolete.")] [ProducesResponseType(StatusCodes.Status200OK)] @@ -139,7 +140,7 @@ namespace Jellyfin.Api.Controllers /// Theme songs returned. /// Item not found. /// The item theme songs. - [HttpGet("/Items/{itemId}/ThemeSongs")] + [HttpGet("Items/{itemId}/ThemeSongs")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -205,7 +206,7 @@ namespace Jellyfin.Api.Controllers /// Theme videos returned. /// Item not found. /// The item theme videos. - [HttpGet("/Items/{itemId}/ThemeVideos")] + [HttpGet("Items/{itemId}/ThemeVideos")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -271,7 +272,7 @@ namespace Jellyfin.Api.Controllers /// Theme songs and videos returned. /// Item not found. /// The item theme videos. - [HttpGet("/Items/{itemId}/ThemeMedia")] + [HttpGet("Items/{itemId}/ThemeMedia")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetThemeMedia( @@ -302,7 +303,7 @@ namespace Jellyfin.Api.Controllers /// /// Library scan started. /// A . - [HttpGet("/Library/Refresh")] + [HttpGet("Library/Refresh")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RefreshLibrary() @@ -326,7 +327,7 @@ namespace Jellyfin.Api.Controllers /// Item deleted. /// Unauthorized access. /// A . - [HttpDelete("/Items/{itemId}")] + [HttpDelete("Items/{itemId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] @@ -356,7 +357,7 @@ namespace Jellyfin.Api.Controllers /// Items deleted. /// Unauthorized access. /// A . - [HttpDelete("/Items")] + [HttpDelete("Items")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] @@ -400,7 +401,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Get counts of favorite items. /// Item counts returned. /// Item counts. - [HttpGet("/Items/Counts")] + [HttpGet("Items/Counts")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetItemCounts( @@ -434,7 +435,7 @@ namespace Jellyfin.Api.Controllers /// Item parents returned. /// Item not found. /// Item parents. - [HttpGet("/Items/{itemId}/Ancestors")] + [HttpGet("Items/{itemId}/Ancestors")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -476,7 +477,7 @@ namespace Jellyfin.Api.Controllers /// /// Physical paths returned. /// List of physical paths. - [HttpGet("/Library/PhysicalPaths")] + [HttpGet("Library/PhysicalPaths")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetPhysicalPaths() @@ -491,7 +492,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Filter by folders that are marked hidden, or not. /// Media folders returned. /// List of user media folders. - [HttpGet("/Library/MediaFolders")] + [HttpGet("Library/MediaFolders")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetMediaFolders([FromQuery] bool? isHidden) @@ -521,8 +522,8 @@ namespace Jellyfin.Api.Controllers /// The tvdbId. /// Report success. /// A . - [HttpPost("/Library/Series/Added", Name = "PostAddedSeries")] - [HttpPost("/Library/Series/Updated")] + [HttpPost("Library/Series/Added", Name = "PostAddedSeries")] + [HttpPost("Library/Series/Updated")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostUpdatedSeries([FromQuery] string? tvdbId) @@ -551,8 +552,8 @@ namespace Jellyfin.Api.Controllers /// The imdbId. /// Report success. /// A . - [HttpPost("/Library/Movies/Added", Name = "PostAddedMovies")] - [HttpPost("/Library/Movies/Updated")] + [HttpPost("Library/Movies/Added", Name = "PostAddedMovies")] + [HttpPost("Library/Movies/Updated")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostUpdatedMovies([FromRoute] string? tmdbId, [FromRoute] string? imdbId) @@ -593,7 +594,7 @@ namespace Jellyfin.Api.Controllers /// A list of updated media paths. /// Report success. /// A . - [HttpPost("/Library/Media/Updated")] + [HttpPost("Library/Media/Updated")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostUpdatedMedia([FromBody, BindRequired] MediaUpdateInfoDto[] updates) @@ -614,7 +615,7 @@ namespace Jellyfin.Api.Controllers /// Item not found. /// A containing the media stream. /// User can't download or item can't be downloaded. - [HttpGet("/Items/{itemId}/Download")] + [HttpGet("Items/{itemId}/Download")] [Authorize(Policy = Policies.Download)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -679,12 +680,12 @@ namespace Jellyfin.Api.Controllers /// Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls. /// Similar items returned. /// A containing the similar items. - [HttpGet("/Artists/{itemId}/Similar", Name = "GetSimilarArtists2")] - [HttpGet("/Items/{itemId}/Similar")] - [HttpGet("/Albums/{itemId}/Similar", Name = "GetSimilarAlbums2")] - [HttpGet("/Shows/{itemId}/Similar", Name = "GetSimilarShows2")] - [HttpGet("/Movies/{itemId}/Similar", Name = "GetSimilarMovies2")] - [HttpGet("/Trailers/{itemId}/Similar", Name = "GetSimilarTrailers2")] + [HttpGet("Artists/{itemId}/Similar", Name = "GetSimilarArtists2")] + [HttpGet("Items/{itemId}/Similar")] + [HttpGet("Albums/{itemId}/Similar", Name = "GetSimilarAlbums2")] + [HttpGet("Shows/{itemId}/Similar", Name = "GetSimilarShows2")] + [HttpGet("Movies/{itemId}/Similar", Name = "GetSimilarMovies2")] + [HttpGet("Trailers/{itemId}/Similar", Name = "GetSimilarTrailers2")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSimilarItems( [FromRoute] Guid itemId, @@ -735,7 +736,7 @@ namespace Jellyfin.Api.Controllers /// Whether this is a new library. /// Library options info returned. /// Library options info. - [HttpGet("/Libraries/AvailableOptions")] + [HttpGet("Libraries/AvailableOptions")] [Authorize(Policy = Policies.FirstTimeSetupOrElevated)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetLibraryOptionsInfo( diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 5b0f46b02..242cbf191 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -34,6 +34,7 @@ namespace Jellyfin.Api.Controllers /// /// The media info controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class MediaInfoController : BaseJellyfinApiController { @@ -88,7 +89,7 @@ namespace Jellyfin.Api.Controllers /// The user id. /// Playback info returned. /// A containing a with the playback information. - [HttpGet("/Items/{itemId}/PlaybackInfo")] + [HttpGet("Items/{itemId}/PlaybackInfo")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery] Guid? userId) { @@ -116,7 +117,7 @@ namespace Jellyfin.Api.Controllers /// Whether to allow to copy the audio stream. Default: true. /// Playback info returned. /// A containing a with the playback info. - [HttpPost("/Items/{itemId}/PlaybackInfo")] + [HttpPost("Items/{itemId}/PlaybackInfo")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPostedPlaybackInfo( [FromRoute] Guid itemId, @@ -237,7 +238,7 @@ namespace Jellyfin.Api.Controllers /// Whether to enable direct stream. Default: true. /// Media source opened. /// A containing a . - [HttpPost("/LiveStreams/Open")] + [HttpPost("LiveStreams/Open")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> OpenLiveStream( [FromQuery] string? openToken, @@ -278,7 +279,7 @@ namespace Jellyfin.Api.Controllers /// The livestream id. /// Livestream closed. /// A indicating success. - [HttpPost("/LiveStreams/Close")] + [HttpPost("LiveStreams/Close")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult CloseLiveStream([FromQuery] string? liveStreamId) { @@ -293,7 +294,7 @@ namespace Jellyfin.Api.Controllers /// Test buffer returned. /// Size has to be a numer between 0 and 10,000,000. /// A with specified bitrate. - [HttpGet("/Playback/BitrateTest")] + [HttpGet("Playback/BitrateTest")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [Produces(MediaTypeNames.Application.Octet)] diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index a6c552790..06c4213fb 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -16,7 +16,7 @@ namespace Jellyfin.Api.Controllers /// /// Package Controller. /// - [Route("Packages")] + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class PackageController : BaseJellyfinApiController { @@ -41,7 +41,7 @@ namespace Jellyfin.Api.Controllers /// The GUID of the associated assembly. /// Package retrieved. /// A containing package information. - [HttpGet("/{name}")] + [HttpGet("Packages/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPackageInfo( [FromRoute] [Required] string? name, @@ -61,7 +61,7 @@ namespace Jellyfin.Api.Controllers /// /// Available packages returned. /// An containing available packages information. - [HttpGet] + [HttpGet("Packages")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPackages() { @@ -79,7 +79,7 @@ namespace Jellyfin.Api.Controllers /// Package found. /// Package not found. /// A on success, or a if the package could not be found. - [HttpPost("/Installed/{name}")] + [HttpPost("Packages/Installed/{name}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Authorize(Policy = Policies.RequiresElevation)] @@ -111,7 +111,7 @@ namespace Jellyfin.Api.Controllers /// Installation Id. /// Installation cancelled. /// A on successfully cancelling a package installation. - [HttpDelete("/Installing/{packageId}")] + [HttpDelete("Packages/Installing/{packageId}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult CancelPackageInstallation( @@ -126,7 +126,7 @@ namespace Jellyfin.Api.Controllers /// /// Package repositories returned. /// An containing the list of package repositories. - [HttpGet("/Repositories")] + [HttpGet("Repositories")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetRepositories() @@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers /// The list of package repositories. /// Package repositories saved. /// A . - [HttpOptions("/Repositories")] + [HttpOptions("Repositories")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SetRepositories([FromBody] List repositoryInfos) diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 3ebd003f1..0422bfe72 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers /// /// Playstate controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class PlaystateController : BaseJellyfinApiController { @@ -67,7 +68,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The date the item was played. /// Item marked as played. /// An containing the . - [HttpPost("/Users/{userId}/PlayedItems/{itemId}")] + [HttpPost("Users/{userId}/PlayedItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult MarkPlayedItem( [FromRoute] Guid userId, @@ -93,7 +94,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Item marked as unplayed. /// A containing the . - [HttpDelete("/Users/{userId}/PlayedItem/{itemId}")] + [HttpDelete("Users/{userId}/PlayedItem/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult MarkUnplayedItem([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -115,7 +116,7 @@ namespace Jellyfin.Api.Controllers /// The playback start info. /// Playback start recorded. /// A . - [HttpPost("/Sessions/Playing")] + [HttpPost("Sessions/Playing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ReportPlaybackStart([FromBody] PlaybackStartInfo playbackStartInfo) { @@ -131,7 +132,7 @@ namespace Jellyfin.Api.Controllers /// The playback progress info. /// Playback progress recorded. /// A . - [HttpPost("/Sessions/Playing/Progress")] + [HttpPost("Sessions/Playing/Progress")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ReportPlaybackProgress([FromBody] PlaybackProgressInfo playbackProgressInfo) { @@ -147,7 +148,7 @@ namespace Jellyfin.Api.Controllers /// Playback session id. /// Playback session pinged. /// A . - [HttpPost("/Sessions/Playing/Ping")] + [HttpPost("Sessions/Playing/Ping")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PingPlaybackSession([FromQuery] string playSessionId) { @@ -161,7 +162,7 @@ namespace Jellyfin.Api.Controllers /// The playback stop info. /// Playback stop recorded. /// A . - [HttpPost("/Sessions/Playing/Stopped")] + [HttpPost("Sessions/Playing/Stopped")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task ReportPlaybackStopped([FromBody] PlaybackStopInfo playbackStopInfo) { @@ -190,7 +191,7 @@ namespace Jellyfin.Api.Controllers /// Indicates if the client can seek. /// Play start recorded. /// A . - [HttpPost("/Users/{userId}/PlayingItems/{itemId}")] + [HttpPost("Users/{userId}/PlayingItems/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackStart( @@ -240,7 +241,7 @@ namespace Jellyfin.Api.Controllers /// Indicates if the player is muted. /// Play progress recorded. /// A . - [HttpPost("/Users/{userId}/PlayingItems/{itemId}/Progress")] + [HttpPost("Users/{userId}/PlayingItems/{itemId}/Progress")] [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackProgress( @@ -292,7 +293,7 @@ namespace Jellyfin.Api.Controllers /// The play session id. /// Playback stop recorded. /// A . - [HttpDelete("/Users/{userId}/PlayingItems/{itemId}")] + [HttpDelete("Users/{userId}/PlayingItems/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Required for ServiceStack")] public async Task OnPlaybackStopped( diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 770d74838..fe10f0f1b 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -188,7 +188,7 @@ namespace Jellyfin.Api.Controllers /// Not Implemented. /// This endpoint is not implemented. [Obsolete("Paid plugins are not supported")] - [HttpGet("/Registrations/{name}")] + [HttpGet("Registrations/{name}")] [ProducesResponseType(StatusCodes.Status501NotImplemented)] public ActionResult GetRegistration([FromRoute] string? name) { diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs index 1b300e0d8..3e6f577f1 100644 --- a/Jellyfin.Api/Controllers/SessionController.cs +++ b/Jellyfin.Api/Controllers/SessionController.cs @@ -23,6 +23,7 @@ namespace Jellyfin.Api.Controllers /// /// The session controller. /// + [Route("")] public class SessionController : BaseJellyfinApiController { private readonly ISessionManager _sessionManager; @@ -57,7 +58,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Filter by sessions that were active in the last n seconds. /// List of sessions returned. /// An with the available sessions. - [HttpGet("/Sessions")] + [HttpGet("Sessions")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSessions( @@ -120,7 +121,7 @@ namespace Jellyfin.Api.Controllers /// The name of the item. /// Instruction sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/Viewing")] + [HttpPost("Sessions/{sessionId}/Viewing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult DisplayContent( [FromRoute] string? sessionId, @@ -154,7 +155,7 @@ namespace Jellyfin.Api.Controllers /// The . /// Instruction sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/Playing")] + [HttpPost("Sessions/{sessionId}/Playing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult Play( [FromRoute] string? sessionId, @@ -188,7 +189,7 @@ namespace Jellyfin.Api.Controllers /// The . /// Playstate command sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/Playing/{command}")] + [HttpPost("Sessions/{sessionId}/Playing/{command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendPlaystateCommand( [FromRoute] string? sessionId, @@ -210,7 +211,7 @@ namespace Jellyfin.Api.Controllers /// The command to send. /// System command sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/System/{command}")] + [HttpPost("Sessions/{sessionId}/System/{command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendSystemCommand( [FromRoute] string? sessionId, @@ -241,7 +242,7 @@ namespace Jellyfin.Api.Controllers /// The command to send. /// General command sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/Command/{command}")] + [HttpPost("Sessions/{sessionId}/Command/{command}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendGeneralCommand( [FromRoute] string? sessionId, @@ -267,7 +268,7 @@ namespace Jellyfin.Api.Controllers /// The . /// Full general command sent to session. /// A . - [HttpPost("/Sessions/{sessionId}/Command")] + [HttpPost("Sessions/{sessionId}/Command")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendFullGeneralCommand( [FromRoute] string? sessionId, @@ -300,7 +301,7 @@ namespace Jellyfin.Api.Controllers /// The message timeout. If omitted the user will have to confirm viewing the message. /// Message sent. /// A . - [HttpPost("/Sessions/{sessionId}/Message")] + [HttpPost("Sessions/{sessionId}/Message")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SendMessageCommand( [FromRoute] string? sessionId, @@ -327,7 +328,7 @@ namespace Jellyfin.Api.Controllers /// The user id. /// User added to session. /// A . - [HttpPost("/Sessions/{sessionId}/User/{userId}")] + [HttpPost("Sessions/{sessionId}/User/{userId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult AddUserToSession( [FromRoute] string? sessionId, @@ -344,7 +345,7 @@ namespace Jellyfin.Api.Controllers /// The user id. /// User removed from session. /// A . - [HttpDelete("/Sessions/{sessionId}/User/{userId}")] + [HttpDelete("Sessions/{sessionId}/User/{userId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RemoveUserFromSession( [FromRoute] string? sessionId, @@ -365,7 +366,7 @@ namespace Jellyfin.Api.Controllers /// Determines whether the device supports a unique identifier. /// Capabilities posted. /// A . - [HttpPost("/Sessions/Capabilities")] + [HttpPost("Sessions/Capabilities")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostCapabilities( [FromQuery] string? id, @@ -398,7 +399,7 @@ namespace Jellyfin.Api.Controllers /// The . /// Capabilities updated. /// A . - [HttpPost("/Sessions/Capabilities/Full")] + [HttpPost("Sessions/Capabilities/Full")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult PostFullCapabilities( [FromQuery] string? id, @@ -421,7 +422,7 @@ namespace Jellyfin.Api.Controllers /// The item id. /// Session reported to server. /// A . - [HttpPost("/Sessions/Viewing")] + [HttpPost("Sessions/Viewing")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult ReportViewing( [FromQuery] string? sessionId, @@ -438,7 +439,7 @@ namespace Jellyfin.Api.Controllers /// /// Session end reported to server. /// A . - [HttpPost("/Sessions/Logout")] + [HttpPost("Sessions/Logout")] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult ReportSessionEnded() { @@ -453,7 +454,7 @@ namespace Jellyfin.Api.Controllers /// /// Auth providers retrieved. /// An with the auth providers. - [HttpGet("/Auth/Providers")] + [HttpGet("Auth/Providers")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetAuthProviders() { @@ -465,7 +466,7 @@ namespace Jellyfin.Api.Controllers /// /// Password reset providers retrieved. /// An with the password reset providers. - [HttpGet("/Auto/PasswordResetProviders")] + [HttpGet("Auto/PasswordResetProviders")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetPasswordResetProviders() { diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index f8c19d15c..22144ab1a 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -30,6 +30,7 @@ namespace Jellyfin.Api.Controllers /// /// Subtitle controller. /// + [Route("")] public class SubtitleController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; @@ -80,7 +81,7 @@ namespace Jellyfin.Api.Controllers /// Subtitle deleted. /// Item not found. /// A . - [HttpDelete("/Videos/{itemId}/Subtitles/{index}")] + [HttpDelete("Videos/{itemId}/Subtitles/{index}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] @@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Only show subtitles which are a perfect match. /// Subtitles retrieved. /// An array of . - [HttpGet("/Items/{itemId}/RemoteSearch/Subtitles/{language}")] + [HttpGet("Items/{itemId}/RemoteSearch/Subtitles/{language}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> SearchRemoteSubtitles( @@ -127,7 +128,7 @@ namespace Jellyfin.Api.Controllers /// The subtitle id. /// Subtitle downloaded. /// A . - [HttpPost("/Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}")] + [HttpPost("Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task DownloadRemoteSubtitles( @@ -157,7 +158,7 @@ namespace Jellyfin.Api.Controllers /// The item id. /// File returned. /// A with the subtitle file. - [HttpGet("/Providers/Subtitles/Subtitles/{id}")] + [HttpGet("Providers/Subtitles/Subtitles/{id}")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [Produces(MediaTypeNames.Application.Octet)] @@ -181,8 +182,8 @@ namespace Jellyfin.Api.Controllers /// Optional. The start position of the subtitle in ticks. /// File returned. /// A with the subtitle file. - [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")] - [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks?}/Stream.{format}", Name = "GetSubtitle_2")] + [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")] + [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks?}/Stream.{format}", Name = "GetSubtitle_2")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetSubtitle( [FromRoute, Required] Guid itemId, @@ -247,7 +248,7 @@ namespace Jellyfin.Api.Controllers /// The subtitle segment length. /// Subtitle playlist retrieved. /// A with the HLS subtitle playlist. - [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")] + [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 55759f316..42db6b6a1 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -16,6 +16,7 @@ namespace Jellyfin.Api.Controllers /// /// The suggestions controller. /// + [Route("")] public class SuggestionsController : BaseJellyfinApiController { private readonly IDtoService _dtoService; @@ -49,7 +50,7 @@ namespace Jellyfin.Api.Controllers /// Whether to enable the total record count. /// Suggestions returned. /// A with the suggestions. - [HttpGet("/Users/{userId}/Suggestions")] + [HttpGet("Users/{userId}/Suggestions")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSuggestions( [FromRoute] Guid userId, diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index fbab7948f..5157b08ae 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -108,7 +108,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Enable the total record count. /// Optional, include image information in output. /// A with the trailers. - [HttpGet("/Trailers")] + [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetTrailers( [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 5a9bec2b0..75df16aa7 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers /// /// The universal audio controller. /// + [Route("")] public class UniversalAudioController : BaseJellyfinApiController { private readonly IAuthorizationContext _authorizationContext; @@ -68,10 +69,10 @@ namespace Jellyfin.Api.Controllers /// Audio stream returned. /// Redirected to remote audio stream. /// A containing the audio file. - [HttpGet("/Audio/{itemId}/universal")] - [HttpGet("/Audio/{itemId}/{universal=universal}.{container?}", Name = "GetUniversalAudioStream_2")] - [HttpHead("/Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] - [HttpHead("/Audio/{itemId}/{universal=universal}.{container?}", Name = "HeadUniversalAudioStream_2")] + [HttpGet("Audio/{itemId}/universal")] + [HttpGet("Audio/{itemId}/{universal=universal}.{container?}", Name = "GetUniversalAudioStream_2")] + [HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")] + [HttpHead("Audio/{itemId}/{universal=universal}.{container?}", Name = "HeadUniversalAudioStream_2")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status302Found)] diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 482baf641..2ce5c7e56 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -450,7 +450,7 @@ namespace Jellyfin.Api.Controllers /// The create user by name request body. /// User created. /// An of the new user. - [HttpPost("/Users/New")] + [HttpPost("New")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateUserByName([FromBody] CreateUserByName request) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index cedda3b9d..f55ff6f3d 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -25,6 +25,7 @@ namespace Jellyfin.Api.Controllers /// /// User library controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class UserLibraryController : BaseJellyfinApiController { @@ -67,7 +68,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Item returned. /// An containing the d item. - [HttpGet("/Users/{userId}/Items/{itemId}")] + [HttpGet("Users/{userId}/Items/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetItem([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -90,7 +91,7 @@ namespace Jellyfin.Api.Controllers /// User id. /// Root folder returned. /// An containing the user's root folder. - [HttpGet("/Users/{userId}/Items/Root")] + [HttpGet("Users/{userId}/Items/Root")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetRootFolder([FromRoute] Guid userId) { @@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Intros returned. /// An containing the intros to play. - [HttpGet("/Users/{userId}/Items/{itemId}/Intros")] + [HttpGet("Users/{userId}/Items/{itemId}/Intros")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetIntros([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -135,7 +136,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Item marked as favorite. /// An containing the . - [HttpPost("/Users/{userId}/FavoriteItems/{itemId}")] + [HttpPost("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult MarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -149,7 +150,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Item unmarked as favorite. /// An containing the . - [HttpDelete("/Users/{userId}/FavoriteItems/{itemId}")] + [HttpDelete("Users/{userId}/FavoriteItems/{itemId}")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult UnmarkFavoriteItem([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -163,7 +164,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Personal rating removed. /// An containing the . - [HttpDelete("/Users/{userId}/Items/{itemId}/Rating")] + [HttpDelete("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult DeleteUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -178,7 +179,7 @@ namespace Jellyfin.Api.Controllers /// Whether this is likes. /// Item rating updated. /// An containing the . - [HttpPost("/Users/{userId}/Items/{itemId}/Rating")] + [HttpPost("Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult UpdateUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool? likes) { @@ -192,7 +193,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// An containing the item's local trailers. /// The items local trailers. - [HttpGet("/Users/{userId}/Items/{itemId}/LocalTrailers")] + [HttpGet("Users/{userId}/Items/{itemId}/LocalTrailers")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetLocalTrailers([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -227,7 +228,7 @@ namespace Jellyfin.Api.Controllers /// Item id. /// Special features returned. /// An containing the special features. - [HttpGet("/Users/{userId}/Items/{itemId}/SpecialFeatures")] + [HttpGet("Users/{userId}/Items/{itemId}/SpecialFeatures")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetSpecialFeatures([FromRoute] Guid userId, [FromRoute] Guid itemId) { @@ -260,7 +261,7 @@ namespace Jellyfin.Api.Controllers /// Whether or not to group items into a parent container. /// Latest media returned. /// An containing the latest media. - [HttpGet("/Users/{userId}/Items/Latest")] + [HttpGet("Users/{userId}/Items/Latest")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetLatestMedia( [FromRoute] Guid userId, diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index f4bd451ef..6df7cc779 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -21,6 +21,7 @@ namespace Jellyfin.Api.Controllers /// /// User views controller. /// + [Route("")] public class UserViewsController : BaseJellyfinApiController { private readonly IUserManager _userManager; @@ -60,7 +61,7 @@ namespace Jellyfin.Api.Controllers /// Whether or not to include hidden content. /// User views returned. /// An containing the user views. - [HttpGet("/Users/{userId}/Views")] + [HttpGet("Users/{userId}/Views")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetUserViews( [FromRoute] Guid userId, @@ -122,7 +123,7 @@ namespace Jellyfin.Api.Controllers /// An containing the user view grouping options /// or a if user not found. /// - [HttpGet("/Users/{userId}/GroupingOptions")] + [HttpGet("Users/{userId}/GroupingOptions")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetGroupingOptions([FromRoute] Guid userId) diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 8520dd163..76188f46d 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -30,6 +30,7 @@ namespace Jellyfin.Api.Controllers /// /// The video hls controller. /// + [Route("")] [Authorize(Policy = Policies.DefaultAuthorization)] public class VideoHlsController : BaseJellyfinApiController { @@ -158,7 +159,7 @@ namespace Jellyfin.Api.Controllers /// Optional. Whether to enable subtitles in the manifest. /// Hls live stream retrieved. /// A containing the hls file. - [HttpGet("/Videos/{itemId}/live.m3u8")] + [HttpGet("Videos/{itemId}/live.m3u8")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task GetLiveHlsStream( [FromRoute] Guid itemId, @@ -271,7 +272,7 @@ namespace Jellyfin.Api.Controllers }; var cancellationTokenSource = new CancellationTokenSource(); - var state = await StreamingHelpers.GetStreamingState( + using var state = await StreamingHelpers.GetStreamingState( streamingRequest, Request, _authContext, -- cgit v1.2.3