aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library/LibraryManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Library/LibraryManager.cs')
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs97
1 files changed, 79 insertions, 18 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index de44e2ada5..2bba659a23 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -412,6 +412,13 @@ namespace Emby.Server.Implementations.Library
}
_persistenceService.DeleteItem([.. pathMaps.Select(f => f.Item.Id)]);
+
+ // Evict the deleted items from the cache and announce each removal.
+ foreach (var (item, _, _) in pathMaps)
+ {
+ _cache.TryRemove(item.Id, out _);
+ ReportItemRemoved(item, item.GetOwner() ?? item.GetParent());
+ }
}
public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem)
@@ -611,6 +618,12 @@ namespace Emby.Server.Implementations.Library
folder.UserData = null;
}
+ // Announce the descendants before the item itself.
+ foreach (var child in children)
+ {
+ ReportItemRemoved(child, item);
+ }
+
ReportItemRemoved(item, parent);
}
@@ -1901,14 +1914,14 @@ namespace Emby.Server.Implementations.Library
}
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
- query.AncestorIds = [];
-
- // Prevent searching in all libraries due to empty filter
- if (query.TopParentIds.Length == 0)
+ var topParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
+ if (topParentIds.Length == 0)
{
- query.TopParentIds = [Guid.NewGuid()];
+ return;
}
+
+ query.TopParentIds = topParentIds;
+ query.AncestorIds = [];
}
public QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
@@ -1954,12 +1967,15 @@ namespace Emby.Server.Implementations.Library
if (parents.All(i => i is ICollectionFolder || i is UserView))
{
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
+ var topParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
- // Prevent searching in all libraries due to empty filter
- if (query.TopParentIds.Length == 0)
+ if (topParentIds.Length > 0)
{
- query.TopParentIds = [Guid.NewGuid()];
+ query.TopParentIds = topParentIds;
+ }
+ else
+ {
+ SetAncestorIds(query, parents);
}
}
else if (parents.Count == 1 && parents.First() is Folder folder
@@ -1983,19 +1999,24 @@ namespace Emby.Server.Implementations.Library
}
else
{
- // We need to be able to query from any arbitrary ancestor up the tree
- query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).ToArray();
-
- // Prevent searching in all libraries due to empty filter
- if (query.AncestorIds.Length == 0)
- {
- query.AncestorIds = [Guid.NewGuid()];
- }
+ SetAncestorIds(query, parents);
}
query.Parent = null;
}
+ private static void SetAncestorIds(InternalItemsQuery query, IReadOnlyCollection<BaseItem> parents)
+ {
+ // We need to be able to query from any arbitrary ancestor up the tree
+ query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).ToArray();
+
+ // Prevent searching in all libraries due to empty filter
+ if (query.AncestorIds.Length == 0)
+ {
+ query.AncestorIds = [Guid.NewGuid()];
+ }
+ }
+
private void AddUserToQuery(InternalItemsQuery query, User user, bool allowExternalContent = true)
{
if (query.User is null)
@@ -2235,6 +2256,12 @@ namespace Emby.Server.Implementations.Library
}
/// <inheritdoc />
+ public IReadOnlySet<Guid> GetItemIdsWithAlternateVersions(IReadOnlyList<Guid> itemIds)
+ {
+ return _linkedChildrenService.GetItemIdsWithAlternateVersions(itemIds);
+ }
+
+ /// <inheritdoc />
public void UpsertLinkedChild(Guid parentId, Guid childId, MediaBrowser.Controller.Entities.LinkedChildType childType)
{
_linkedChildrenService.UpsertLinkedChild(parentId, childId, childType);
@@ -2376,6 +2403,7 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ altVideo.IsInMixedFolder = video.IsInMixedFolder;
// ResolveAlternateVersion only sees the alternate's primary file.
// If the alternate is itself a stack (e.g. 1080p part1 + part2),
// detect its parts from sibling files so its AdditionalParts persist.
@@ -2561,6 +2589,8 @@ namespace Emby.Server.Implementations.Library
item.DateLastSaved = DateTime.UtcNow;
}
+ ForgetDroppedLocalAlternateVersions(items);
+
// Resolve and add any local alternate version items that don't exist yet
// This ensures they exist in the database when LinkedChildren are processed
var allItems = new List<BaseItem>(items);
@@ -2589,6 +2619,7 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ altVideo.IsInMixedFolder = video.IsInMixedFolder;
// ResolveAlternateVersion only sees the alternate's primary file.
// If the alternate is itself a stack (e.g. 1080p part1 + part2),
// detect its parts from sibling files so its AdditionalParts persist.
@@ -2649,6 +2680,30 @@ namespace Emby.Server.Implementations.Library
public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
=> UpdateItemsAsync([item], parent, updateReason, cancellationToken);
+ /// <summary>
+ /// Forgets the cached local alternate versions of the supplied items that they no longer list.
+ /// </summary>
+ /// <param name="items">The items about to be saved.</param>
+ private void ForgetDroppedLocalAlternateVersions(IReadOnlyList<BaseItem> items)
+ {
+ foreach (var video in items.OfType<Video>())
+ {
+ var videoType = video.GetType();
+ var keptIds = video.LocalAlternateVersions
+ .Where(path => !string.IsNullOrEmpty(path))
+ .Select(path => GetNewItemId(path, videoType))
+ .ToHashSet();
+
+ foreach (var versionId in GetLocalAlternateVersionIds(video))
+ {
+ if (!keptIds.Contains(versionId))
+ {
+ _cache.TryRemove(versionId, out _);
+ }
+ }
+ }
+ }
+
/// <inheritdoc />
public async Task ReattachUserDataAsync(BaseItem item, CancellationToken cancellationToken)
{
@@ -3509,6 +3564,12 @@ namespace Emby.Server.Implementations.Library
return _peopleRepository.GetPeopleNamesByItems(itemIds, personTypes);
}
+ /// <inheritdoc/>
+ public IReadOnlyDictionary<Guid, IReadOnlyList<PersonInfo>> GetPeopleByItems(IReadOnlyList<Guid> itemIds)
+ {
+ return _peopleRepository.GetPeopleByItems(itemIds);
+ }
+
public void UpdatePeople(BaseItem item, List<PersonInfo> people)
{
UpdatePeopleAsync(item, people, CancellationToken.None).GetAwaiter().GetResult();