Make query parameters nullable or set default value

This commit is contained in:
crobibero 2020-07-07 09:10:51 -06:00
parent 2eef7d4913
commit 5d34b07d1f
31 changed files with 442 additions and 408 deletions

View File

@ -52,7 +52,7 @@ namespace Jellyfin.Api.Auth
{ {
// Ensure claim has userId. // Ensure claim has userId.
var userId = ClaimHelpers.GetUserId(claimsPrincipal); var userId = ClaimHelpers.GetUserId(claimsPrincipal);
if (userId == null) if (!userId.HasValue)
{ {
return false; return false;
} }

View File

@ -52,7 +52,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSimilarAlbums( public ActionResult<QueryResult<BaseItemDto>> GetSimilarAlbums(
[FromRoute] string albumId, [FromRoute] string albumId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? excludeArtistIds, [FromQuery] string? excludeArtistIds,
[FromQuery] int? limit) [FromQuery] int? limit)
{ {
@ -84,7 +84,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetSimilarArtists( public ActionResult<QueryResult<BaseItemDto>> GetSimilarArtists(
[FromRoute] string artistId, [FromRoute] string artistId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? excludeArtistIds, [FromQuery] string? excludeArtistIds,
[FromQuery] int? limit) [FromQuery] int? limit)
{ {

View File

@ -83,31 +83,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -119,9 +119,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -292,31 +292,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -328,9 +328,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -469,15 +469,15 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the artist.</returns> /// <returns>An <see cref="OkResult"/> containing the artist.</returns>
[HttpGet("{name}")] [HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)] [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 dtoOptions = new DtoOptions().AddClientFields(Request);
var item = _libraryManager.GetArtist(name, dtoOptions); 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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -53,7 +53,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet] [HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetChannels( public ActionResult<QueryResult<BaseItemDto>> GetChannels(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] bool? supportsLatestItems, [FromQuery] bool? supportsLatestItems,
@ -64,7 +64,7 @@ namespace Jellyfin.Api.Controllers
{ {
Limit = limit, Limit = limit,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId, UserId = userId ?? Guid.Empty,
SupportsLatestItems = supportsLatestItems, SupportsLatestItems = supportsLatestItems,
SupportsMediaDeletion = supportsMediaDeletion, SupportsMediaDeletion = supportsMediaDeletion,
IsFavorite = isFavorite IsFavorite = isFavorite
@ -124,9 +124,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? sortBy, [FromQuery] string? sortBy,
[FromQuery] string? fields) [FromQuery] string? fields)
{ {
var user = userId == null var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId.Value); : null;
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {
@ -195,13 +195,13 @@ namespace Jellyfin.Api.Controllers
[FromQuery] Guid? userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string channelIds) [FromQuery] string? channelIds)
{ {
var user = userId == null || userId == Guid.Empty var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId.Value); : null;
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
{ {

View File

@ -44,8 +44,8 @@ namespace Jellyfin.Api.Controllers
/// </summary> /// </summary>
/// <param name="name">The name of the collection.</param> /// <param name="name">The name of the collection.</param>
/// <param name="ids">Item Ids to add to 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="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> /// <response code="200">Collection created.</response>
/// <returns>A <see cref="CollectionCreationOptions"/> with information about the new collection.</returns> /// <returns>A <see cref="CollectionCreationOptions"/> with information about the new collection.</returns>
[HttpPost] [HttpPost]
@ -53,8 +53,8 @@ namespace Jellyfin.Api.Controllers
public ActionResult<CollectionCreationResult> CreateCollection( public ActionResult<CollectionCreationResult> CreateCollection(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] string? ids, [FromQuery] string? ids,
[FromQuery] bool isLocked, [FromQuery] Guid? parentId,
[FromQuery] Guid? parentId) [FromQuery] bool isLocked = false)
{ {
var userId = _authContext.GetAuthorizationInfo(Request).UserId; var userId = _authContext.GetAuthorizationInfo(Request).UserId;

View File

@ -57,9 +57,9 @@ namespace Jellyfin.Api.Controllers
? null ? null
: _libraryManager.GetItemById(parentId); : _libraryManager.GetItemById(parentId);
var user = userId == null || userId == Guid.Empty var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId.Value); : null;
if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase)
|| string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase)
@ -152,9 +152,9 @@ namespace Jellyfin.Api.Controllers
? null ? null
: _libraryManager.GetItemById(parentId); : _libraryManager.GetItemById(parentId);
var user = userId == null || userId == Guid.Empty var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId.Value); : null;
if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase)
|| string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase)

View File

@ -84,31 +84,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -120,9 +120,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the genre.</returns> /// <returns>An <see cref="OkResult"/> containing the genre.</returns>
[HttpGet("{genreName}")] [HttpGet("{genreName}")]
[ProducesResponseType(StatusCodes.Status200OK)] [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() var dtoOptions = new DtoOptions()
.AddClientFields(Request); .AddClientFields(Request);
@ -280,9 +280,9 @@ namespace Jellyfin.Api.Controllers
item = _libraryManager.GetGenre(genreName); 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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -63,7 +63,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromSong( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromSong(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -72,7 +72,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -98,7 +100,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromAlbum( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromAlbum(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -107,7 +109,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var album = _libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -133,7 +137,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromPlaylist( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromPlaylist(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -142,7 +146,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var playlist = (Playlist)_libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -168,7 +174,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenre( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenre(
[FromRoute] string? name, [FromRoute] string? name,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -176,7 +182,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string? enableImageTypes) [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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -202,7 +210,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -211,7 +219,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -237,7 +247,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -246,7 +256,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -272,7 +284,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromItem( public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromItem(
[FromRoute] Guid id, [FromRoute] Guid id,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
@ -281,7 +293,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes) [FromQuery] string? enableImageTypes)
{ {
var item = _libraryManager.GetItemById(id); 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)
@ -290,7 +304,7 @@ namespace Jellyfin.Api.Controllers
return GetResult(items, user, limit, dtoOptions); 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; var list = items;

View File

@ -143,8 +143,8 @@ namespace Jellyfin.Api.Controllers
[HttpGet("/Users/{uId}/Items")] [HttpGet("/Users/{uId}/Items")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetItems( public ActionResult<QueryResult<BaseItemDto>> GetItems(
[FromRoute] Guid uId, [FromRoute] Guid? uId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? maxOfficialRating, [FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeSong,
[FromQuery] bool? hasThemeVideo, [FromQuery] bool? hasThemeVideo,
@ -226,9 +226,11 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
// use user id route parameter over query parameter // 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request) .AddClientFields(Request)

View File

@ -146,11 +146,11 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ThemeMediaResult> GetThemeSongs( public ActionResult<ThemeMediaResult> GetThemeSongs(
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent) [FromQuery] bool inheritFromParent = false)
{ {
var user = !userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId) ? _userManager.GetUserById(userId.Value)
: null; : null;
var item = itemId.Equals(Guid.Empty) var item = itemId.Equals(Guid.Empty)
@ -212,11 +212,11 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<ThemeMediaResult> GetThemeVideos( public ActionResult<ThemeMediaResult> GetThemeVideos(
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent) [FromQuery] bool inheritFromParent = false)
{ {
var user = !userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId) ? _userManager.GetUserById(userId.Value)
: null; : null;
var item = itemId.Equals(Guid.Empty) var item = itemId.Equals(Guid.Empty)
@ -277,8 +277,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<AllThemeMediaResult> GetThemeMedia( public ActionResult<AllThemeMediaResult> GetThemeMedia(
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] bool inheritFromParent) [FromQuery] bool inheritFromParent = false)
{ {
var themeSongs = GetThemeSongs( var themeSongs = GetThemeSongs(
itemId, itemId,
@ -361,12 +361,14 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status401Unauthorized)]
public ActionResult DeleteItems([FromQuery] string ids) public ActionResult DeleteItems([FromQuery] string? ids)
{ {
var itemIds = string.IsNullOrWhiteSpace(ids) if (string.IsNullOrEmpty(ids))
? Array.Empty<string>() {
: RequestHelpers.Split(ids, ',', true); return NoContent();
}
var itemIds = RequestHelpers.Split(ids, ',', true);
foreach (var i in itemIds) foreach (var i in itemIds)
{ {
var item = _libraryManager.GetItemById(i); var item = _libraryManager.GetItemById(i);
@ -403,12 +405,12 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<ItemCounts> GetItemCounts( public ActionResult<ItemCounts> GetItemCounts(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] bool? isFavorite) [FromQuery] bool? isFavorite)
{ {
var user = userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId); : null;
var counts = new ItemCounts var counts = new ItemCounts
{ {
@ -437,7 +439,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [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); var item = _libraryManager.GetItemById(itemId);
@ -448,8 +450,8 @@ namespace Jellyfin.Api.Controllers
var baseItemDtos = new List<BaseItemDto>(); var baseItemDtos = new List<BaseItemDto>();
var user = !userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId) ? _userManager.GetUserById(userId.Value)
: null; : null;
var dtoOptions = new DtoOptions().AddClientFields(Request); var dtoOptions = new DtoOptions().AddClientFields(Request);
@ -688,7 +690,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<QueryResult<BaseItemDto>> GetSimilarItems( public ActionResult<QueryResult<BaseItemDto>> GetSimilarItems(
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] string? excludeArtistIds, [FromQuery] string? excludeArtistIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields) [FromQuery] string? fields)
{ {
@ -737,7 +739,9 @@ namespace Jellyfin.Api.Controllers
[HttpGet("/Libraries/AvailableOptions")] [HttpGet("/Libraries/AvailableOptions")]
[Authorize(Policy = Policies.FirstTimeSetupOrElevated)] [Authorize(Policy = Policies.FirstTimeSetupOrElevated)]
[ProducesResponseType(StatusCodes.Status200OK)] [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(); var result = new LibraryOptionsResultDto();
@ -878,13 +882,15 @@ namespace Jellyfin.Api.Controllers
private QueryResult<BaseItemDto> GetSimilarItemsResult( private QueryResult<BaseItemDto> GetSimilarItemsResult(
BaseItem item, BaseItem item,
string? excludeArtistIds, string? excludeArtistIds,
Guid userId, Guid? userId,
int? limit, int? limit,
string? fields, string? fields,
string[] includeItemTypes, string[] includeItemTypes,
bool isMovie) 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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request); .AddClientFields(Request);

View File

@ -64,9 +64,9 @@ namespace Jellyfin.Api.Controllers
/// </summary> /// </summary>
/// <param name="name">The name of the virtual folder.</param> /// <param name="name">The name of the virtual folder.</param>
/// <param name="collectionType">The type of the collection.</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="paths">The paths of the virtual folder.</param>
/// <param name="libraryOptions">The library options.</param> /// <param name="libraryOptions">The library options.</param>
/// <param name="refreshLibrary">Whether to refresh the library.</param>
/// <response code="204">Folder added.</response> /// <response code="204">Folder added.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns> /// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost] [HttpPost]
@ -74,9 +74,9 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> AddVirtualFolder( public async Task<ActionResult> AddVirtualFolder(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] string? collectionType, [FromQuery] string? collectionType,
[FromQuery] bool refreshLibrary,
[FromQuery] string[] paths, [FromQuery] string[] paths,
[FromQuery] LibraryOptions libraryOptions) [FromQuery] LibraryOptions? libraryOptions,
[FromQuery] bool refreshLibrary = false)
{ {
libraryOptions ??= new LibraryOptions(); libraryOptions ??= new LibraryOptions();
@ -101,7 +101,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<ActionResult> RemoveVirtualFolder( public async Task<ActionResult> RemoveVirtualFolder(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] bool refreshLibrary) [FromQuery] bool refreshLibrary = false)
{ {
await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false); await _libraryManager.RemoveVirtualFolder(name, refreshLibrary).ConfigureAwait(false);
return NoContent(); return NoContent();
@ -125,7 +125,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult RenameVirtualFolder( public ActionResult RenameVirtualFolder(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] string? newName, [FromQuery] string? newName,
[FromQuery] bool refreshLibrary) [FromQuery] bool refreshLibrary = false)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
@ -207,8 +207,8 @@ namespace Jellyfin.Api.Controllers
public ActionResult AddMediaPath( public ActionResult AddMediaPath(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] string? path, [FromQuery] string? path,
[FromQuery] MediaPathInfo pathInfo, [FromQuery] MediaPathInfo? pathInfo,
[FromQuery] bool refreshLibrary) [FromQuery] bool refreshLibrary = false)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
@ -257,7 +257,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateMediaPath( public ActionResult UpdateMediaPath(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] MediaPathInfo pathInfo) [FromQuery] MediaPathInfo? pathInfo)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
@ -282,7 +282,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult RemoveMediaPath( public ActionResult RemoveMediaPath(
[FromQuery] string? name, [FromQuery] string? name,
[FromQuery] string? path, [FromQuery] string? path,
[FromQuery] bool refreshLibrary) [FromQuery] bool refreshLibrary = false)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
@ -328,7 +328,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult UpdateLibraryOptions( public ActionResult UpdateLibraryOptions(
[FromQuery] string? id, [FromQuery] string? id,
[FromQuery] LibraryOptions libraryOptions) [FromQuery] LibraryOptions? libraryOptions)
{ {
var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(id); var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(id);

View File

@ -113,7 +113,6 @@ namespace Jellyfin.Api.Controllers
/// <param name="isFavorite">Optional. Filter by channels that are favorites, or not.</param> /// <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="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="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="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="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> /// <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="enableUserData">Optional. Include user data.</param>
/// <param name="sortBy">Optional. Key to sort by.</param> /// <param name="sortBy">Optional. Key to sort by.</param>
/// <param name="sortOrder">Optional. Sort order.</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> /// <param name="addCurrentProgram">Optional. Adds current program info to each channel.</param>
/// <response code="200">Available live tv channels returned.</response> /// <response code="200">Available live tv channels returned.</response>
/// <returns> /// <returns>
@ -131,7 +131,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
public ActionResult<QueryResult<BaseItemDto>> GetChannels( public ActionResult<QueryResult<BaseItemDto>> GetChannels(
[FromQuery] ChannelType? type, [FromQuery] ChannelType? type,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] bool? isMovie, [FromQuery] bool? isMovie,
[FromQuery] bool? isSeries, [FromQuery] bool? isSeries,
@ -142,14 +142,14 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] bool? isLiked, [FromQuery] bool? isLiked,
[FromQuery] bool? isDisliked, [FromQuery] bool? isDisliked,
[FromQuery] bool enableFavoriteSorting,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] string sortBy, [FromQuery] string? sortBy,
[FromQuery] SortOrder? sortOrder, [FromQuery] SortOrder? sortOrder,
[FromQuery] bool enableFavoriteSorting = false,
[FromQuery] bool addCurrentProgram = true) [FromQuery] bool addCurrentProgram = true)
{ {
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers
new LiveTvChannelQuery new LiveTvChannelQuery
{ {
ChannelType = type, ChannelType = type,
UserId = userId, UserId = userId ?? Guid.Empty,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
IsFavorite = isFavorite, IsFavorite = isFavorite,
@ -180,9 +180,9 @@ namespace Jellyfin.Api.Controllers
dtoOptions, dtoOptions,
CancellationToken.None); CancellationToken.None);
var user = userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId); : null;
var fieldsList = dtoOptions.Fields.ToList(); var fieldsList = dtoOptions.Fields.ToList();
fieldsList.Remove(ItemFields.CanDelete); fieldsList.Remove(ItemFields.CanDelete);
@ -210,9 +210,11 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Channels/{channelId}")] [HttpGet("Channels/{channelId}")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [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) var item = channelId.Equals(Guid.Empty)
? _libraryManager.GetUserRootFolder() ? _libraryManager.GetUserRootFolder()
: _libraryManager.GetItemById(channelId); : _libraryManager.GetItemById(channelId);
@ -250,17 +252,17 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
public ActionResult<QueryResult<BaseItemDto>> GetRecordings( public ActionResult<QueryResult<BaseItemDto>> GetRecordings(
[FromQuery] string channelId, [FromQuery] string? channelId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] RecordingStatus? status, [FromQuery] RecordingStatus? status,
[FromQuery] bool? isInProgress, [FromQuery] bool? isInProgress,
[FromQuery] string seriesTimerId, [FromQuery] string? seriesTimerId,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] bool? isMovie, [FromQuery] bool? isMovie,
[FromQuery] bool? isSeries, [FromQuery] bool? isSeries,
@ -279,7 +281,7 @@ namespace Jellyfin.Api.Controllers
new RecordingQuery new RecordingQuery
{ {
ChannelId = channelId, ChannelId = channelId,
UserId = userId, UserId = userId ?? Guid.Empty,
StartIndex = startIndex, StartIndex = startIndex,
Limit = limit, Limit = limit,
Status = status, 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 = "enableUserData", Justification = "Imported from ServiceStack")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableTotalRecordCount", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableTotalRecordCount", Justification = "Imported from ServiceStack")]
public ActionResult<QueryResult<BaseItemDto>> GetRecordingsSeries( public ActionResult<QueryResult<BaseItemDto>> GetRecordingsSeries(
[FromQuery] string channelId, [FromQuery] string? channelId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string groupId, [FromQuery] string? groupId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] RecordingStatus? status, [FromQuery] RecordingStatus? status,
[FromQuery] bool? isInProgress, [FromQuery] bool? isInProgress,
[FromQuery] string seriesTimerId, [FromQuery] string? seriesTimerId,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -365,7 +367,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[Obsolete("This endpoint is obsolete.")] [Obsolete("This endpoint is obsolete.")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")] [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>(); return new QueryResult<BaseItemDto>();
} }
@ -379,9 +381,11 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Recordings/Folders")] [HttpGet("Recordings/Folders")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [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 folders = _liveTvManager.GetRecordingFolders(user);
var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user); var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user);
@ -403,9 +407,11 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Recordings/{recordingId}")] [HttpGet("Recordings/{recordingId}")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [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 item = recordingId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
@ -457,7 +463,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Timers/Defaults")] [HttpGet("Timers/Defaults")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [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) return string.IsNullOrEmpty(programId)
? await _liveTvManager.GetNewTimerDefaults(CancellationToken.None).ConfigureAwait(false) ? await _liveTvManager.GetNewTimerDefaults(CancellationToken.None).ConfigureAwait(false)
@ -478,8 +484,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
public async Task<ActionResult<QueryResult<TimerInfoDto>>> GetTimers( public async Task<ActionResult<QueryResult<TimerInfoDto>>> GetTimers(
[FromQuery] string channelId, [FromQuery] string? channelId,
[FromQuery] string seriesTimerId, [FromQuery] string? seriesTimerId,
[FromQuery] bool? isActive, [FromQuery] bool? isActive,
[FromQuery] bool? isScheduled) [FromQuery] bool? isScheduled)
{ {
@ -532,8 +538,8 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
public async Task<ActionResult<QueryResult<BaseItemDto>>> GetPrograms( public async Task<ActionResult<QueryResult<BaseItemDto>>> GetPrograms(
[FromQuery] string channelIds, [FromQuery] string? channelIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] DateTime? minStartDate, [FromQuery] DateTime? minStartDate,
[FromQuery] bool? hasAired, [FromQuery] bool? hasAired,
[FromQuery] bool? isAiring, [FromQuery] bool? isAiring,
@ -547,20 +553,22 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? isSports, [FromQuery] bool? isSports,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string sortBy, [FromQuery] string? sortBy,
[FromQuery] string sortOrder, [FromQuery] string? sortOrder,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] string seriesTimerId, [FromQuery] string? seriesTimerId,
[FromQuery] Guid librarySeriesId, [FromQuery] Guid? librarySeriesId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] bool enableTotalRecordCount = true) [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) var query = new InternalItemsQuery(user)
{ {
@ -590,7 +598,7 @@ namespace Jellyfin.Api.Controllers
{ {
query.IsSeries = true; query.IsSeries = true;
if (_libraryManager.GetItemById(librarySeriesId) is Series series) if (_libraryManager.GetItemById(librarySeriesId ?? Guid.Empty) is Series series)
{ {
query.Name = series.Name; query.Name = series.Name;
} }
@ -684,7 +692,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetRecommendedPrograms( public ActionResult<QueryResult<BaseItemDto>> GetRecommendedPrograms(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] bool? isAiring, [FromQuery] bool? isAiring,
[FromQuery] bool? hasAired, [FromQuery] bool? hasAired,
@ -695,13 +703,15 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? isSports, [FromQuery] bool? isSports,
[FromQuery] bool? enableImages, [FromQuery] bool? enableImages,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] bool enableTotalRecordCount = true) [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) var query = new InternalItemsQuery(user)
{ {
@ -736,11 +746,11 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<BaseItemDto>> GetProgram( public async Task<ActionResult<BaseItemDto>> GetProgram(
[FromRoute] string programId, [FromRoute] string programId,
[FromQuery] Guid userId) [FromQuery] Guid? userId)
{ {
var user = userId.Equals(Guid.Empty) var user = userId.HasValue && !userId.Equals(Guid.Empty)
? null ? _userManager.GetUserById(userId.Value)
: _userManager.GetUserById(userId); : null;
return await _liveTvManager.GetProgram(programId, CancellationToken.None, user).ConfigureAwait(false); return await _liveTvManager.GetProgram(programId, CancellationToken.None, user).ConfigureAwait(false);
} }
@ -856,12 +866,12 @@ namespace Jellyfin.Api.Controllers
[HttpGet("SeriesTimers")] [HttpGet("SeriesTimers")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [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( return await _liveTvManager.GetSeriesTimers(
new SeriesTimerQuery new SeriesTimerQuery
{ {
SortOrder = sortOrder, SortOrder = sortOrder ?? SortOrder.Ascending,
SortBy = sortBy SortBy = sortBy
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);
} }
@ -925,7 +935,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("This endpoint is obsolete.")] [Obsolete("This endpoint is obsolete.")]
public ActionResult<BaseItemDto> GetRecordingGroup([FromQuery] Guid groupId) public ActionResult<BaseItemDto> GetRecordingGroup([FromQuery] Guid? groupId)
{ {
return NotFound(); return NotFound();
} }
@ -966,7 +976,7 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("TunerHosts")] [HttpDelete("TunerHosts")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult DeleteTunerHost([FromQuery] string id) public ActionResult DeleteTunerHost([FromQuery] string? id)
{ {
var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv"); var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv");
config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray(); config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
@ -990,10 +1000,10 @@ namespace Jellyfin.Api.Controllers
/// <summary> /// <summary>
/// Adds a listings provider. /// Adds a listings provider.
/// </summary> /// </summary>
/// <param name="validateLogin">Validate login.</param>
/// <param name="validateListings">Validate listings.</param>
/// <param name="pw">Password.</param> /// <param name="pw">Password.</param>
/// <param name="listingsProviderInfo">New listings info.</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> /// <response code="200">Created listings provider returned.</response>
/// <returns>A <see cref="OkResult"/> containing the created listings provider.</returns> /// <returns>A <see cref="OkResult"/> containing the created listings provider.</returns>
[HttpGet("ListingProviders")] [HttpGet("ListingProviders")]
@ -1001,10 +1011,10 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA5350:RemoveSha1", MessageId = "AddListingProvider", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA5350:RemoveSha1", MessageId = "AddListingProvider", Justification = "Imported from ServiceStack")]
public async Task<ActionResult<ListingsProviderInfo>> AddListingProvider( public async Task<ActionResult<ListingsProviderInfo>> AddListingProvider(
[FromQuery] bool validateLogin, [FromQuery] string? pw,
[FromQuery] bool validateListings, [FromBody] ListingsProviderInfo listingsProviderInfo,
[FromQuery] string pw, [FromQuery] bool validateListings = false,
[FromBody] ListingsProviderInfo listingsProviderInfo) [FromQuery] bool validateLogin = false)
{ {
using var sha = SHA1.Create(); using var sha = SHA1.Create();
if (!string.IsNullOrEmpty(pw)) if (!string.IsNullOrEmpty(pw))
@ -1024,7 +1034,7 @@ namespace Jellyfin.Api.Controllers
[HttpDelete("ListingProviders")] [HttpDelete("ListingProviders")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult DeleteListingProvider([FromQuery] string id) public ActionResult DeleteListingProvider([FromQuery] string? id)
{ {
_liveTvManager.DeleteListingsProvider(id); _liveTvManager.DeleteListingsProvider(id);
return NoContent(); return NoContent();
@ -1043,10 +1053,10 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<IEnumerable<NameIdPair>>> GetLineups( public async Task<ActionResult<IEnumerable<NameIdPair>>> GetLineups(
[FromQuery] string id, [FromQuery] string? id,
[FromQuery] string type, [FromQuery] string? type,
[FromQuery] string location, [FromQuery] string? location,
[FromQuery] string country) [FromQuery] string? country)
{ {
return await _liveTvManager.GetLineups(type, id, country, location).ConfigureAwait(false); return await _liveTvManager.GetLineups(type, id, country, location).ConfigureAwait(false);
} }
@ -1079,7 +1089,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("ChannelMappingOptions")] [HttpGet("ChannelMappingOptions")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [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"); var config = _configurationManager.GetConfiguration<LiveTvOptions>("livetv");
@ -1120,9 +1130,9 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<TunerChannelMapping>> SetChannelMapping( public async Task<ActionResult<TunerChannelMapping>> SetChannelMapping(
[FromQuery] string providerId, [FromQuery] string? providerId,
[FromQuery] string tunerChannelId, [FromQuery] string? tunerChannelId,
[FromQuery] string providerChannelId) [FromQuery] string? providerChannelId)
{ {
return await _liveTvManager.SetChannelMapping(providerId, tunerChannelId, providerChannelId).ConfigureAwait(false); return await _liveTvManager.SetChannelMapping(providerId, tunerChannelId, providerChannelId).ConfigureAwait(false);
} }
@ -1149,7 +1159,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Tuners/Discvover")] [HttpGet("Tuners/Discvover")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [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); return await _liveTvManager.DiscoverTuners(newDevicesOnly, CancellationToken.None).ConfigureAwait(false);
} }

View File

@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="Task"/> containing a <see cref="PlaybackInfoResponse"/> with the playback information.</returns> /// <returns>A <see cref="Task"/> containing a <see cref="PlaybackInfoResponse"/> with the playback information.</returns>
[HttpGet("/Items/{itemId}/PlaybackInfo")] [HttpGet("/Items/{itemId}/PlaybackInfo")]
[ProducesResponseType(StatusCodes.Status200OK)] [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); return await GetPlaybackInfoInternal(itemId, userId, null, null).ConfigureAwait(false);
} }
@ -118,16 +118,16 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<PlaybackInfoResponse>> GetPostedPlaybackInfo( public async Task<ActionResult<PlaybackInfoResponse>> GetPostedPlaybackInfo(
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] long? maxStreamingBitrate, [FromQuery] long? maxStreamingBitrate,
[FromQuery] long? startTimeTicks, [FromQuery] long? startTimeTicks,
[FromQuery] int? audioStreamIndex, [FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex, [FromQuery] int? subtitleStreamIndex,
[FromQuery] int? maxAudioChannels, [FromQuery] int? maxAudioChannels,
[FromQuery] string mediaSourceId, [FromQuery] string? mediaSourceId,
[FromQuery] string liveStreamId, [FromQuery] string? liveStreamId,
[FromQuery] DeviceProfile deviceProfile, [FromQuery] DeviceProfile? deviceProfile,
[FromQuery] bool autoOpenLiveStream, [FromQuery] bool autoOpenLiveStream = false,
[FromQuery] bool enableDirectPlay = true, [FromQuery] bool enableDirectPlay = true,
[FromQuery] bool enableDirectStream = true, [FromQuery] bool enableDirectStream = true,
[FromQuery] bool enableTranscoding = true, [FromQuery] bool enableTranscoding = true,
@ -165,12 +165,12 @@ namespace Jellyfin.Api.Controllers
authInfo, authInfo,
maxStreamingBitrate ?? profile.MaxStreamingBitrate, maxStreamingBitrate ?? profile.MaxStreamingBitrate,
startTimeTicks ?? 0, startTimeTicks ?? 0,
mediaSourceId, mediaSourceId ?? string.Empty,
audioStreamIndex, audioStreamIndex,
subtitleStreamIndex, subtitleStreamIndex,
maxAudioChannels, maxAudioChannels,
info!.PlaySessionId!, info!.PlaySessionId!,
userId, userId ?? Guid.Empty,
enableDirectPlay, enableDirectPlay,
enableDirectStream, enableDirectStream,
enableTranscoding, enableTranscoding,
@ -199,7 +199,7 @@ namespace Jellyfin.Api.Controllers
PlaySessionId = info.PlaySessionId, PlaySessionId = info.PlaySessionId,
StartTimeTicks = startTimeTicks, StartTimeTicks = startTimeTicks,
SubtitleStreamIndex = subtitleStreamIndex, SubtitleStreamIndex = subtitleStreamIndex,
UserId = userId, UserId = userId ?? Guid.Empty,
OpenToken = mediaSource.OpenToken OpenToken = mediaSource.OpenToken
}).ConfigureAwait(false); }).ConfigureAwait(false);
@ -239,16 +239,16 @@ namespace Jellyfin.Api.Controllers
[HttpPost("/LiveStreams/Open")] [HttpPost("/LiveStreams/Open")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<LiveStreamResponse>> OpenLiveStream( public async Task<ActionResult<LiveStreamResponse>> OpenLiveStream(
[FromQuery] string openToken, [FromQuery] string? openToken,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string playSessionId, [FromQuery] string? playSessionId,
[FromQuery] long? maxStreamingBitrate, [FromQuery] long? maxStreamingBitrate,
[FromQuery] long? startTimeTicks, [FromQuery] long? startTimeTicks,
[FromQuery] int? audioStreamIndex, [FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex, [FromQuery] int? subtitleStreamIndex,
[FromQuery] int? maxAudioChannels, [FromQuery] int? maxAudioChannels,
[FromQuery] Guid itemId, [FromQuery] Guid? itemId,
[FromQuery] DeviceProfile deviceProfile, [FromQuery] DeviceProfile? deviceProfile,
[FromQuery] MediaProtocol[] directPlayProtocols, [FromQuery] MediaProtocol[] directPlayProtocols,
[FromQuery] bool enableDirectPlay = true, [FromQuery] bool enableDirectPlay = true,
[FromQuery] bool enableDirectStream = true) [FromQuery] bool enableDirectStream = true)
@ -256,14 +256,14 @@ namespace Jellyfin.Api.Controllers
var request = new LiveStreamRequest var request = new LiveStreamRequest
{ {
OpenToken = openToken, OpenToken = openToken,
UserId = userId, UserId = userId ?? Guid.Empty,
PlaySessionId = playSessionId, PlaySessionId = playSessionId,
MaxStreamingBitrate = maxStreamingBitrate, MaxStreamingBitrate = maxStreamingBitrate,
StartTimeTicks = startTimeTicks, StartTimeTicks = startTimeTicks,
AudioStreamIndex = audioStreamIndex, AudioStreamIndex = audioStreamIndex,
SubtitleStreamIndex = subtitleStreamIndex, SubtitleStreamIndex = subtitleStreamIndex,
MaxAudioChannels = maxAudioChannels, MaxAudioChannels = maxAudioChannels,
ItemId = itemId, ItemId = itemId ?? Guid.Empty,
DeviceProfile = deviceProfile, DeviceProfile = deviceProfile,
EnableDirectPlay = enableDirectPlay, EnableDirectPlay = enableDirectPlay,
EnableDirectStream = enableDirectStream, EnableDirectStream = enableDirectStream,
@ -280,7 +280,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="NoContentResult"/> indicating success.</returns> /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
[HttpPost("/LiveStreams/Close")] [HttpPost("/LiveStreams/Close")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult CloseLiveStream([FromQuery] string liveStreamId) public ActionResult CloseLiveStream([FromQuery] string? liveStreamId)
{ {
_mediaSourceManager.CloseLiveStream(liveStreamId).GetAwaiter().GetResult(); _mediaSourceManager.CloseLiveStream(liveStreamId).GetAwaiter().GetResult();
return NoContent(); return NoContent();
@ -325,11 +325,13 @@ namespace Jellyfin.Api.Controllers
private async Task<PlaybackInfoResponse> GetPlaybackInfoInternal( private async Task<PlaybackInfoResponse> GetPlaybackInfoInternal(
Guid id, Guid id,
Guid userId, Guid? userId,
string? mediaSourceId = null, string? mediaSourceId = null,
string? liveStreamId = 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 item = _libraryManager.GetItemById(id);
var result = new PlaybackInfoResponse(); var result = new PlaybackInfoResponse();

View File

@ -55,32 +55,22 @@ namespace Jellyfin.Api.Controllers
/// </summary> /// </summary>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param> /// <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="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="fields">Optional. The fields to return.</param>
/// <param name="categoryLimit">The max number of categories 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> /// <param name="itemLimit">The max number of items to return per category.</param>
/// <response code="200">Movie recommendations returned.</response> /// <response code="200">Movie recommendations returned.</response>
/// <returns>The list of movie recommendations.</returns> /// <returns>The list of movie recommendations.</returns>
[HttpGet("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<IEnumerable<RecommendationDto>> GetMovieRecommendations( public ActionResult<IEnumerable<RecommendationDto>> GetMovieRecommendations(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] bool? enableImages,
[FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit,
[FromQuery] string? enableImageTypes,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] int categoryLimit = 5, [FromQuery] int categoryLimit = 5,
[FromQuery] int itemLimit = 8) [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() var dtoOptions = new DtoOptions()
.AddItemFields(fields) .AddItemFields(fields)
.AddClientFields(Request); .AddClientFields(Request);
@ -185,7 +175,7 @@ namespace Jellyfin.Api.Controllers
} }
private IEnumerable<RecommendationDto> GetWithDirector( private IEnumerable<RecommendationDto> GetWithDirector(
User user, User? user,
IEnumerable<string> names, IEnumerable<string> names,
int itemLimit, int itemLimit,
DtoOptions dtoOptions, 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) }; var itemTypes = new List<string> { nameof(Movie) };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) 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) }; var itemTypes = new List<string> { nameof(Movie) };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)

View File

@ -83,31 +83,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -119,9 +119,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -258,7 +258,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns> /// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns>
[HttpGet("{genreName}")] [HttpGet("{genreName}")]
[ProducesResponseType(StatusCodes.Status200OK)] [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); var dtoOptions = new DtoOptions().AddClientFields(Request);
@ -273,9 +273,9 @@ namespace Jellyfin.Api.Controllers
item = _libraryManager.GetMusicGenre(genreName); 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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -80,31 +80,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -116,9 +116,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -259,7 +259,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{name}")] [HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [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() var dtoOptions = new DtoOptions()
.AddClientFields(Request); .AddClientFields(Request);
@ -270,9 +270,9 @@ namespace Jellyfin.Api.Controllers
return NotFound(); 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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -86,9 +86,9 @@ namespace Jellyfin.Api.Controllers
public ActionResult AddToPlaylist( public ActionResult AddToPlaylist(
[FromRoute] string? playlistId, [FromRoute] string? playlistId,
[FromQuery] string? ids, [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(); return NoContent();
} }

View File

@ -188,12 +188,12 @@ namespace Jellyfin.Api.Controllers
/// <param name="userId">User id.</param> /// <param name="userId">User id.</param>
/// <param name="itemId">Item id.</param> /// <param name="itemId">Item id.</param>
/// <param name="mediaSourceId">The id of the MediaSource.</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="audioStreamIndex">The audio stream index.</param>
/// <param name="subtitleStreamIndex">The subtitle stream index.</param> /// <param name="subtitleStreamIndex">The subtitle stream index.</param>
/// <param name="playMethod">The play method.</param> /// <param name="playMethod">The play method.</param>
/// <param name="liveStreamId">The live stream id.</param> /// <param name="liveStreamId">The live stream id.</param>
/// <param name="playSessionId">The play session 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> /// <response code="204">Play start recorded.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns> /// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("/Users/{userId}/PlayingItems/{itemId}")] [HttpPost("/Users/{userId}/PlayingItems/{itemId}")]
@ -202,13 +202,13 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> OnPlaybackStart( public async Task<ActionResult> OnPlaybackStart(
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] string mediaSourceId, [FromQuery] string? mediaSourceId,
[FromQuery] bool canSeek,
[FromQuery] int? audioStreamIndex, [FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex, [FromQuery] int? subtitleStreamIndex,
[FromQuery] PlayMethod playMethod, [FromQuery] PlayMethod playMethod,
[FromQuery] string liveStreamId, [FromQuery] string? liveStreamId,
[FromQuery] string playSessionId) [FromQuery] string playSessionId,
[FromQuery] bool canSeek = false)
{ {
var playbackStartInfo = new PlaybackStartInfo var playbackStartInfo = new PlaybackStartInfo
{ {
@ -235,8 +235,6 @@ namespace Jellyfin.Api.Controllers
/// <param name="itemId">Item id.</param> /// <param name="itemId">Item id.</param>
/// <param name="mediaSourceId">The id of the MediaSource.</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="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="audioStreamIndex">The audio stream index.</param>
/// <param name="subtitleStreamIndex">The subtitle stream index.</param> /// <param name="subtitleStreamIndex">The subtitle stream index.</param>
/// <param name="volumeLevel">Scale of 0-100.</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="liveStreamId">The live stream id.</param>
/// <param name="playSessionId">The play session id.</param> /// <param name="playSessionId">The play session id.</param>
/// <param name="repeatMode">The repeat mode.</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> /// <response code="204">Play progress recorded.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns> /// <returns>A <see cref="NoContentResult"/>.</returns>
[HttpPost("/Users/{userId}/PlayingItems/{itemId}/Progress")] [HttpPost("/Users/{userId}/PlayingItems/{itemId}/Progress")]
@ -252,17 +252,17 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> OnPlaybackProgress( public async Task<ActionResult> OnPlaybackProgress(
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] string mediaSourceId, [FromQuery] string? mediaSourceId,
[FromQuery] long? positionTicks, [FromQuery] long? positionTicks,
[FromQuery] bool isPaused,
[FromQuery] bool isMuted,
[FromQuery] int? audioStreamIndex, [FromQuery] int? audioStreamIndex,
[FromQuery] int? subtitleStreamIndex, [FromQuery] int? subtitleStreamIndex,
[FromQuery] int? volumeLevel, [FromQuery] int? volumeLevel,
[FromQuery] PlayMethod playMethod, [FromQuery] PlayMethod playMethod,
[FromQuery] string liveStreamId, [FromQuery] string? liveStreamId,
[FromQuery] string playSessionId, [FromQuery] string playSessionId,
[FromQuery] RepeatMode repeatMode) [FromQuery] RepeatMode repeatMode,
[FromQuery] bool isPaused = false,
[FromQuery] bool isMuted = false)
{ {
var playbackProgressInfo = new PlaybackProgressInfo var playbackProgressInfo = new PlaybackProgressInfo
{ {
@ -304,11 +304,11 @@ namespace Jellyfin.Api.Controllers
public async Task<ActionResult> OnPlaybackStopped( public async Task<ActionResult> OnPlaybackStopped(
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromRoute] Guid itemId, [FromRoute] Guid itemId,
[FromQuery] string mediaSourceId, [FromQuery] string? mediaSourceId,
[FromQuery] string nextMediaType, [FromQuery] string? nextMediaType,
[FromQuery] long? positionTicks, [FromQuery] long? positionTicks,
[FromQuery] string liveStreamId, [FromQuery] string? liveStreamId,
[FromQuery] string playSessionId) [FromQuery] string? playSessionId)
{ {
var playbackStopInfo = new PlaybackStopInfo var playbackStopInfo = new PlaybackStopInfo
{ {

View File

@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string providerName, [FromQuery] string providerName,
[FromQuery] bool includeAllLanguages) [FromQuery] bool includeAllLanguages = false)
{ {
var item = _libraryManager.GetItemById(itemId); var item = _libraryManager.GetItemById(itemId);
if (item == null) if (item == null)

View File

@ -80,7 +80,7 @@ namespace Jellyfin.Api.Controllers
public ActionResult<SearchHintResult> Get( public ActionResult<SearchHintResult> Get(
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery, Required] string? searchTerm, [FromQuery, Required] string? searchTerm,
[FromQuery] string? includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string? excludeItemTypes, [FromQuery] string? excludeItemTypes,
@ -107,7 +107,7 @@ namespace Jellyfin.Api.Controllers
IncludePeople = includePeople, IncludePeople = includePeople,
IncludeStudios = includeStudios, IncludeStudios = includeStudios,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId, UserId = userId ?? Guid.Empty,
IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true),
ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true),
MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), MediaTypes = RequestHelpers.Split(mediaTypes, ',', true),

View File

@ -61,7 +61,7 @@ namespace Jellyfin.Api.Controllers
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<IEnumerable<SessionInfo>> GetSessions( public ActionResult<IEnumerable<SessionInfo>> GetSessions(
[FromQuery] Guid controllableByUserId, [FromQuery] Guid? controllableByUserId,
[FromQuery] string? deviceId, [FromQuery] string? deviceId,
[FromQuery] int? activeWithinSeconds) [FromQuery] int? activeWithinSeconds)
{ {
@ -72,15 +72,15 @@ namespace Jellyfin.Api.Controllers
result = result.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase)); 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); result = result.Where(i => i.SupportsRemoteControl);
var user = _userManager.GetUserById(controllableByUserId); var user = _userManager.GetUserById(controllableByUserId.Value);
if (!user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) 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)) if (!user.HasPermission(PermissionKind.EnableSharedDeviceControl))
@ -371,8 +371,8 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? id, [FromQuery] string? id,
[FromQuery] string? playableMediaTypes, [FromQuery] string? playableMediaTypes,
[FromQuery] string? supportedCommands, [FromQuery] string? supportedCommands,
[FromQuery] bool supportsMediaControl, [FromQuery] bool supportsMediaControl = false,
[FromQuery] bool supportsSync, [FromQuery] bool supportsSync = false,
[FromQuery] bool supportsPersistentIdentifier = true) [FromQuery] bool supportsPersistentIdentifier = true)
{ {
if (string.IsNullOrWhiteSpace(id)) if (string.IsNullOrWhiteSpace(id))

View File

@ -82,31 +82,31 @@ namespace Jellyfin.Api.Controllers
[FromQuery] double? minCommunityRating, [FromQuery] double? minCommunityRating,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string searchTerm, [FromQuery] string? searchTerm,
[FromQuery] string parentId, [FromQuery] string? parentId,
[FromQuery] string fields, [FromQuery] string? fields,
[FromQuery] string excludeItemTypes, [FromQuery] string? excludeItemTypes,
[FromQuery] string includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] string filters, [FromQuery] string? filters,
[FromQuery] bool? isFavorite, [FromQuery] bool? isFavorite,
[FromQuery] string mediaTypes, [FromQuery] string? mediaTypes,
[FromQuery] string genres, [FromQuery] string? genres,
[FromQuery] string genreIds, [FromQuery] string? genreIds,
[FromQuery] string officialRatings, [FromQuery] string? officialRatings,
[FromQuery] string tags, [FromQuery] string? tags,
[FromQuery] string years, [FromQuery] string? years,
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] string person, [FromQuery] string? person,
[FromQuery] string personIds, [FromQuery] string? personIds,
[FromQuery] string personTypes, [FromQuery] string? personTypes,
[FromQuery] string studios, [FromQuery] string? studios,
[FromQuery] string studioIds, [FromQuery] string? studioIds,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string nameStartsWithOrGreater, [FromQuery] string? nameStartsWithOrGreater,
[FromQuery] string nameStartsWith, [FromQuery] string? nameStartsWith,
[FromQuery] string nameLessThan, [FromQuery] string? nameLessThan,
[FromQuery] bool? enableImages = true, [FromQuery] bool? enableImages = true,
[FromQuery] bool enableTotalRecordCount = true) [FromQuery] bool enableTotalRecordCount = true)
{ {
@ -118,9 +118,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -259,14 +259,14 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the studio.</returns> /// <returns>An <see cref="OkResult"/> containing the studio.</returns>
[HttpGet("{name}")] [HttpGet("{name}")]
[ProducesResponseType(StatusCodes.Status200OK)] [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 dtoOptions = new DtoOptions().AddClientFields(Request);
var item = _libraryManager.GetStudio(name); 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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -190,8 +190,8 @@ namespace Jellyfin.Api.Controllers
[FromRoute, Required] int index, [FromRoute, Required] int index,
[FromRoute, Required] string? format, [FromRoute, Required] string? format,
[FromQuery] long? endPositionTicks, [FromQuery] long? endPositionTicks,
[FromQuery] bool copyTimestamps, [FromQuery] bool copyTimestamps = false,
[FromQuery] bool addVttTimeMap, [FromQuery] bool addVttTimeMap = false,
[FromRoute] long startPositionTicks = 0) [FromRoute] long startPositionTicks = 0)
{ {
if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase))

View File

@ -44,9 +44,9 @@ namespace Jellyfin.Api.Controllers
/// <param name="userId">The user id.</param> /// <param name="userId">The user id.</param>
/// <param name="mediaType">The media types.</param> /// <param name="mediaType">The media types.</param>
/// <param name="type">The type.</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="startIndex">Optional. The start index.</param>
/// <param name="limit">Optional. The limit.</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> /// <response code="200">Suggestions returned.</response>
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the suggestions.</returns> /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the suggestions.</returns>
[HttpGet("/Users/{userId}/Suggestions")] [HttpGet("/Users/{userId}/Suggestions")]
@ -55,9 +55,9 @@ namespace Jellyfin.Api.Controllers
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromQuery] string? mediaType, [FromQuery] string? mediaType,
[FromQuery] string? type, [FromQuery] string? type,
[FromQuery] bool enableTotalRecordCount,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit) [FromQuery] int? limit,
[FromQuery] bool enableTotalRecordCount = false)
{ {
var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null; var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null;

View File

@ -132,7 +132,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("/Trailers")] [HttpGet("/Trailers")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetTrailers( public ActionResult<QueryResult<BaseItemDto>> GetTrailers(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? maxOfficialRating, [FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeSong,
[FromQuery] bool? hasThemeVideo, [FromQuery] bool? hasThemeVideo,

View File

@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("NextUp")] [HttpGet("NextUp")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetNextUp( public ActionResult<QueryResult<BaseItemDto>> GetNextUp(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
@ -93,12 +93,14 @@ namespace Jellyfin.Api.Controllers
ParentId = parentId, ParentId = parentId,
SeriesId = seriesId, SeriesId = seriesId,
StartIndex = startIndex, StartIndex = startIndex,
UserId = userId, UserId = userId ?? Guid.Empty,
EnableTotalRecordCount = enableTotalRecordCount EnableTotalRecordCount = enableTotalRecordCount
}, },
options); 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); var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user);
@ -125,7 +127,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("Upcoming")] [HttpGet("Upcoming")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetUpcomingEpisodes( public ActionResult<QueryResult<BaseItemDto>> GetUpcomingEpisodes(
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] int? startIndex, [FromQuery] int? startIndex,
[FromQuery] int? limit, [FromQuery] int? limit,
[FromQuery] string? fields, [FromQuery] string? fields,
@ -135,7 +137,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] bool? enableUserData) [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); var minPremiereDate = DateTime.Now.Date.ToUniversalTime().AddDays(-1);
@ -191,7 +195,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<QueryResult<BaseItemDto>> GetEpisodes( public ActionResult<QueryResult<BaseItemDto>> GetEpisodes(
[FromRoute] string? seriesId, [FromRoute] string? seriesId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] int? season, [FromQuery] int? season,
[FromQuery] string? seasonId, [FromQuery] string? seasonId,
@ -206,7 +210,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] string? sortBy) [FromQuery] string? sortBy)
{ {
var user = _userManager.GetUserById(userId); var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
: null;
List<BaseItem> episodes; List<BaseItem> episodes;
@ -312,7 +318,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<QueryResult<BaseItemDto>> GetSeasons( public ActionResult<QueryResult<BaseItemDto>> GetSeasons(
[FromRoute] string? seriesId, [FromRoute] string? seriesId,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] bool? isSpecialSeason, [FromQuery] bool? isSpecialSeason,
[FromQuery] bool? isMissing, [FromQuery] bool? isMissing,
@ -322,7 +328,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] string? enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] bool? enableUserData) [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)) if (!(_libraryManager.GetItemById(seriesId) is Series series))
{ {

View File

@ -180,7 +180,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns> /// <returns>An <see cref="OkResult"/> containing the <see cref="UserItemDataDto"/>.</returns>
[HttpPost("/Users/{userId}/Items/{itemId}/Rating")] [HttpPost("/Users/{userId}/Items/{itemId}/Rating")]
[ProducesResponseType(StatusCodes.Status200OK)] [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); return UpdateUserItemRatingInternal(userId, itemId, likes);
} }
@ -264,7 +264,7 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<IEnumerable<BaseItemDto>> GetLatestMedia( public ActionResult<IEnumerable<BaseItemDto>> GetLatestMedia(
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromQuery] Guid parentId, [FromQuery] Guid? parentId,
[FromQuery] string? fields, [FromQuery] string? fields,
[FromQuery] string? includeItemTypes, [FromQuery] string? includeItemTypes,
[FromQuery] bool? isPlayed, [FromQuery] bool? isPlayed,
@ -297,7 +297,7 @@ namespace Jellyfin.Api.Controllers
IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true),
IsPlayed = isPlayed, IsPlayed = isPlayed,
Limit = limit, Limit = limit,
ParentId = parentId, ParentId = parentId ?? Guid.Empty,
UserId = userId, UserId = userId,
}, dtoOptions); }, dtoOptions);

View File

@ -56,8 +56,8 @@ namespace Jellyfin.Api.Controllers
/// </summary> /// </summary>
/// <param name="userId">User id.</param> /// <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="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="presetViews">Preset views.</param>
/// <param name="includeHidden">Whether or not to include hidden content.</param>
/// <response code="200">User views returned.</response> /// <response code="200">User views returned.</response>
/// <returns>An <see cref="OkResult"/> containing the user views.</returns> /// <returns>An <see cref="OkResult"/> containing the user views.</returns>
[HttpGet("/Users/{userId}/Views")] [HttpGet("/Users/{userId}/Views")]
@ -65,8 +65,8 @@ namespace Jellyfin.Api.Controllers
public ActionResult<QueryResult<BaseItemDto>> GetUserViews( public ActionResult<QueryResult<BaseItemDto>> GetUserViews(
[FromRoute] Guid userId, [FromRoute] Guid userId,
[FromQuery] bool? includeExternalContent, [FromQuery] bool? includeExternalContent,
[FromQuery] bool includeHidden, [FromQuery] string? presetViews,
[FromQuery] string? presetViews) [FromQuery] bool includeHidden = false)
{ {
var query = new UserViewQuery var query = new UserViewQuery
{ {

View File

@ -53,9 +53,11 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{itemId}/AdditionalParts")] [HttpGet("{itemId}/AdditionalParts")]
[Authorize(Policy = Policies.DefaultAuthorization)] [Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)] [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) var item = itemId.Equals(Guid.Empty)
? (!userId.Equals(Guid.Empty) ? (!userId.Equals(Guid.Empty)

View File

@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? enableUserData, [FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit, [FromQuery] int? imageTypeLimit,
[FromQuery] string? enableImageTypes, [FromQuery] string? enableImageTypes,
[FromQuery] Guid userId, [FromQuery] Guid? userId,
[FromQuery] bool recursive = true, [FromQuery] bool recursive = true,
[FromQuery] bool? enableImages = true) [FromQuery] bool? enableImages = true)
{ {
@ -86,9 +86,9 @@ namespace Jellyfin.Api.Controllers
User? user = null; User? user = null;
BaseItem parentItem; 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); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId);
} }
else else
@ -176,7 +176,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{year}")] [HttpGet("{year}")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [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); var item = _libraryManager.GetYear(year);
if (item == null) if (item == null)
@ -187,9 +187,9 @@ namespace Jellyfin.Api.Controllers
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
.AddClientFields(Request); .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); return _dtoService.GetBaseItemDto(item, dtoOptions, user);
} }

View File

@ -4,7 +4,6 @@ using System.Linq;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
@ -21,14 +20,16 @@ namespace Jellyfin.Api.Helpers
IUserManager userManager, IUserManager userManager,
ILibraryManager libraryManager, ILibraryManager libraryManager,
IDtoService dtoService, IDtoService dtoService,
Guid userId, Guid? userId,
string id, string id,
string? excludeArtistIds, string? excludeArtistIds,
int? limit, int? limit,
Type[] includeTypes, Type[] includeTypes,
Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore) 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) ? var item = string.IsNullOrEmpty(id) ?
(!userId.Equals(Guid.Empty) ? libraryManager.GetUserRootFolder() : (!userId.Equals(Guid.Empty) ? libraryManager.GetUserRootFolder() :
@ -38,11 +39,10 @@ namespace Jellyfin.Api.Helpers
{ {
IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(), IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
Recursive = true, Recursive = true,
DtoOptions = dtoOptions DtoOptions = dtoOptions,
ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds)
}; };
query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds);
var inputItems = libraryManager.GetItemList(query); var inputItems = libraryManager.GetItemList(query);
var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore) var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)