Merge pull request #17231 from theguymadmax/fix-paths-not-being-deleted

Fix ghost entries when deleting library paths
This commit is contained in:
Bond-009
2026-07-05 16:19:46 +02:00
committed by GitHub
3 changed files with 25 additions and 6 deletions

View File

@@ -691,7 +691,7 @@ namespace Emby.Server.Implementations.IO
} }
catch (Exception ex) when (ex is UnauthorizedAccessException or DirectoryNotFoundException or SecurityException) catch (Exception ex) when (ex is UnauthorizedAccessException or DirectoryNotFoundException or SecurityException)
{ {
_logger.LogError(ex, "Failed to enumerate path {Path}", path); _logger.LogWarning("Failed to enumerate path \"{Path}\": {Message}", path, ex.Message);
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
} }

View File

@@ -1,6 +1,7 @@
#nullable disable #nullable disable
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
@@ -46,7 +47,16 @@ namespace Emby.Server.Implementations.Library.Resolvers
} }
// It's a directory-based playlist if the directory contains a playlist file // It's a directory-based playlist if the directory contains a playlist file
var filePaths = Directory.EnumerateFiles(args.Path, "*", new EnumerationOptions { IgnoreInaccessible = true }); IEnumerable<string> filePaths;
try
{
filePaths = Directory.EnumerateFiles(args.Path, "*", new EnumerationOptions { IgnoreInaccessible = true });
}
catch (IOException)
{
return null;
}
if (filePaths.Any(f => f.EndsWith(PlaylistXmlSaver.DefaultPlaylistFilename, StringComparison.OrdinalIgnoreCase))) if (filePaths.Any(f => f.EndsWith(PlaylistXmlSaver.DefaultPlaylistFilename, StringComparison.OrdinalIgnoreCase)))
{ {
return new Playlist return new Playlist

View File

@@ -384,6 +384,7 @@ namespace MediaBrowser.Controller.Entities
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var validChildren = new List<BaseItem>(); var validChildren = new List<BaseItem>();
var accessibleChildren = new List<BaseItem>();
var validChildrenNeedGeneration = false; var validChildrenNeedGeneration = false;
if (IsFileProtocol) if (IsFileProtocol)
@@ -438,12 +439,19 @@ namespace MediaBrowser.Controller.Entities
{ {
if (!IsLibraryFolderAccessible(directoryService, child, allowRemoveRoot)) if (!IsLibraryFolderAccessible(directoryService, child, allowRemoveRoot))
{ {
// Preserve inaccessible items so they aren't treated as removed.
if (currentChildren.TryGetValue(child.Id, out var childrenToKeep))
{
validChildren.Add(childrenToKeep);
}
continue; continue;
} }
if (currentChildren.TryGetValue(child.Id, out BaseItem currentChild)) if (currentChildren.TryGetValue(child.Id, out BaseItem currentChild))
{ {
validChildren.Add(currentChild); validChildren.Add(currentChild);
accessibleChildren.Add(currentChild);
if (currentChild.UpdateFromResolvedItem(child) > ItemUpdateType.None) if (currentChild.UpdateFromResolvedItem(child) > ItemUpdateType.None)
{ {
@@ -480,11 +488,12 @@ namespace MediaBrowser.Controller.Entities
child.SetParent(this); child.SetParent(this);
newItems.Add(child); newItems.Add(child);
validChildren.Add(child); validChildren.Add(child);
accessibleChildren.Add(child);
} }
// That's all the new and changed ones - now see if any have been removed and need cleanup // That's all the new and changed ones - now see if any have been removed and need cleanup
var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); var itemsRemoved = currentChildren.Values.Except(validChildren).ToList();
var shouldRemove = !IsRoot || allowRemoveRoot;
// If it's an AggregateFolder, don't remove // If it's an AggregateFolder, don't remove
// Collect replaced primaries for deferred deletion (after CreateItems) // Collect replaced primaries for deferred deletion (after CreateItems)
var replacedPrimaries = new List<(Video OldPrimary, Video NewPrimary)>(); var replacedPrimaries = new List<(Video OldPrimary, Video NewPrimary)>();
@@ -497,7 +506,7 @@ namespace MediaBrowser.Controller.Entities
.Where(p => !string.IsNullOrEmpty(p)) .Where(p => !string.IsNullOrEmpty(p))
.ToHashSet(StringComparer.OrdinalIgnoreCase); .ToHashSet(StringComparer.OrdinalIgnoreCase);
if (shouldRemove && itemsRemoved.Count > 0) if (itemsRemoved.Count > 0)
{ {
foreach (var item in itemsRemoved) foreach (var item in itemsRemoved)
{ {
@@ -703,7 +712,7 @@ namespace MediaBrowser.Controller.Entities
validChildrenNeedGeneration = false; validChildrenNeedGeneration = false;
} }
await ValidateSubFolders(validChildren.OfType<Folder>().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false); await ValidateSubFolders(accessibleChildren.OfType<Folder>().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false);
} }
if (refreshChildMetadata) if (refreshChildMetadata)
@@ -742,7 +751,7 @@ namespace MediaBrowser.Controller.Entities
validChildren = Children.ToList(); validChildren = Children.ToList();
} }
await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken).ConfigureAwait(false); await RefreshMetadataRecursive(accessibleChildren, refreshOptions, recursive, innerProgress, cancellationToken).ConfigureAwait(false);
} }
} }
} }