diff options
31 files changed, 442 insertions, 408 deletions
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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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 /// <returns>An <see cref="OkResult"/> containing the artist.</returns> [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<BaseItemDto> GetArtistByName([FromRoute] string name, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> GetArtistByName([FromRoute] 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<QueryResult<BaseItemDto>> 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 /// </summary> /// <param name="name">The name of the collection.</param> /// <param name="ids">Item Ids to add to the collection.</param> - /// <param name="isLocked">Whether or not to lock the new collection.</param> /// <param name="parentId">Optional. Create the collection within a specific folder.</param> + /// <param name="isLocked">Whether or not to lock the new collection.</param> /// <response code="200">Collection created.</response> /// <returns>A <see cref="CollectionCreationOptions"/> with information about the new collection.</returns> [HttpPost] @@ -53,8 +53,8 @@ namespace Jellyfin.Api.Controllers public ActionResult<CollectionCreationResult> 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 /// <returns>An <see cref="OkResult"/> containing the genre.</returns> [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<BaseItemDto> GetGenre([FromRoute] string genreName, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> GetGenre([FromRoute] 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<BaseItemDto> GetResult(List<BaseItem> items, User user, int? limit, DtoOptions dtoOptions) + private QueryResult<BaseItemDto> GetResult(List<BaseItem> 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<QueryResult<BaseItemDto>> 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<ThemeMediaResult> 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<ThemeMediaResult> 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<AllThemeMediaResult> 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<string>() - : 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<ItemCounts> 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<IEnumerable<BaseItemDto>> GetAncestors([FromRoute] Guid itemId, [FromQuery] Guid userId) + public ActionResult<IEnumerable<BaseItemDto>> GetAncestors([FromRoute] Guid itemId, [FromQuery] Guid? userId) { var item = _libraryManager.GetItemById(itemId); @@ -448,8 +450,8 @@ namespace Jellyfin.Api.Controllers var baseItemDtos = new List<BaseItemDto>(); - 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<QueryResult<BaseItemDto>> 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<LibraryOptionsResultDto> GetLibraryOptionsInfo([FromQuery] string? libraryContentType, [FromQuery] bool isNewLibrary) + public ActionResult<LibraryOptionsResultDto> GetLibraryOptionsInfo( + [FromQuery] string? libraryContentType, + [FromQuery] bool isNewLibrary = false) { var result = new LibraryOptionsResultDto(); @@ -878,13 +882,15 @@ namespace Jellyfin.Api.Controllers private QueryResult<BaseItemDto> 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 /// </summary> /// <param name="name">The name of the virtual folder.</param> /// <param name="collectionType">The type of the collection.</param> - /// <param name="refreshLibrary">Whether to refresh the library.</param> /// <param name="paths">The paths of the virtual folder.</param> /// <param name="libraryOptions">The library options.</param> + /// <param name="refreshLibrary">Whether to refresh the library.</param> /// <response code="204">Folder added.</response> /// <returns>A <see cref="NoContentResult"/>.</returns> [HttpPost] @@ -74,9 +74,9 @@ namespace Jellyfin.Api.Controllers public async Task<ActionResult> 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<ActionResult> 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 /// <param name="isFavorite">Optional. Filter by channels that are favorites, or not.</param> /// <param name="isLiked">Optional. Filter by channels that are liked, or not.</param> /// <param name="isDisliked">Optional. Filter by channels that are disliked, or not.</param> - /// <param name="enableFavoriteSorting">Optional. Incorporate favorite and like status into channel sorting.</param> /// <param name="enableImages">Optional. Include image information in output.</param> /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param> /// <param name="enableImageTypes">"Optional. The image types to include in the output.</param> @@ -121,6 +120,7 @@ namespace Jellyfin.Api.Controllers /// <param name="enableUserData">Optional. Include user data.</param> /// <param name="sortBy">Optional. Key to sort by.</param> /// <param name="sortOrder">Optional. Sort order.</param> + /// <param name="enableFavoriteSorting">Optional. Incorporate favorite and like status into channel sorting.</param> /// <param name="addCurrentProgram">Optional. Adds current program info to each channel.</param> /// <response code="200">Available live tv channels returned.</response> /// <returns> @@ -131,7 +131,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] public ActionResult<QueryResult<BaseItemDto>> 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<BaseItemDto> GetChannel([FromRoute] Guid channelId, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> GetRecordingGroups([FromQuery] Guid userId) + public ActionResult<QueryResult<BaseItemDto>> GetRecordingGroups([FromQuery] Guid? userId) { return new QueryResult<BaseItemDto>(); } @@ -379,9 +381,11 @@ namespace Jellyfin.Api.Controllers [HttpGet("Recordings/Folders")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.DefaultAuthorization)] - public ActionResult<QueryResult<BaseItemDto>> GetRecordingFolders([FromQuery] Guid userId) + public ActionResult<QueryResult<BaseItemDto>> 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<BaseItemDto> GetRecording([FromRoute] Guid recordingId, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> 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<ActionResult<SeriesTimerInfoDto>> GetDefaultTimer([FromQuery] string programId) + public async Task<ActionResult<SeriesTimerInfoDto>> 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<ActionResult<QueryResult<TimerInfoDto>>> 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<ActionResult<QueryResult<BaseItemDto>>> 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<QueryResult<BaseItemDto>> 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<ActionResult<BaseItemDto>> 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<ActionResult<QueryResult<SeriesTimerInfoDto>>> GetSeriesTimers([FromQuery] string sortBy, [FromQuery] SortOrder sortOrder) + public async Task<ActionResult<QueryResult<SeriesTimerInfoDto>>> 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<BaseItemDto> GetRecordingGroup([FromQuery] Guid groupId) + public ActionResult<BaseItemDto> 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<LiveTvOptions>("livetv"); config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray(); @@ -990,10 +1000,10 @@ namespace Jellyfin.Api.Controllers /// <summary> /// Adds a listings provider. /// </summary> - /// <param name="validateLogin">Validate login.</param> - /// <param name="validateListings">Validate listings.</param> /// <param name="pw">Password.</param> /// <param name="listingsProviderInfo">New listings info.</param> + /// <param name="validateListings">Validate listings.</param> + /// <param name="validateLogin">Validate login.</param> /// <response code="200">Created listings provider returned.</response> /// <returns>A <see cref="OkResult"/> containing the created listings provider.</returns> [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<ActionResult<ListingsProviderInfo>> 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<ActionResult<IEnumerable<NameIdPair>>> 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<ActionResult<ChannelMappingOptionsDto>> GetChannelMappingOptions([FromQuery] string providerId) + public async Task<ActionResult<ChannelMappingOptionsDto>> GetChannelMappingOptions([FromQuery] string? providerId) { var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv"); @@ -1120,9 +1130,9 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult<TunerChannelMapping>> 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<ActionResult<IEnumerable<TunerHostInfo>>> DiscoverTuners([FromQuery] bool newDevicesOnly) + public async Task<ActionResult<IEnumerable<TunerHostInfo>>> 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 /// <returns>A <see cref="Task"/> containing a <see cref="PlaybackInfoResponse"/> with the playback information.</returns> [HttpGet("/Items/{itemId}/PlaybackInfo")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task<ActionResult<PlaybackInfoResponse>> GetPlaybackInfo([FromRoute] Guid itemId, [FromQuery] Guid userId) + public async Task<ActionResult<PlaybackInfoResponse>> 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<ActionResult<PlaybackInfoResponse>> 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<ActionResult<LiveStreamResponse>> 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 /// <returns>A <see cref="NoContentResult"/> indicating success.</returns> [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<PlaybackInfoResponse> 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 /// </summary> /// <param name="userId">Optional. Filter by user id, and attach user data.</param> /// <param name="parentId">Specify this to localize the search to a specific item or folder. Omit to use the root.</param> - /// <param name="enableImages">(Unused) Optional. include image information in output.</param> - /// <param name="enableUserData">(Unused) Optional. include user data.</param> - /// <param name="imageTypeLimit">(Unused) Optional. the max number of images to return, per image type.</param> - /// <param name="enableImageTypes">(Unused) Optional. The image types to include in the output.</param> /// <param name="fields">Optional. The fields to return.</param> /// <param name="categoryLimit">The max number of categories to return.</param> /// <param name="itemLimit">The max number of items to return per category.</param> /// <response code="200">Movie recommendations returned.</response> /// <returns>The list of movie recommendations.</returns> [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<IEnumerable<RecommendationDto>> 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<RecommendationDto> GetWithDirector( - User user, + User? user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, @@ -230,7 +220,7 @@ namespace Jellyfin.Api.Controllers } } - private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable<RecommendationDto> GetWithActor(User? user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List<string> { nameof(Movie) }; if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) @@ -270,7 +260,7 @@ namespace Jellyfin.Api.Controllers } } - private IEnumerable<RecommendationDto> GetSimilarTo(User user, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable<RecommendationDto> GetSimilarTo(User? user, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List<string> { 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 /// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns> [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<BaseItemDto> GetMusicGenre([FromRoute] string genreName, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> GetMusicGenre([FromRoute] 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<BaseItemDto> GetPerson([FromRoute] string name, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> 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 /// <param name="userId">User id.</param> /// <param name="itemId">Item id.</param> /// <param name="mediaSourceId">The id of the MediaSource.</param> - /// <param name="canSeek">Indicates if the client can seek.</param> /// <param name="audioStreamIndex">The audio stream index.</param> /// <param name="subtitleStreamIndex">The subtitle stream index.</param> /// <param name="playMethod">The play method.</param> /// <param name="liveStreamId">The live stream id.</param> /// <param name="playSessionId">The play session id.</param> + /// <param name="canSeek">Indicates if the client can seek.</param> /// <response code="204">Play start recorded.</response> /// <returns>A <see cref="NoContentResult"/>.</returns> [HttpPost("/Users/{userId}/PlayingItems/{itemId}")] @@ -202,13 +202,13 @@ namespace Jellyfin.Api.Controllers public async Task<ActionResult> 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 /// <param name="itemId">Item id.</param> /// <param name="mediaSourceId">The id of the MediaSource.</param> /// <param name="positionTicks">Optional. The current position, in ticks. 1 tick = 10000 ms.</param> - /// <param name="isPaused">Indicates if the player is paused.</param> - /// <param name="isMuted">Indicates if the player is muted.</param> /// <param name="audioStreamIndex">The audio stream index.</param> /// <param name="subtitleStreamIndex">The subtitle stream index.</param> /// <param name="volumeLevel">Scale of 0-100.</param> @@ -244,6 +242,8 @@ namespace Jellyfin.Api.Controllers /// <param name="liveStreamId">The live stream id.</param> /// <param name="playSessionId">The play session id.</param> /// <param name="repeatMode">The repeat mode.</param> + /// <param name="isPaused">Indicates if the player is paused.</param> + /// <param name="isMuted">Indicates if the player is muted.</param> /// <response code="204">Play progress recorded.</response> /// <returns>A <see cref="NoContentResult"/>.</returns> [HttpPost("/Users/{userId}/PlayingItems/{itemId}/Progress")] @@ -252,17 +252,17 @@ namespace Jellyfin.Api.Controllers public async Task<ActionResult> 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<ActionResult> 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<SearchHintResult> 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<IEnumerable<SessionInfo>> 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 /// <returns>An <see cref="OkResult"/> containing the studio.</returns> [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<BaseItemDto> GetStudio([FromRoute] string name, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> GetStudio([FromRoute] 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 /// <param name="userId">The user id.</param> /// <param name="mediaType">The media types.</param> /// <param name="type">The type.</param> - /// <param name="enableTotalRecordCount">Whether to enable the total record count.</param> /// <param name="startIndex">Optional. The start index.</param> /// <param name="limit">Optional. The limit.</param> + /// <param name="enableTotalRecordCount">Whether to enable the total record count.</param> /// <response code="200">Suggestions returned.</response> /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the suggestions.</returns> [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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> 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<BaseItem> episodes; @@ -312,7 +318,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult<QueryResult<BaseItemDto>> 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 /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns> [HttpPost("/Users/{userId}/Items/{itemId}/Rating")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute] Guid userId, [FromRoute] Guid itemId, [FromQuery] bool likes) + public ActionResult<UserItemDataDto> UpdateUserItemRating([FromRoute] 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<IEnumerable<BaseItemDto>> 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 /// </summary> /// <param name="userId">User id.</param> /// <param name="includeExternalContent">Whether or not to include external views such as channels or live tv.</param> - /// <param name="includeHidden">Whether or not to include hidden content.</param> /// <param name="presetViews">Preset views.</param> + /// <param name="includeHidden">Whether or not to include hidden content.</param> /// <response code="200">User views returned.</response> /// <returns>An <see cref="OkResult"/> containing the user views.</returns> [HttpGet("/Users/{userId}/Views")] @@ -65,8 +65,8 @@ namespace Jellyfin.Api.Controllers public ActionResult<QueryResult<BaseItemDto>> 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<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid userId) + public ActionResult<QueryResult<BaseItemDto>> 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<BaseItemDto> GetYear([FromRoute] int year, [FromQuery] Guid userId) + public ActionResult<BaseItemDto> 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<BaseItem, List<PersonInfo>, List<PersonInfo>, 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) |
