diff options
| author | JPVenson <github@jpb.email> | 2025-09-25 00:20:30 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-24 15:20:30 -0600 |
| commit | 5a6d9180fed81a30cb91ef3fed30176cd4402116 (patch) | |
| tree | c67bfa1cfe27ff1a7b7a09e3a7d201ef543652a0 /Emby.Server.Implementations/Library/LibraryManager.cs | |
| parent | 897975fc57f1669322f6db18753939dbf6be43e8 (diff) | |
Add People Dedup and multiple progress fixes (#14848)
Diffstat (limited to 'Emby.Server.Implementations/Library/LibraryManager.cs')
| -rw-r--r-- | Emby.Server.Implementations/Library/LibraryManager.cs | 166 |
1 files changed, 110 insertions, 56 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index a66835dec..102779729 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -327,6 +327,45 @@ namespace Emby.Server.Implementations.Library DeleteItem(item, options, parent, notifyParentItem); } + public void DeleteItemsUnsafeFast(IEnumerable<BaseItem> items) + { + var pathMaps = items.Select(e => (Item: e, InternalPath: GetInternalMetadataPaths(e), DeletePaths: e.GetDeletePaths())).ToArray(); + + foreach (var (item, internalPaths, pathsToDelete) in pathMaps) + { + foreach (var metadataPath in internalPaths) + { + if (!Directory.Exists(metadataPath)) + { + continue; + } + + _logger.LogDebug( + "Deleting metadata path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", + item.GetType().Name, + item.Name ?? "Unknown name", + metadataPath, + item.Id); + + try + { + Directory.Delete(metadataPath, true); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error deleting {MetadataPath}", metadataPath); + } + } + + foreach (var fileSystemInfo in pathsToDelete) + { + DeleteItemPath(item, false, fileSystemInfo); + } + } + + _itemRepository.DeleteItem([.. pathMaps.Select(f => f.Item.Id)]); + } + public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem) { ArgumentNullException.ThrowIfNull(item); @@ -403,59 +442,7 @@ namespace Emby.Server.Implementations.Library foreach (var fileSystemInfo in item.GetDeletePaths()) { - if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName)) - { - try - { - _logger.LogInformation( - "Deleting item path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", - item.GetType().Name, - item.Name ?? "Unknown name", - fileSystemInfo.FullName, - item.Id); - - if (fileSystemInfo.IsDirectory) - { - Directory.Delete(fileSystemInfo.FullName, true); - } - else - { - File.Delete(fileSystemInfo.FullName); - } - } - catch (DirectoryNotFoundException) - { - _logger.LogInformation( - "Directory not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", - item.GetType().Name, - item.Name ?? "Unknown name", - fileSystemInfo.FullName, - item.Id); - } - catch (FileNotFoundException) - { - _logger.LogInformation( - "File not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", - item.GetType().Name, - item.Name ?? "Unknown name", - fileSystemInfo.FullName, - item.Id); - } - catch (IOException) - { - if (isRequiredForDelete) - { - throw; - } - } - catch (UnauthorizedAccessException) - { - if (isRequiredForDelete) - { - throw; - } - } - } + DeleteItemPath(item, isRequiredForDelete, fileSystemInfo); isRequiredForDelete = false; } @@ -463,17 +450,73 @@ namespace Emby.Server.Implementations.Library item.SetParent(null); - _itemRepository.DeleteItem(item.Id); + _itemRepository.DeleteItem([item.Id, .. children.Select(f => f.Id)]); _cache.TryRemove(item.Id, out _); foreach (var child in children) { - _itemRepository.DeleteItem(child.Id); _cache.TryRemove(child.Id, out _); } ReportItemRemoved(item, parent); } + private void DeleteItemPath(BaseItem item, bool isRequiredForDelete, FileSystemMetadata fileSystemInfo) + { + if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName)) + { + try + { + _logger.LogInformation( + "Deleting item path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", + item.GetType().Name, + item.Name ?? "Unknown name", + fileSystemInfo.FullName, + item.Id); + + if (fileSystemInfo.IsDirectory) + { + Directory.Delete(fileSystemInfo.FullName, true); + } + else + { + File.Delete(fileSystemInfo.FullName); + } + } + catch (DirectoryNotFoundException) + { + _logger.LogInformation( + "Directory not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", + item.GetType().Name, + item.Name ?? "Unknown name", + fileSystemInfo.FullName, + item.Id); + } + catch (FileNotFoundException) + { + _logger.LogInformation( + "File not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}", + item.GetType().Name, + item.Name ?? "Unknown name", + fileSystemInfo.FullName, + item.Id); + } + catch (IOException) + { + if (isRequiredForDelete) + { + throw; + } + } + catch (UnauthorizedAccessException) + { + if (isRequiredForDelete) + { + throw; + } + } + } + } + private bool IsInternalItem(BaseItem item) { if (!item.IsFileProtocol) @@ -990,6 +1033,11 @@ namespace Emby.Server.Implementations.Library return GetArtist(name, new DtoOptions(true)); } + public IReadOnlyDictionary<string, MusicArtist[]> GetArtists(IReadOnlyList<string> names) + { + return _itemRepository.FindArtists(names); + } + public MusicArtist GetArtist(string name, DtoOptions options) { return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name, options); @@ -1115,18 +1163,24 @@ namespace Emby.Server.Implementations.Library cancellationToken: cancellationToken).ConfigureAwait(false); // Quickly scan CollectionFolders for changes + var toDelete = new List<Guid>(); foreach (var child in rootFolder.Children!.OfType<Folder>()) { // If the user has somehow deleted the collection directory, remove the metadata from the database. if (child is CollectionFolder collectionFolder && !Directory.Exists(collectionFolder.Path)) { - _itemRepository.DeleteItem(collectionFolder.Id); + toDelete.Add(collectionFolder.Id); } else { await child.RefreshMetadata(cancellationToken).ConfigureAwait(false); } } + + if (toDelete.Count > 0) + { + _itemRepository.DeleteItem(toDelete.ToArray()); + } } private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken) |
