diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index bb5cc746e9..0a4432beca 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -46,6 +46,7 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
+using TMDbLib.Objects.Authentication;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
using Genre = MediaBrowser.Controller.Entities.Genre;
@@ -1222,12 +1223,7 @@ namespace Emby.Server.Implementations.Library
return null;
}
- ///
- /// Gets the item by id.
- ///
- /// The id.
- /// BaseItem.
- /// is null.
+ ///
public BaseItem GetItemById(Guid id)
{
if (id.IsEmpty())
@@ -1263,6 +1259,22 @@ namespace Emby.Server.Implementations.Library
return null;
}
+ ///
+ public T GetItemById(Guid id, Guid userId)
+ where T : BaseItem
+ {
+ var user = userId.IsEmpty() ? null : _userManager.GetUserById(userId);
+ return GetItemById(id, user);
+ }
+
+ ///
+ public T GetItemById(Guid id, User user)
+ where T : BaseItem
+ {
+ var item = GetItemById(id);
+ return ItemIsVisible(item, user) ? item : null;
+ }
+
public List GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
if (query.Recursive && !query.ParentId.IsEmpty())
@@ -3191,5 +3203,20 @@ namespace Emby.Server.Implementations.Library
CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
}
+
+ private static bool ItemIsVisible(BaseItem item, User user)
+ {
+ if (item is null)
+ {
+ return false;
+ }
+
+ if (user is null)
+ {
+ return true;
+ }
+
+ return item is UserRootFolder || item.IsVisibleStandalone(user);
+ }
}
}
diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index 1cad663264..6d94d96f3a 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -194,7 +194,7 @@ public class DisplayPreferencesController : BaseJellyfinApiController
foreach (var key in displayPreferences.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.OrdinalIgnoreCase)))
{
- if (!Enum.TryParse(displayPreferences.CustomPrefs[key], true, out var type))
+ if (!Enum.TryParse(displayPreferences.CustomPrefs[key], true, out _))
{
_logger.LogError("Invalid ViewType: {LandingScreenOption}", displayPreferences.CustomPrefs[key]);
displayPreferences.CustomPrefs.Remove(key);
diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs
index d6e043e6a1..4abca32713 100644
--- a/Jellyfin.Api/Controllers/FilterController.cs
+++ b/Jellyfin.Api/Controllers/FilterController.cs
@@ -162,7 +162,7 @@ public class FilterController : BaseJellyfinApiController
}
else if (parentId.HasValue)
{
- parentItem = _libraryManager.GetItemById(parentId.Value);
+ parentItem = _libraryManager.GetItemById(parentId.Value);
}
var filters = new QueryFilters();
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index 6b38fa7d34..8e8accab3c 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -90,6 +90,7 @@ public class ImageController : BaseJellyfinApiController
/// User Id.
/// Image updated.
/// User does not have permission to delete the image.
+ /// Item not found.
/// A .
[HttpPost("UserImage")]
[Authorize]
@@ -97,6 +98,7 @@ public class ImageController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task PostUserImage(
[FromQuery] Guid? userId)
{
@@ -289,7 +291,7 @@ public class ImageController : BaseJellyfinApiController
[FromRoute, Required] ImageType imageType,
[FromQuery] int? imageIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -317,7 +319,7 @@ public class ImageController : BaseJellyfinApiController
[FromRoute, Required] ImageType imageType,
[FromRoute] int imageIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -346,7 +348,7 @@ public class ImageController : BaseJellyfinApiController
[FromRoute, Required] Guid itemId,
[FromRoute, Required] ImageType imageType)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -390,7 +392,7 @@ public class ImageController : BaseJellyfinApiController
[FromRoute, Required] ImageType imageType,
[FromRoute] int imageIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -433,7 +435,7 @@ public class ImageController : BaseJellyfinApiController
[FromRoute, Required] int imageIndex,
[FromQuery, Required] int newIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -456,7 +458,7 @@ public class ImageController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task>> GetItemImageInfos([FromRoute, Required] Guid itemId)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -559,7 +561,7 @@ public class ImageController : BaseJellyfinApiController
[FromQuery] string? foregroundLayer,
[FromQuery] int? imageIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -637,7 +639,7 @@ public class ImageController : BaseJellyfinApiController
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -715,7 +717,7 @@ public class ImageController : BaseJellyfinApiController
[FromQuery] string? foregroundLayer,
[FromRoute, Required] int imageIndex)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs
index 3cf4852995..dcbacf1d78 100644
--- a/Jellyfin.Api/Controllers/InstantMixController.cs
+++ b/Jellyfin.Api/Controllers/InstantMixController.cs
@@ -62,9 +62,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Songs/{itemId}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromSong(
[FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
@@ -75,11 +77,16 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var item = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -99,9 +106,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Albums/{itemId}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromAlbum(
[FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
@@ -112,15 +121,20 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var album = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- var items = _musicManager.GetInstantMixFromItem(album, user, dtoOptions);
+ var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
}
@@ -136,9 +150,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Playlists/{itemId}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromPlaylist(
[FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
@@ -149,15 +165,20 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var playlist = (Playlist)_libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
- var items = _musicManager.GetInstantMixFromItem(playlist, user, dtoOptions);
+ var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
}
@@ -209,9 +230,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Artists/{itemId}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromArtists(
[FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
@@ -222,11 +245,16 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var item = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -246,9 +274,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Items/{itemId}/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromItem(
[FromRoute, Required] Guid itemId,
[FromQuery] Guid? userId,
@@ -259,11 +289,16 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var item = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -283,9 +318,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("Artists/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Use GetInstantMixFromArtists")]
public ActionResult> GetInstantMixFromArtists2(
[FromQuery, Required] Guid id,
@@ -320,9 +357,11 @@ public class InstantMixController : BaseJellyfinApiController
/// Optional. The max number of images to return, per image type.
/// Optional. The image types to include in the output.
/// Instant playlist returned.
+ /// Item not found.
/// A with the playlist items.
[HttpGet("MusicGenres/InstantMix")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetInstantMixFromMusicGenreById(
[FromQuery, Required] Guid id,
[FromQuery] Guid? userId,
@@ -333,11 +372,16 @@ public class InstantMixController : BaseJellyfinApiController
[FromQuery] int? imageTypeLimit,
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
{
- var item = _libraryManager.GetItemById(id);
userId = RequestHelpers.GetUserId(User, userId);
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(id, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs
index e3aee1bf7a..d009f80a96 100644
--- a/Jellyfin.Api/Controllers/ItemLookupController.cs
+++ b/Jellyfin.Api/Controllers/ItemLookupController.cs
@@ -4,6 +4,8 @@ using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
+using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Api;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -64,7 +66,7 @@ public class ItemLookupController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetExternalIdInfos([FromRoute, Required] Guid itemId)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -234,6 +236,7 @@ public class ItemLookupController : BaseJellyfinApiController
/// The remote search result.
/// Optional. Whether or not to replace all images. Default: True.
/// Item metadata refreshed.
+ /// Item not found.
///
/// A that represents the asynchronous operation to get the remote search results.
/// The task result contains an .
@@ -241,12 +244,18 @@ public class ItemLookupController : BaseJellyfinApiController
[HttpPost("Items/RemoteSearch/Apply/{itemId}")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task ApplySearchCriteria(
[FromRoute, Required] Guid itemId,
[FromBody, Required] RemoteSearchResult searchResult,
[FromQuery] bool replaceAllImages = true)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
+ if (item is null)
+ {
+ return NotFound();
+ }
+
_logger.LogInformation(
"Setting provider id's to item {ItemId}-{ItemName}: {@ProviderIds}",
item.Id,
diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs
index 0a8522e1cf..c1343b1309 100644
--- a/Jellyfin.Api/Controllers/ItemRefreshController.cs
+++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs
@@ -2,7 +2,10 @@ using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Jellyfin.Api.Constants;
+using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Api;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
@@ -61,7 +64,7 @@ public class ItemRefreshController : BaseJellyfinApiController
[FromQuery] bool replaceAllMetadata = false,
[FromQuery] bool replaceAllImages = false)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs
index 9800248c68..83f308bb19 100644
--- a/Jellyfin.Api/Controllers/ItemUpdateController.cs
+++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs
@@ -5,6 +5,8 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
+using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Api;
using MediaBrowser.Controller.Configuration;
@@ -72,7 +74,7 @@ public class ItemUpdateController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task UpdateItem([FromRoute, Required] Guid itemId, [FromBody, Required] BaseItemDto request)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -145,7 +147,11 @@ public class ItemUpdateController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult GetMetadataEditorInfo([FromRoute, Required] Guid itemId)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
+ if (item is null)
+ {
+ return NotFound();
+ }
var info = new MetadataEditorInfo
{
@@ -197,7 +203,7 @@ public class ItemUpdateController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery] string? contentType)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index 26ae1a820f..6ffe6e7da1 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -967,9 +967,13 @@ public class ItemsController : BaseJellyfinApiController
}
var user = _userManager.GetUserById(requestUserId) ?? throw new ResourceNotFoundException();
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
- return (item == null) ? NotFound() : _userDataRepository.GetUserDataDto(item, user);
+ return _userDataRepository.GetUserDataDto(item, user);
}
///
@@ -1014,8 +1018,8 @@ public class ItemsController : BaseJellyfinApiController
}
var user = _userManager.GetUserById(requestUserId) ?? throw new ResourceNotFoundException();
- var item = _libraryManager.GetItemById(itemId);
- if (item == null)
+ var item = _libraryManager.GetItemById(itemId, user);
+ if (item is null)
{
return NotFound();
}
diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs
index 360389d292..3b4e80ff3c 100644
--- a/Jellyfin.Api/Controllers/LibraryController.cs
+++ b/Jellyfin.Api/Controllers/LibraryController.cs
@@ -102,7 +102,7 @@ public class LibraryController : BaseJellyfinApiController
[ProducesFile("video/*", "audio/*")]
public ActionResult GetFile([FromRoute, Required] Guid itemId)
{
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, User.GetUserId());
if (item is null)
{
return NotFound();
@@ -152,11 +152,10 @@ public class LibraryController : BaseJellyfinApiController
? (userId.IsNullOrEmpty()
? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder())
- : _libraryManager.GetItemById(itemId);
-
+ : _libraryManager.GetItemById(itemId, user);
if (item is null)
{
- return NotFound("Item not found.");
+ return NotFound();
}
IEnumerable themeItems;
@@ -214,16 +213,14 @@ public class LibraryController : BaseJellyfinApiController
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
-
var item = itemId.IsEmpty()
? (userId.IsNullOrEmpty()
? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder())
- : _libraryManager.GetItemById(itemId);
-
+ : _libraryManager.GetItemById(itemId, user);
if (item is null)
{
- return NotFound("Item not found.");
+ return NotFound();
}
IEnumerable themeItems;
@@ -286,7 +283,8 @@ public class LibraryController : BaseJellyfinApiController
userId,
inheritFromParent);
- if (themeSongs.Result is NotFoundObjectResult || themeVideos.Result is NotFoundObjectResult)
+ if (themeSongs.Result is StatusCodeResult { StatusCode: StatusCodes.Status404NotFound }
+ || themeVideos.Result is StatusCodeResult { StatusCode: StatusCodes.Status404NotFound })
{
return NotFound();
}
@@ -327,6 +325,7 @@ public class LibraryController : BaseJellyfinApiController
/// The item id.
/// Item deleted.
/// Unauthorized access.
+ /// Item not found.
/// A .
[HttpDelete("Items/{itemId}")]
[Authorize]
@@ -335,17 +334,18 @@ public class LibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult DeleteItem(Guid itemId)
{
- var isApiKey = User.GetIsApiKey();
var userId = User.GetUserId();
- var user = !isApiKey && !userId.IsEmpty()
- ? _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException()
- : null;
- if (!isApiKey && user is null)
+ var isApiKey = User.GetIsApiKey();
+ var user = userId.IsEmpty() && isApiKey
+ ? null
+ : _userManager.GetUserById(userId);
+
+ if (user is null && !isApiKey)
{
- return Unauthorized("Unauthorized access");
+ return NotFound();
}
- var item = _libraryManager.GetItemById(itemId);
+ var item = _libraryManager.GetItemById(itemId, user);
if (item is null)
{
return NotFound();
@@ -391,7 +391,7 @@ public class LibraryController : BaseJellyfinApiController
foreach (var i in ids)
{
- var item = _libraryManager.GetItemById(i);
+ var item = _libraryManager.GetItemById(i, user);
if (item is null)
{
return NotFound();
@@ -459,20 +459,18 @@ public class LibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult> GetAncestors([FromRoute, Required] Guid itemId, [FromQuery] Guid? userId)
{
- var item = _libraryManager.GetItemById(itemId);
userId = RequestHelpers.GetUserId(User, userId);
-
+ var user = userId.IsNullOrEmpty()
+ ? null
+ : _userManager.GetUserById(userId.Value);
+ var item = _libraryManager.GetItemById(itemId, user);
if (item is null)
{
- return NotFound("Item not found");
+ return NotFound();
}
var baseItemDtos = new List();
- var user = userId.IsNullOrEmpty()
- ? null
- : _userManager.GetUserById(userId.Value);
-
var dtoOptions = new DtoOptions().AddClientFields(User);
BaseItem? parent = item.GetParent();
@@ -644,14 +642,16 @@ public class LibraryController : BaseJellyfinApiController
[ProducesFile("video/*", "audio/*")]
public async Task GetDownload([FromRoute, Required] Guid itemId)
{
- var item = _libraryManager.GetItemById(itemId);
+ var userId = User.GetUserId();
+ var user = userId.IsEmpty()
+ ? null
+ : _userManager.GetUserById(userId);
+ var item = _libraryManager.GetItemById(itemId, user);
if (item is null)
{
return NotFound();
}
- var user = _userManager.GetUserById(User.GetUserId());
-
if (user is not null)
{
if (!item.CanDownload(user))
@@ -704,12 +704,14 @@ public class LibraryController : BaseJellyfinApiController
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields)
{
userId = RequestHelpers.GetUserId(User, userId);
+ var user = userId.IsNullOrEmpty()
+ ? null
+ : _userManager.GetUserById(userId.Value);
var item = itemId.IsEmpty()
- ? (userId.IsNullOrEmpty()
+ ? (user is null
? _libraryManager.RootFolder
: _libraryManager.GetUserRootFolder())
- : _libraryManager.GetItemById(itemId);
-
+ : _libraryManager.GetItemById(itemId, user);
if (item is null)
{
return NotFound();
@@ -720,9 +722,6 @@ public class LibraryController : BaseJellyfinApiController
return new QueryResult();
}
- var user = userId.IsNullOrEmpty()
- ? null
- : _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User);
diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs
index 23c430f859..c1d01a5c2f 100644
--- a/Jellyfin.Api/Controllers/LibraryStructureController.cs
+++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs
@@ -6,6 +6,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.LibraryStructureDto;
using MediaBrowser.Common.Api;
@@ -311,15 +313,21 @@ public class LibraryStructureController : BaseJellyfinApiController
///
/// The library name and options.
/// Library updated.
+ /// Item not found.
/// A .
[HttpPost("LibraryOptions")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult UpdateLibraryOptions(
[FromBody] UpdateLibraryOptionsDto request)
{
- var collectionFolder = (CollectionFolder)_libraryManager.GetItemById(request.Id);
+ var item = _libraryManager.GetItemById(request.Id, User.GetUserId());
+ if (item is null)
+ {
+ return NotFound();
+ }
- collectionFolder.UpdateLibraryOptions(request.LibraryOptions);
+ item.UpdateLibraryOptions(request.LibraryOptions);
return NoContent();
}
}
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index 7768b3c45f..2b26c01f88 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -220,9 +220,11 @@ public class LiveTvController : BaseJellyfinApiController
/// Channel id.
/// Optional. Attach user data.
/// Live tv channel returned.
+ /// Item not found.
/// An containing the live tv channel.
[HttpGet("Channels/{channelId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.LiveTvAccess)]
public ActionResult GetChannel([FromRoute, Required] Guid channelId, [FromQuery] Guid? userId)
{
@@ -232,7 +234,12 @@ public class LiveTvController : BaseJellyfinApiController
: _userManager.GetUserById(userId.Value);
var item = channelId.IsEmpty()
? _libraryManager.GetUserRootFolder()
- : _libraryManager.GetItemById(channelId);
+ : _libraryManager.GetItemById(channelId, user);
+
+ if (item is null)
+ {
+ return NotFound();
+ }
var dtoOptions = new DtoOptions()
.AddClientFields(User);
@@ -416,9 +423,11 @@ public class LiveTvController : BaseJellyfinApiController
/// Recording id.
/// Optional. Attach user data.
/// Recording returned.
+ /// Item not found.
/// An containing the live tv recording.
[HttpGet("Recordings/{recordingId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.LiveTvAccess)]
public ActionResult GetRecording([FromRoute, Required] Guid recordingId, [FromQuery] Guid? userId)
{
@@ -426,7 +435,13 @@ public class LiveTvController : BaseJellyfinApiController
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
- var item = recordingId.IsEmpty() ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(recordingId);
+ var item = recordingId.IsEmpty()
+ ? _libraryManager.GetUserRootFolder()
+ : _libraryManager.GetItemById(recordingId, user);
+ if (item is null)
+ {
+ return NotFound();
+ }
var dtoOptions = new DtoOptions()
.AddClientFields(User);
@@ -611,7 +626,8 @@ public class LiveTvController : BaseJellyfinApiController
{
query.IsSeries = true;
- if (_libraryManager.GetItemById(librarySeriesId.Value) is Series series)
+ var series = _libraryManager.GetItemById(librarySeriesId.Value);
+ if (series is not null)
{
query.Name = series.Name;
}
@@ -665,7 +681,8 @@ public class LiveTvController : BaseJellyfinApiController
{
query.IsSeries = true;
- if (_libraryManager.GetItemById(body.LibrarySeriesId) is Series series)
+ var series = _libraryManager.GetItemById(body.LibrarySeriesId);
+ if (series is not null)
{
query.Name = series.Name;
}
@@ -779,7 +796,7 @@ public class LiveTvController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult DeleteRecording([FromRoute, Required] Guid recordingId)
{
- var item = _libraryManager.GetItemById(recordingId);
+ var item = _libraryManager.GetItemById(recordingId, User.GetUserId());
if (item is null)
{
return NotFound();
diff --git a/Jellyfin.Api/Controllers/LyricsController.cs b/Jellyfin.Api/Controllers/LyricsController.cs
index f2b312b478..8eb4cadf88 100644
--- a/Jellyfin.Api/Controllers/LyricsController.cs
+++ b/Jellyfin.Api/Controllers/LyricsController.cs
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
using Jellyfin.Extensions;
using MediaBrowser.Common.Api;
using MediaBrowser.Controller.Entities.Audio;
@@ -66,37 +67,16 @@ public class LyricsController : BaseJellyfinApiController
[HttpGet("Audio/{itemId}/Lyrics")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task> GetLyrics([FromRoute, Required] Guid itemId)
{
- var isApiKey = User.GetIsApiKey();
- var userId = User.GetUserId();
- if (!isApiKey && userId.IsEmpty())
- {
- return BadRequest();
- }
-
- var audio = _libraryManager.GetItemById