aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Library')
-rw-r--r--Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs91
-rw-r--r--Emby.Server.Implementations/Library/ExternalDataManager.cs6
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs20
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs5
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs4
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs11
6 files changed, 84 insertions, 53 deletions
diff --git a/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs
index bafe3ad43..473ff8e1d 100644
--- a/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs
+++ b/Emby.Server.Implementations/Library/DotIgnoreIgnoreRule.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.IO;
@@ -11,28 +12,24 @@ namespace Emby.Server.Implementations.Library;
/// </summary>
public class DotIgnoreIgnoreRule : IResolverIgnoreRule
{
+ private static readonly bool IsWindows = OperatingSystem.IsWindows();
+
private static FileInfo? FindIgnoreFile(DirectoryInfo directory)
{
- var ignoreFile = new FileInfo(Path.Join(directory.FullName, ".ignore"));
- if (ignoreFile.Exists)
- {
- return ignoreFile;
- }
-
- var parentDir = directory.Parent;
- if (parentDir is null)
+ for (var current = directory; current is not null; current = current.Parent)
{
- return null;
+ var ignorePath = Path.Join(current.FullName, ".ignore");
+ if (File.Exists(ignorePath))
+ {
+ return new FileInfo(ignorePath);
+ }
}
- return FindIgnoreFile(parentDir);
+ return null;
}
/// <inheritdoc />
- public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent)
- {
- return IsIgnored(fileInfo, parent);
- }
+ public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) => IsIgnored(fileInfo, parent);
/// <summary>
/// Checks whether or not the file is ignored.
@@ -42,60 +39,58 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule
/// <returns>True if the file should be ignored.</returns>
public static bool IsIgnored(FileSystemMetadata fileInfo, BaseItem? parent)
{
- if (fileInfo.IsDirectory)
- {
- var dirIgnoreFile = FindIgnoreFile(new DirectoryInfo(fileInfo.FullName));
- if (dirIgnoreFile is null)
- {
- return false;
- }
-
- // Fast path in case the ignore files isn't a symlink and is empty
- if ((dirIgnoreFile.Attributes & FileAttributes.ReparsePoint) == 0
- && dirIgnoreFile.Length == 0)
- {
- return true;
- }
-
- // ignore the directory only if the .ignore file is empty
- // evaluate individual files otherwise
- return string.IsNullOrWhiteSpace(GetFileContent(dirIgnoreFile));
- }
+ var searchDirectory = fileInfo.IsDirectory
+ ? new DirectoryInfo(fileInfo.FullName)
+ : new DirectoryInfo(Path.GetDirectoryName(fileInfo.FullName) ?? string.Empty);
- var parentDirPath = Path.GetDirectoryName(fileInfo.FullName);
- if (string.IsNullOrEmpty(parentDirPath))
+ if (string.IsNullOrEmpty(searchDirectory.FullName))
{
return false;
}
- var folder = new DirectoryInfo(parentDirPath);
- var ignoreFile = FindIgnoreFile(folder);
+ var ignoreFile = FindIgnoreFile(searchDirectory);
if (ignoreFile is null)
{
return false;
}
- string ignoreFileString = GetFileContent(ignoreFile);
-
- if (string.IsNullOrWhiteSpace(ignoreFileString))
+ // Fast path in case the ignore files isn't a symlink and is empty
+ if (ignoreFile.LinkTarget is null && ignoreFile.Length == 0)
{
// Ignore directory if we just have the file
return true;
}
+ var content = GetFileContent(ignoreFile);
+ return string.IsNullOrWhiteSpace(content)
+ || CheckIgnoreRules(fileInfo.FullName, content, fileInfo.IsDirectory);
+ }
+
+ private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
+ {
// If file has content, base ignoring off the content .gitignore-style rules
- var ignoreRules = ignoreFileString.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ var rules = ignoreFileContent.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var ignore = new Ignore.Ignore();
- ignore.Add(ignoreRules);
+ ignore.Add(rules);
- return ignore.IsIgnored(fileInfo.FullName);
- }
+ // Mitigate the problem of the Ignore library not handling Windows paths correctly.
+ // See https://github.com/jellyfin/jellyfin/issues/15484
+ var pathToCheck = IsWindows ? path.NormalizePath('/') : path;
- private static string GetFileContent(FileInfo dirIgnoreFile)
- {
- using (var reader = dirIgnoreFile.OpenText())
+ // Add trailing slash for directories to match "folder/"
+ if (isDirectory)
{
- return reader.ReadToEnd();
+ pathToCheck = string.Concat(pathToCheck.AsSpan().TrimEnd('/'), "/");
}
+
+ return ignore.IsIgnored(pathToCheck);
+ }
+
+ private static string GetFileContent(FileInfo ignoreFile)
+ {
+ ignoreFile = FileSystemHelper.ResolveLinkTarget(ignoreFile, returnFinalTarget: true) ?? ignoreFile;
+ return ignoreFile.Exists
+ ? File.ReadAllText(ignoreFile.FullName)
+ : string.Empty;
}
}
diff --git a/Emby.Server.Implementations/Library/ExternalDataManager.cs b/Emby.Server.Implementations/Library/ExternalDataManager.cs
index d3cfa1d25..4ad0f999b 100644
--- a/Emby.Server.Implementations/Library/ExternalDataManager.cs
+++ b/Emby.Server.Implementations/Library/ExternalDataManager.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.MediaSegments;
@@ -20,6 +21,7 @@ public class ExternalDataManager : IExternalDataManager
private readonly IMediaSegmentManager _mediaSegmentManager;
private readonly IPathManager _pathManager;
private readonly ITrickplayManager _trickplayManager;
+ private readonly IChapterManager _chapterManager;
private readonly ILogger<ExternalDataManager> _logger;
/// <summary>
@@ -29,18 +31,21 @@ public class ExternalDataManager : IExternalDataManager
/// <param name="mediaSegmentManager">The media segment manager.</param>
/// <param name="pathManager">The path manager.</param>
/// <param name="trickplayManager">The trickplay manager.</param>
+ /// <param name="chapterManager">The chapter manager.</param>
/// <param name="logger">The logger.</param>
public ExternalDataManager(
IKeyframeManager keyframeManager,
IMediaSegmentManager mediaSegmentManager,
IPathManager pathManager,
ITrickplayManager trickplayManager,
+ IChapterManager chapterManager,
ILogger<ExternalDataManager> logger)
{
_keyframeManager = keyframeManager;
_mediaSegmentManager = mediaSegmentManager;
_pathManager = pathManager;
_trickplayManager = trickplayManager;
+ _chapterManager = chapterManager;
_logger = logger;
}
@@ -67,5 +72,6 @@ public class ExternalDataManager : IExternalDataManager
await _keyframeManager.DeleteKeyframeDataAsync(itemId, cancellationToken).ConfigureAwait(false);
await _mediaSegmentManager.DeleteSegmentsAsync(itemId, cancellationToken).ConfigureAwait(false);
await _trickplayManager.DeleteTrickplayDataAsync(itemId, cancellationToken).ConfigureAwait(false);
+ await _chapterManager.DeleteChapterDataAsync(itemId, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index e2d8325fe..cab87e53d 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -457,6 +457,12 @@ namespace Emby.Server.Implementations.Library
_cache.TryRemove(child.Id, out _);
}
+ if (parent is Folder folder)
+ {
+ folder.Children = null;
+ folder.UserData = null;
+ }
+
ReportItemRemoved(item, parent);
}
@@ -1993,6 +1999,12 @@ namespace Emby.Server.Implementations.Library
RegisterItem(item);
}
+ if (parent is Folder folder)
+ {
+ folder.Children = null;
+ folder.UserData = null;
+ }
+
if (ItemAdded is not null)
{
foreach (var item in items)
@@ -2129,6 +2141,8 @@ namespace Emby.Server.Implementations.Library
}
}
+ item.ValidateImages();
+
_itemRepository.SaveImages(item);
RegisterItem(item);
@@ -2148,6 +2162,12 @@ namespace Emby.Server.Implementations.Library
_itemRepository.SaveItems(items, cancellationToken);
+ if (parent is Folder folder)
+ {
+ folder.Children = null;
+ folder.UserData = null;
+ }
+
if (ItemUpdated is not null)
{
foreach (var item in items)
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 750346169..c667fb060 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc />>
public MediaProtocol GetPathProtocol(string path)
{
+ if (string.IsNullOrEmpty(path))
+ {
+ return MediaProtocol.File;
+ }
+
if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Rtsp;
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index e0c8ae371..e19ad3ef6 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -28,7 +28,9 @@ namespace Emby.Server.Implementations.Library
public IReadOnlyList<BaseItem> GetInstantMixFromSong(Audio item, User? user, DtoOptions dtoOptions)
{
- return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
+ var instantMixItems = GetInstantMixFromGenres(item.Genres, user, dtoOptions);
+
+ return [item, .. instantMixItems.Where(i => !i.Id.Equals(item.Id))];
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 333c8c34b..98e8f5350 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -369,13 +369,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
// We need to only look at the name of this actual item (not parents)
var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path.AsSpan()) : Path.GetFileName(item.ContainingFolderPath.AsSpan());
- if (!justName.IsEmpty)
+ var tmdbid = justName.GetAttributeValue("tmdbid");
+
+ // If not in a mixed folder and ID not found in folder path, check filename
+ if (string.IsNullOrEmpty(tmdbid) && !item.IsInMixedFolder)
{
- // Check for TMDb id
- var tmdbid = justName.GetAttributeValue("tmdbid");
- item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
+ tmdbid = Path.GetFileName(item.Path.AsSpan()).GetAttributeValue("tmdbid");
}
+ item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
+
if (!string.IsNullOrEmpty(item.Path))
{
// Check for IMDb id - we use full media path, as we can assume that this will match in any use case (whether id in parent dir or in file name)