aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody Robibero <cody@robibe.ro>2026-08-01 08:06:46 -0400
committerGitHub <noreply@github.com>2026-08-01 08:06:46 -0400
commit341c19bacebfeb4e957adfa75094c6a8febfc155 (patch)
treeb83b9686c4e03486aa40b3374b03fb3362c42b84
parente3a8d209b4c1520435e9f0b3a982525a71f742a3 (diff)
parent046225654af0105a3f8cf1678b1b1e8e00fd215a (diff)
Merge pull request #17460 from Shadowghost/fix-user-items
Queue person metadata refresh instead of blocking the item request and fix ItemCounts
-rw-r--r--Jellyfin.Api/Controllers/UserLibraryController.cs45
-rw-r--r--Jellyfin.Server.Implementations/Item/ItemCountService.cs19
2 files changed, 37 insertions, 27 deletions
diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs
index a718035528..ea134a4619 100644
--- a/Jellyfin.Api/Controllers/UserLibraryController.cs
+++ b/Jellyfin.Api/Controllers/UserLibraryController.cs
@@ -40,6 +40,7 @@ public class UserLibraryController : BaseJellyfinApiController
private readonly IDtoService _dtoService;
private readonly IUserViewManager _userViewManager;
private readonly IFileSystem _fileSystem;
+ private readonly IProviderManager _providerManager;
/// <summary>
/// Initializes a new instance of the <see cref="UserLibraryController"/> class.
@@ -50,13 +51,15 @@ public class UserLibraryController : BaseJellyfinApiController
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
/// <param name="userViewManager">Instance of the <see cref="IUserViewManager"/> interface.</param>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
+ /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
public UserLibraryController(
IUserManager userManager,
IUserDataManager userDataRepository,
ILibraryManager libraryManager,
IDtoService dtoService,
IUserViewManager userViewManager,
- IFileSystem fileSystem)
+ IFileSystem fileSystem,
+ IProviderManager providerManager)
{
_userManager = userManager;
_userDataRepository = userDataRepository;
@@ -64,6 +67,7 @@ public class UserLibraryController : BaseJellyfinApiController
_dtoService = dtoService;
_userViewManager = userViewManager;
_fileSystem = fileSystem;
+ _providerManager = providerManager;
}
/// <summary>
@@ -75,7 +79,7 @@ public class UserLibraryController : BaseJellyfinApiController
/// <returns>An <see cref="OkResult"/> containing the item.</returns>
[HttpGet("Items/{itemId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public async Task<ActionResult<BaseItemDto>> GetItem(
+ public ActionResult<BaseItemDto> GetItem(
[FromQuery] Guid? userId,
[FromRoute, Required] Guid itemId)
{
@@ -94,7 +98,7 @@ public class UserLibraryController : BaseJellyfinApiController
return NotFound();
}
- await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
+ QueueRefreshOnDemandIfNeeded(item);
var dtoOptions = new DtoOptions();
@@ -112,7 +116,7 @@ public class UserLibraryController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
[Obsolete("Kept for backwards compatibility")]
[ApiExplorerSettings(IgnoreApi = true)]
- public Task<ActionResult<BaseItemDto>> GetItemLegacy(
+ public ActionResult<BaseItemDto> GetItemLegacy(
[FromRoute, Required] Guid userId,
[FromRoute, Required] Guid itemId)
=> GetItem(userId, itemId);
@@ -639,25 +643,28 @@ public class UserLibraryController : BaseJellyfinApiController
limit,
groupItems);
- private async Task RefreshItemOnDemandIfNeeded(BaseItem item)
+ private void QueueRefreshOnDemandIfNeeded(BaseItem item)
{
- if (item is Person)
+ if (item is not Person)
{
- var hasMetadata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary);
- var performFullRefresh = !hasMetadata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3;
+ return;
+ }
- if (performFullRefresh)
- {
- var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
- {
- MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
- ImageRefreshMode = MetadataRefreshMode.FullRefresh,
- ForceSave = true
- };
-
- await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
- }
+ var hasMetadata = !string.IsNullOrWhiteSpace(item.Overview) && item.HasImage(ImageType.Primary);
+ if (hasMetadata || (DateTime.UtcNow - item.DateLastRefreshed).TotalDays < 3)
+ {
+ return;
}
+
+ _providerManager.QueueRefresh(
+ item.Id,
+ new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+ {
+ MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
+ ImageRefreshMode = MetadataRefreshMode.FullRefresh,
+ ForceSave = true
+ },
+ RefreshPriority.High);
}
/// <summary>
diff --git a/Jellyfin.Server.Implementations/Item/ItemCountService.cs b/Jellyfin.Server.Implementations/Item/ItemCountService.cs
index 604db9f839..4aa65769fd 100644
--- a/Jellyfin.Server.Implementations/Item/ItemCountService.cs
+++ b/Jellyfin.Server.Implementations/Item/ItemCountService.cs
@@ -141,32 +141,32 @@ public class ItemCountService : IItemCountService
switch (kind)
{
case BaseItemKind.Person:
- baseQuery = context.PeopleBaseItemMap
+ baseQuery = ItemsById(context, context.PeopleBaseItemMap
.AsNoTracking()
.Where(m => m.People.Name == item.Name)
- .Select(m => m.Item);
+ .Select(m => m.ItemId));
break;
case BaseItemKind.MusicArtist:
- baseQuery = context.ItemValuesMap
+ baseQuery = ItemsById(context, context.ItemValuesMap
.AsNoTracking()
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
&& (ivm.ItemValue.Type == ItemValueType.Artist || ivm.ItemValue.Type == ItemValueType.AlbumArtist))
- .Select(ivm => ivm.Item);
+ .Select(ivm => ivm.ItemId));
break;
case BaseItemKind.Genre:
case BaseItemKind.MusicGenre:
- baseQuery = context.ItemValuesMap
+ baseQuery = ItemsById(context, context.ItemValuesMap
.AsNoTracking()
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
&& ivm.ItemValue.Type == ItemValueType.Genre)
- .Select(ivm => ivm.Item);
+ .Select(ivm => ivm.ItemId));
break;
case BaseItemKind.Studio:
- baseQuery = context.ItemValuesMap
+ baseQuery = ItemsById(context, context.ItemValuesMap
.AsNoTracking()
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
&& ivm.ItemValue.Type == ItemValueType.Studios)
- .Select(ivm => ivm.Item);
+ .Select(ivm => ivm.ItemId));
break;
case BaseItemKind.Year:
if (int.TryParse(item.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
@@ -254,6 +254,9 @@ public class ItemCountService : IItemCountService
return result;
}
+ private static IQueryable<BaseItemEntity> ItemsById(JellyfinDbContext context, IQueryable<Guid> itemIds)
+ => context.BaseItems.AsNoTracking().Where(e => itemIds.Contains(e.Id));
+
/// <inheritdoc/>
public int GetPlayedCount(InternalItemsQuery filter, Guid ancestorId)
{