mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 05:47:14 -04:00
Merge pull request #10218 from Bond-009/librarymonitor
This commit is contained in:
commit
7958a2fd15
@ -157,7 +157,7 @@ namespace Emby.Server.Implementations
|
|||||||
_fileSystemManager = new ManagedFileSystem(LoggerFactory.CreateLogger<ManagedFileSystem>(), applicationPaths);
|
_fileSystemManager = new ManagedFileSystem(LoggerFactory.CreateLogger<ManagedFileSystem>(), applicationPaths);
|
||||||
|
|
||||||
Logger = LoggerFactory.CreateLogger<ApplicationHost>();
|
Logger = LoggerFactory.CreateLogger<ApplicationHost>();
|
||||||
_fileSystemManager.AddShortcutHandler(new MbLinkShortcutHandler(_fileSystemManager));
|
_fileSystemManager.AddShortcutHandler(new MbLinkShortcutHandler());
|
||||||
_deviceId = new DeviceId(ApplicationPaths, LoggerFactory);
|
_deviceId = new DeviceId(ApplicationPaths, LoggerFactory);
|
||||||
|
|
||||||
ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version;
|
ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version;
|
||||||
|
@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetPath(string path, string affectedFile)
|
public void ResetPath(string path, string? affectedFile)
|
||||||
{
|
{
|
||||||
lock (_timerLock)
|
lock (_timerLock)
|
||||||
{
|
{
|
||||||
@ -148,13 +148,6 @@ namespace Emby.Server.Implementations.IO
|
|||||||
{
|
{
|
||||||
item.ChangedExternally();
|
item.ChangedExternally();
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
// For now swallow and log.
|
|
||||||
// Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable)
|
|
||||||
// Should we remove it from it's parent?
|
|
||||||
_logger.LogError(ex, "Error refreshing {Name}", item.Name);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error refreshing {Name}", item.Name);
|
_logger.LogError(ex, "Error refreshing {Name}", item.Name);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#nullable disable
|
|
||||||
|
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@ -160,7 +158,7 @@ namespace Emby.Server.Implementations.IO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">The source of the event.</param>
|
/// <param name="sender">The source of the event.</param>
|
||||||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||||
private void OnLibraryManagerItemRemoved(object sender, ItemChangeEventArgs e)
|
private void OnLibraryManagerItemRemoved(object? sender, ItemChangeEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Parent is AggregateFolder)
|
if (e.Parent is AggregateFolder)
|
||||||
{
|
{
|
||||||
@ -173,7 +171,7 @@ namespace Emby.Server.Implementations.IO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">The source of the event.</param>
|
/// <param name="sender">The source of the event.</param>
|
||||||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||||
private void OnLibraryManagerItemAdded(object sender, ItemChangeEventArgs e)
|
private void OnLibraryManagerItemAdded(object? sender, ItemChangeEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Parent is AggregateFolder)
|
if (e.Parent is AggregateFolder)
|
||||||
{
|
{
|
||||||
@ -189,19 +187,28 @@ namespace Emby.Server.Implementations.IO
|
|||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns><c>true</c> if [contains parent folder] [the specified LST]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [contains parent folder] [the specified LST]; otherwise, <c>false</c>.</returns>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c>.</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c>.</exception>
|
||||||
private static bool ContainsParentFolder(IEnumerable<string> lst, string path)
|
private static bool ContainsParentFolder(IReadOnlyList<string> lst, ReadOnlySpan<char> path)
|
||||||
{
|
{
|
||||||
ArgumentException.ThrowIfNullOrEmpty(path);
|
if (path.IsEmpty)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Path can't be empty", nameof(path));
|
||||||
|
}
|
||||||
|
|
||||||
path = path.TrimEnd(Path.DirectorySeparatorChar);
|
path = path.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
return lst.Any(str =>
|
foreach (var str in lst)
|
||||||
{
|
{
|
||||||
// this should be a little quicker than examining each actual parent folder...
|
// this should be a little quicker than examining each actual parent folder...
|
||||||
var compare = str.TrimEnd(Path.DirectorySeparatorChar);
|
var compare = str.AsSpan().TrimEnd(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
return path.Equals(compare, StringComparison.OrdinalIgnoreCase) || (path.StartsWith(compare, StringComparison.OrdinalIgnoreCase) && path[compare.Length] == Path.DirectorySeparatorChar);
|
if (path.Equals(compare, StringComparison.OrdinalIgnoreCase)
|
||||||
});
|
|| (path.StartsWith(compare, StringComparison.OrdinalIgnoreCase) && path[compare.Length] == Path.DirectorySeparatorChar))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -349,21 +356,19 @@ namespace Emby.Server.Implementations.IO
|
|||||||
{
|
{
|
||||||
ArgumentException.ThrowIfNullOrEmpty(path);
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
||||||
|
|
||||||
var monitorPath = !IgnorePatterns.ShouldIgnore(path);
|
if (IgnorePatterns.ShouldIgnore(path))
|
||||||
|
|
||||||
// Ignore certain files, If the parent of an ignored path has a change event, ignore that too
|
|
||||||
if (_tempIgnoredPaths.Keys.Any(i =>
|
|
||||||
{
|
{
|
||||||
if (_fileSystem.AreEqual(i, path))
|
return;
|
||||||
{
|
|
||||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fileSystem.ContainsSubPath(i, path))
|
// Ignore certain files, If the parent of an ignored path has a change event, ignore that too
|
||||||
|
foreach (var i in _tempIgnoredPaths.Keys)
|
||||||
|
{
|
||||||
|
if (_fileSystem.AreEqual(i, path)
|
||||||
|
|| _fileSystem.ContainsSubPath(i, path))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
_logger.LogDebug("Ignoring change to {Path}", path);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go up a level
|
// Go up a level
|
||||||
@ -371,21 +376,12 @@ namespace Emby.Server.Implementations.IO
|
|||||||
if (!string.IsNullOrEmpty(parent) && _fileSystem.AreEqual(parent, path))
|
if (!string.IsNullOrEmpty(parent) && _fileSystem.AreEqual(parent, path))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Ignoring change to {Path}", path);
|
_logger.LogDebug("Ignoring change to {Path}", path);
|
||||||
return true;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}))
|
|
||||||
{
|
|
||||||
monitorPath = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitorPath)
|
|
||||||
{
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
CreateRefresher(path);
|
CreateRefresher(path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateRefresher(string path)
|
private void CreateRefresher(string path)
|
||||||
{
|
{
|
||||||
@ -417,7 +413,8 @@ namespace Emby.Server.Implementations.IO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// They are siblings. Rebase the refresher to the parent folder.
|
// They are siblings. Rebase the refresher to the parent folder.
|
||||||
if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal))
|
if (parentPath is not null
|
||||||
|
&& Path.GetDirectoryName(refresher.Path.AsSpan()).Equals(parentPath, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
refresher.ResetPath(parentPath, path);
|
refresher.ResetPath(parentPath, path);
|
||||||
return;
|
return;
|
||||||
@ -430,8 +427,13 @@ namespace Emby.Server.Implementations.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNewRefresherCompleted(object sender, EventArgs e)
|
private void OnNewRefresherCompleted(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (sender is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var refresher = (FileRefresher)sender;
|
var refresher = (FileRefresher)sender;
|
||||||
DisposeRefresher(refresher);
|
DisposeRefresher(refresher);
|
||||||
}
|
}
|
||||||
|
@ -485,25 +485,11 @@ namespace Emby.Server.Implementations.IO
|
|||||||
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual string NormalizePath(string path)
|
|
||||||
{
|
|
||||||
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
||||||
|
|
||||||
if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Path.TrimEndingDirectorySeparator(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual bool AreEqual(string path1, string path2)
|
public virtual bool AreEqual(string path1, string path2)
|
||||||
{
|
{
|
||||||
return string.Equals(
|
return Path.TrimEndingDirectorySeparator(path1).Equals(
|
||||||
NormalizePath(path1),
|
Path.TrimEndingDirectorySeparator(path2),
|
||||||
NormalizePath(path2),
|
|
||||||
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,24 +8,17 @@ namespace Emby.Server.Implementations.IO
|
|||||||
{
|
{
|
||||||
public class MbLinkShortcutHandler : IShortcutHandler
|
public class MbLinkShortcutHandler : IShortcutHandler
|
||||||
{
|
{
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
|
|
||||||
public MbLinkShortcutHandler(IFileSystem fileSystem)
|
|
||||||
{
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Extension => ".mblink";
|
public string Extension => ".mblink";
|
||||||
|
|
||||||
public string? Resolve(string shortcutPath)
|
public string? Resolve(string shortcutPath)
|
||||||
{
|
{
|
||||||
ArgumentException.ThrowIfNullOrEmpty(shortcutPath);
|
ArgumentException.ThrowIfNullOrEmpty(shortcutPath);
|
||||||
|
|
||||||
if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase))
|
if (Path.GetExtension(shortcutPath.AsSpan()).Equals(".mblink", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var path = File.ReadAllText(shortcutPath);
|
var path = File.ReadAllText(shortcutPath);
|
||||||
|
|
||||||
return _fileSystem.NormalizePath(path);
|
return Path.TrimEndingDirectorySeparator(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -608,7 +608,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
var originalList = paths.ToList();
|
var originalList = paths.ToList();
|
||||||
|
|
||||||
var list = originalList.Where(i => i.IsDirectory)
|
var list = originalList.Where(i => i.IsDirectory)
|
||||||
.Select(i => _fileSystem.NormalizePath(i.FullName))
|
.Select(i => Path.TrimEndingDirectorySeparator(i.FullName))
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@ -116,13 +116,6 @@ namespace MediaBrowser.Model.IO
|
|||||||
/// <returns><c>true</c> if [contains sub path] [the specified parent path]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [contains sub path] [the specified parent path]; otherwise, <c>false</c>.</returns>
|
||||||
bool ContainsSubPath(string parentPath, string path);
|
bool ContainsSubPath(string parentPath, string path);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normalizes the path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
string NormalizePath(string path);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the file name without extension.
|
/// Gets the file name without extension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -52,6 +52,8 @@
|
|||||||
<Rule Id="SA1204" Action="None" />
|
<Rule Id="SA1204" Action="None" />
|
||||||
<!-- disable warning SA1309: Fields must not begin with an underscore -->
|
<!-- disable warning SA1309: Fields must not begin with an underscore -->
|
||||||
<Rule Id="SA1309" Action="None" />
|
<Rule Id="SA1309" Action="None" />
|
||||||
|
<!-- disable warning SA1311: Static readonly fields should begin with upper-case letter -->
|
||||||
|
<Rule Id="SA1311" Action="None" />
|
||||||
<!-- disable warning SA1413: Use trailing comma in multi-line initializers -->
|
<!-- disable warning SA1413: Use trailing comma in multi-line initializers -->
|
||||||
<Rule Id="SA1413" Action="None" />
|
<Rule Id="SA1413" Action="None" />
|
||||||
<!-- disable warning SA1512: Single-line comments must not be followed by blank line -->
|
<!-- disable warning SA1512: Single-line comments must not be followed by blank line -->
|
||||||
|
Loading…
Reference in New Issue
Block a user