Merge pull request #17460 from Shadowghost/fix-user-items
Queue person metadata refresh instead of blocking the item request and fix ItemCounts
This commit is contained in:
@@ -40,6 +40,7 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
private readonly IUserViewManager _userViewManager;
|
private readonly IUserViewManager _userViewManager;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly IProviderManager _providerManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UserLibraryController"/> class.
|
/// 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="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
||||||
/// <param name="userViewManager">Instance of the <see cref="IUserViewManager"/> 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="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||||
|
/// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
|
||||||
public UserLibraryController(
|
public UserLibraryController(
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IUserDataManager userDataRepository,
|
IUserDataManager userDataRepository,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IDtoService dtoService,
|
IDtoService dtoService,
|
||||||
IUserViewManager userViewManager,
|
IUserViewManager userViewManager,
|
||||||
IFileSystem fileSystem)
|
IFileSystem fileSystem,
|
||||||
|
IProviderManager providerManager)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_userDataRepository = userDataRepository;
|
_userDataRepository = userDataRepository;
|
||||||
@@ -64,6 +67,7 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
_userViewManager = userViewManager;
|
_userViewManager = userViewManager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_providerManager = providerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -75,7 +79,7 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
/// <returns>An <see cref="OkResult"/> containing the item.</returns>
|
/// <returns>An <see cref="OkResult"/> containing the item.</returns>
|
||||||
[HttpGet("Items/{itemId}")]
|
[HttpGet("Items/{itemId}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public async Task<ActionResult<BaseItemDto>> GetItem(
|
public ActionResult<BaseItemDto> GetItem(
|
||||||
[FromQuery] Guid? userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromRoute, Required] Guid itemId)
|
[FromRoute, Required] Guid itemId)
|
||||||
{
|
{
|
||||||
@@ -94,7 +98,7 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
|
QueueRefreshOnDemandIfNeeded(item);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = new DtoOptions();
|
||||||
|
|
||||||
@@ -112,7 +116,7 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[Obsolete("Kept for backwards compatibility")]
|
[Obsolete("Kept for backwards compatibility")]
|
||||||
[ApiExplorerSettings(IgnoreApi = true)]
|
[ApiExplorerSettings(IgnoreApi = true)]
|
||||||
public Task<ActionResult<BaseItemDto>> GetItemLegacy(
|
public ActionResult<BaseItemDto> GetItemLegacy(
|
||||||
[FromRoute, Required] Guid userId,
|
[FromRoute, Required] Guid userId,
|
||||||
[FromRoute, Required] Guid itemId)
|
[FromRoute, Required] Guid itemId)
|
||||||
=> GetItem(userId, itemId);
|
=> GetItem(userId, itemId);
|
||||||
@@ -639,25 +643,28 @@ public class UserLibraryController : BaseJellyfinApiController
|
|||||||
limit,
|
limit,
|
||||||
groupItems);
|
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);
|
return;
|
||||||
var performFullRefresh = !hasMetadata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 3;
|
|
||||||
|
|
||||||
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>
|
/// <summary>
|
||||||
|
|||||||
@@ -141,32 +141,32 @@ public class ItemCountService : IItemCountService
|
|||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case BaseItemKind.Person:
|
case BaseItemKind.Person:
|
||||||
baseQuery = context.PeopleBaseItemMap
|
baseQuery = ItemsById(context, context.PeopleBaseItemMap
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(m => m.People.Name == item.Name)
|
.Where(m => m.People.Name == item.Name)
|
||||||
.Select(m => m.Item);
|
.Select(m => m.ItemId));
|
||||||
break;
|
break;
|
||||||
case BaseItemKind.MusicArtist:
|
case BaseItemKind.MusicArtist:
|
||||||
baseQuery = context.ItemValuesMap
|
baseQuery = ItemsById(context, context.ItemValuesMap
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
||||||
&& (ivm.ItemValue.Type == ItemValueType.Artist || ivm.ItemValue.Type == ItemValueType.AlbumArtist))
|
&& (ivm.ItemValue.Type == ItemValueType.Artist || ivm.ItemValue.Type == ItemValueType.AlbumArtist))
|
||||||
.Select(ivm => ivm.Item);
|
.Select(ivm => ivm.ItemId));
|
||||||
break;
|
break;
|
||||||
case BaseItemKind.Genre:
|
case BaseItemKind.Genre:
|
||||||
case BaseItemKind.MusicGenre:
|
case BaseItemKind.MusicGenre:
|
||||||
baseQuery = context.ItemValuesMap
|
baseQuery = ItemsById(context, context.ItemValuesMap
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
||||||
&& ivm.ItemValue.Type == ItemValueType.Genre)
|
&& ivm.ItemValue.Type == ItemValueType.Genre)
|
||||||
.Select(ivm => ivm.Item);
|
.Select(ivm => ivm.ItemId));
|
||||||
break;
|
break;
|
||||||
case BaseItemKind.Studio:
|
case BaseItemKind.Studio:
|
||||||
baseQuery = context.ItemValuesMap
|
baseQuery = ItemsById(context, context.ItemValuesMap
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
.Where(ivm => ivm.ItemValue.CleanValue == item.CleanName
|
||||||
&& ivm.ItemValue.Type == ItemValueType.Studios)
|
&& ivm.ItemValue.Type == ItemValueType.Studios)
|
||||||
.Select(ivm => ivm.Item);
|
.Select(ivm => ivm.ItemId));
|
||||||
break;
|
break;
|
||||||
case BaseItemKind.Year:
|
case BaseItemKind.Year:
|
||||||
if (int.TryParse(item.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
|
if (int.TryParse(item.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
|
||||||
@@ -254,6 +254,9 @@ public class ItemCountService : IItemCountService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IQueryable<BaseItemEntity> ItemsById(JellyfinDbContext context, IQueryable<Guid> itemIds)
|
||||||
|
=> context.BaseItems.AsNoTracking().Where(e => itemIds.Contains(e.Id));
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int GetPlayedCount(InternalItemsQuery filter, Guid ancestorId)
|
public int GetPlayedCount(InternalItemsQuery filter, Guid ancestorId)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user