mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-01-15 23:58:57 +00:00
Recognize file changes and remove data on change (#13839)
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
OpenAPI / OpenAPI - HEAD (push) Waiting to run
OpenAPI / OpenAPI - BASE (push) Waiting to run
OpenAPI / OpenAPI - Difference (push) Blocked by required conditions
OpenAPI / OpenAPI - Publish Unstable Spec (push) Blocked by required conditions
OpenAPI / OpenAPI - Publish Stable Spec (push) Blocked by required conditions
Tests / run-tests (macos-latest) (push) Waiting to run
Tests / run-tests (ubuntu-latest) (push) Waiting to run
Tests / run-tests (windows-latest) (push) Waiting to run
Project Automation / Project board (push) Waiting to run
Merge Conflict Labeler / Labeling (push) Waiting to run
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
OpenAPI / OpenAPI - HEAD (push) Waiting to run
OpenAPI / OpenAPI - BASE (push) Waiting to run
OpenAPI / OpenAPI - Difference (push) Blocked by required conditions
OpenAPI / OpenAPI - Publish Unstable Spec (push) Blocked by required conditions
OpenAPI / OpenAPI - Publish Stable Spec (push) Blocked by required conditions
Tests / run-tests (macos-latest) (push) Waiting to run
Tests / run-tests (ubuntu-latest) (push) Waiting to run
Tests / run-tests (windows-latest) (push) Waiting to run
Project Automation / Project board (push) Waiting to run
Merge Conflict Labeler / Labeling (push) Waiting to run
This commit is contained in:
@@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.Library
|
||||
/// Gets or sets the postscan tasks.
|
||||
/// </summary>
|
||||
/// <value>The postscan tasks.</value>
|
||||
private ILibraryPostScanTask[] PostscanTasks { get; set; } = [];
|
||||
private ILibraryPostScanTask[] PostScanTasks { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the intro providers.
|
||||
@@ -245,20 +245,20 @@ namespace Emby.Server.Implementations.Library
|
||||
/// <param name="resolvers">The resolvers.</param>
|
||||
/// <param name="introProviders">The intro providers.</param>
|
||||
/// <param name="itemComparers">The item comparers.</param>
|
||||
/// <param name="postscanTasks">The post scan tasks.</param>
|
||||
/// <param name="postScanTasks">The post scan tasks.</param>
|
||||
public void AddParts(
|
||||
IEnumerable<IResolverIgnoreRule> rules,
|
||||
IEnumerable<IItemResolver> resolvers,
|
||||
IEnumerable<IIntroProvider> introProviders,
|
||||
IEnumerable<IBaseItemComparer> itemComparers,
|
||||
IEnumerable<ILibraryPostScanTask> postscanTasks)
|
||||
IEnumerable<ILibraryPostScanTask> postScanTasks)
|
||||
{
|
||||
EntityResolutionIgnoreRules = rules.ToArray();
|
||||
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
|
||||
MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray();
|
||||
IntroProviders = introProviders.ToArray();
|
||||
Comparers = itemComparers.ToArray();
|
||||
PostscanTasks = postscanTasks.ToArray();
|
||||
PostScanTasks = postScanTasks.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -393,7 +393,7 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
if (options.DeleteFileLocation && item.IsFileProtocol)
|
||||
if ((options.DeleteFileLocation && item.IsFileProtocol) || IsInternalItem(item))
|
||||
{
|
||||
// Assume only the first is required
|
||||
// Add this flag to GetDeletePaths if required in the future
|
||||
@@ -472,6 +472,36 @@ namespace Emby.Server.Implementations.Library
|
||||
ReportItemRemoved(item, parent);
|
||||
}
|
||||
|
||||
private bool IsInternalItem(BaseItem item)
|
||||
{
|
||||
if (!item.IsFileProtocol)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pathToCheck = item switch
|
||||
{
|
||||
Genre => _configurationManager.ApplicationPaths.GenrePath,
|
||||
MusicArtist => _configurationManager.ApplicationPaths.ArtistsPath,
|
||||
MusicGenre => _configurationManager.ApplicationPaths.GenrePath,
|
||||
Person => _configurationManager.ApplicationPaths.PeoplePath,
|
||||
Studio => _configurationManager.ApplicationPaths.StudioPath,
|
||||
Year => _configurationManager.ApplicationPaths.YearPath,
|
||||
_ => null
|
||||
};
|
||||
|
||||
var itemPath = item.Path;
|
||||
if (!string.IsNullOrEmpty(pathToCheck) && !string.IsNullOrEmpty(itemPath))
|
||||
{
|
||||
var cleanPath = _fileSystem.GetValidFilename(itemPath);
|
||||
var cleanCheckPath = _fileSystem.GetValidFilename(pathToCheck);
|
||||
|
||||
return cleanPath.StartsWith(cleanCheckPath, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<string> GetMetadataPaths(BaseItem item, IEnumerable<BaseItem> children)
|
||||
{
|
||||
var list = GetInternalMetadataPaths(item);
|
||||
@@ -639,7 +669,7 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
// Need to remove subpaths that may have been resolved from shortcuts
|
||||
// Need to remove sub-paths that may have been resolved from shortcuts
|
||||
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
||||
if (isPhysicalRoot)
|
||||
{
|
||||
@@ -772,11 +802,12 @@ namespace Emby.Server.Implementations.Library
|
||||
// Add in the plug-in folders
|
||||
var path = Path.Combine(_configurationManager.ApplicationPaths.DataPath, "playlists");
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var info = Directory.CreateDirectory(path);
|
||||
Folder folder = new PlaylistsFolder
|
||||
{
|
||||
Path = path
|
||||
Path = path,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
};
|
||||
|
||||
if (folder.Id.IsEmpty())
|
||||
@@ -862,7 +893,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
Path = path,
|
||||
IsFolder = isFolder,
|
||||
OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
|
||||
OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending)],
|
||||
Limit = 1,
|
||||
DtoOptions = new DtoOptions(true)
|
||||
};
|
||||
@@ -968,7 +999,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
var existing = GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.MusicArtist },
|
||||
IncludeItemTypes = [BaseItemKind.MusicArtist],
|
||||
Name = name,
|
||||
DtoOptions = options
|
||||
}).Cast<MusicArtist>()
|
||||
@@ -987,12 +1018,13 @@ namespace Emby.Server.Implementations.Library
|
||||
var item = GetItemById(id) as T;
|
||||
if (item is null)
|
||||
{
|
||||
var info = Directory.CreateDirectory(path);
|
||||
item = new T
|
||||
{
|
||||
Name = name,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
Path = path
|
||||
};
|
||||
|
||||
@@ -1118,7 +1150,7 @@ namespace Emby.Server.Implementations.Library
|
||||
/// <returns>Task.</returns>
|
||||
private async Task RunPostScanTasks(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var tasks = PostscanTasks.ToList();
|
||||
var tasks = PostScanTasks.ToList();
|
||||
|
||||
var numComplete = 0;
|
||||
var numTasks = tasks.Count;
|
||||
@@ -1241,7 +1273,7 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
private CollectionTypeOptions? GetCollectionType(string path)
|
||||
{
|
||||
var files = _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false);
|
||||
var files = _fileSystem.GetFilePaths(path, [".collection"], true, false);
|
||||
foreach (ReadOnlySpan<char> file in files)
|
||||
{
|
||||
if (Enum.TryParse<CollectionTypeOptions>(Path.GetFileNameWithoutExtension(file), true, out var res))
|
||||
@@ -1312,7 +1344,7 @@ namespace Emby.Server.Implementations.Library
|
||||
var parent = GetItemById(query.ParentId);
|
||||
if (parent is not null)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, new[] { parent });
|
||||
SetTopParentIdsOrAncestors(query, [parent]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1343,7 +1375,7 @@ namespace Emby.Server.Implementations.Library
|
||||
var parent = GetItemById(query.ParentId);
|
||||
if (parent is not null)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, new[] { parent });
|
||||
SetTopParentIdsOrAncestors(query, [parent]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1531,7 +1563,7 @@ namespace Emby.Server.Implementations.Library
|
||||
var parent = GetItemById(query.ParentId);
|
||||
if (parent is not null)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, new[] { parent });
|
||||
SetTopParentIdsOrAncestors(query, [parent]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1561,7 +1593,7 @@ namespace Emby.Server.Implementations.Library
|
||||
// Prevent searching in all libraries due to empty filter
|
||||
if (query.TopParentIds.Length == 0)
|
||||
{
|
||||
query.TopParentIds = new[] { Guid.NewGuid() };
|
||||
query.TopParentIds = [Guid.NewGuid()];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1572,7 +1604,7 @@ namespace Emby.Server.Implementations.Library
|
||||
// Prevent searching in all libraries due to empty filter
|
||||
if (query.AncestorIds.Length == 0)
|
||||
{
|
||||
query.AncestorIds = new[] { Guid.NewGuid() };
|
||||
query.AncestorIds = [Guid.NewGuid()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1601,7 +1633,7 @@ namespace Emby.Server.Implementations.Library
|
||||
// Prevent searching in all libraries due to empty filter
|
||||
if (query.TopParentIds.Length == 0)
|
||||
{
|
||||
query.TopParentIds = new[] { Guid.NewGuid() };
|
||||
query.TopParentIds = [Guid.NewGuid()];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1644,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
if (view.ViewType == CollectionType.livetv)
|
||||
{
|
||||
return new[] { view.Id };
|
||||
return [view.Id];
|
||||
}
|
||||
|
||||
// Translate view into folders
|
||||
@@ -1661,7 +1693,7 @@ namespace Emby.Server.Implementations.Library
|
||||
var topParent = item.GetTopParent();
|
||||
if (topParent is not null)
|
||||
{
|
||||
return new[] { topParent.Id };
|
||||
return [topParent.Id];
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -1868,7 +1900,7 @@ namespace Emby.Server.Implementations.Library
|
||||
/// <inheritdoc />
|
||||
public void CreateItem(BaseItem item, BaseItem? parent)
|
||||
{
|
||||
CreateItems(new[] { item }, parent, CancellationToken.None);
|
||||
CreateItems([item], parent, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -2054,7 +2086,7 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||
=> UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken);
|
||||
=> UpdateItemsAsync([item], parent, updateReason, cancellationToken);
|
||||
|
||||
public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason)
|
||||
{
|
||||
@@ -2283,13 +2315,13 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (item is null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var info = Directory.CreateDirectory(path);
|
||||
item = new UserView
|
||||
{
|
||||
Path = path,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
Name = name,
|
||||
ViewType = viewType,
|
||||
ForcedSortName = sortName
|
||||
@@ -2331,13 +2363,13 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var info = Directory.CreateDirectory(path);
|
||||
item = new UserView
|
||||
{
|
||||
Path = path,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
Name = name,
|
||||
ViewType = viewType,
|
||||
ForcedSortName = sortName,
|
||||
@@ -2395,20 +2427,19 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var info = Directory.CreateDirectory(path);
|
||||
item = new UserView
|
||||
{
|
||||
Path = path,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
Name = name,
|
||||
ViewType = viewType,
|
||||
ForcedSortName = sortName
|
||||
ForcedSortName = sortName,
|
||||
DisplayParentId = parentId
|
||||
};
|
||||
|
||||
item.DisplayParentId = parentId;
|
||||
|
||||
CreateItem(item, null);
|
||||
|
||||
isNew = true;
|
||||
@@ -2465,20 +2496,19 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var info = Directory.CreateDirectory(path);
|
||||
item = new UserView
|
||||
{
|
||||
Path = path,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = info.LastWriteTimeUtc,
|
||||
Name = name,
|
||||
ViewType = viewType,
|
||||
ForcedSortName = sortName
|
||||
ForcedSortName = sortName,
|
||||
DisplayParentId = parentId
|
||||
};
|
||||
|
||||
item.DisplayParentId = parentId;
|
||||
|
||||
CreateItem(item, null);
|
||||
|
||||
isNew = true;
|
||||
@@ -2989,12 +3019,14 @@ namespace Emby.Server.Implementations.Library
|
||||
if (personEntity is null)
|
||||
{
|
||||
var path = Person.GetPath(person.Name);
|
||||
var info = Directory.CreateDirectory(path);
|
||||
var lastWriteTime = info.LastWriteTimeUtc;
|
||||
personEntity = new Person()
|
||||
{
|
||||
Name = person.Name,
|
||||
Id = GetItemByNameId<Person>(path),
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow,
|
||||
DateCreated = info.CreationTimeUtc,
|
||||
DateModified = lastWriteTime,
|
||||
Path = path
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user