Make query parameters nullable or set default value

pull/3524/head
crobibero 4 years ago
parent 2eef7d4913
commit 5d34b07d1f

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -55,32 +55,22 @@ namespace Jellyfin.Api.Controllers
/// </summary>
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
/// <param name="parentId">Specify this to localize the search to a specific item or folder. Omit to use the root.</param>
/// <param name="enableImages">(Unused) Optional. include image information in output.</param>
/// <param name="enableUserData">(Unused) Optional. include user data.</param>
/// <param name="imageTypeLimit">(Unused) Optional. the max number of images to return, per image type.</param>
/// <param name="enableImageTypes">(Unused) Optional. The image types to include in the output.</param>
/// <param name="fields">Optional. The fields to return.</param>
/// <param name="categoryLimit">The max number of categories to return.</param>
/// <param name="itemLimit">The max number of items to return per category.</param>
/// <response code="200">Movie recommendations returned.</response>
/// <returns>The list of movie recommendations.</returns>
[HttpGet("Recommendations")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImages", Justification = "Imported from ServiceStack")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableUserData", Justification = "Imported from ServiceStack")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageTypeLimit", Justification = "Imported from ServiceStack")]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "enableImageTypes", Justification = "Imported from ServiceStack")]
public ActionResult<IEnumerable<RecommendationDto>> GetMovieRecommendations(
[FromQuery] Guid userId,
[FromQuery] string parentId,
[FromQuery] bool? enableImages,
[FromQuery] bool? enableUserData,
[FromQuery] int? imageTypeLimit,
[FromQuery] string? enableImageTypes,
[FromQuery] Guid? userId,
[FromQuery] string? parentId,
[FromQuery] string? fields,
[FromQuery] int categoryLimit = 5,
[FromQuery] int itemLimit = 8)
{
var user = _userManager.GetUserById(userId);
var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
: null;
var dtoOptions = new DtoOptions()
.AddItemFields(fields)
.AddClientFields(Request);
@ -185,7 +175,7 @@ namespace Jellyfin.Api.Controllers
}
private IEnumerable<RecommendationDto> GetWithDirector(
User user,
User? user,
IEnumerable<string> names,
int itemLimit,
DtoOptions dtoOptions,
@ -230,7 +220,7 @@ namespace Jellyfin.Api.Controllers
}
}
private IEnumerable<RecommendationDto> GetWithActor(User user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
private IEnumerable<RecommendationDto> GetWithActor(User? user, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var itemTypes = new List<string> { nameof(Movie) };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)
@ -270,7 +260,7 @@ namespace Jellyfin.Api.Controllers
}
}
private IEnumerable<RecommendationDto> GetSimilarTo(User user, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
private IEnumerable<RecommendationDto> GetSimilarTo(User? user, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
{
var itemTypes = new List<string> { nameof(Movie) };
if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions)

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

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

@ -86,9 +86,9 @@ namespace Jellyfin.Api.Controllers
public ActionResult AddToPlaylist(
[FromRoute] string? playlistId,
[FromQuery] string? ids,
[FromQuery] Guid userId)
[FromQuery] Guid? userId)
{
_playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId);
_playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty);
return NoContent();
}

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

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

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

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

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

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

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

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

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

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

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

@ -53,9 +53,11 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{itemId}/AdditionalParts")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid userId)
public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute] Guid itemId, [FromQuery] Guid? userId)
{
var user = !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId) : null;
var user = userId.HasValue && !userId.Equals(Guid.Empty)
? _userManager.GetUserById(userId.Value)
: null;
var item = itemId.Equals(Guid.Empty)
? (!userId.Equals(Guid.Empty)

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

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

Loading…
Cancel
Save