From 434bcdae4c02f188bc6ba6648680accfb391e71e Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Tue, 27 Jul 2021 10:24:23 -0500 Subject: [PATCH] Ignore Mac metadata hidden files ._* (#443) * Implemented the ability to completely ignore all MacOS ._ files. They are ignored for all I/O operations (on all OSes) --- API/Parser/Parser.cs | 1 + API/Services/ArchiveService.cs | 18 ++++++++++++++---- API/Services/DirectoryService.cs | 6 ++++-- Kavita.Common/Kavita.Common.csproj | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 914508f9f..6b5a79b4b 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -16,6 +16,7 @@ namespace API.Parser public const string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg)"; public const string ArchiveFileExtensions = @"\.cbz|\.zip|\.rar|\.cbr|\.tar.gz|\.7zip|\.7z|\.cb7|\.cbt"; public const string BookFileExtensions = @"\.epub|\.pdf"; + public const string MacOsMetadataFileStartsWith = @"._"; public const string SupportedExtensions = ArchiveFileExtensions + "|" + ImageFileExtensions + "|" + BookFileExtensions; diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index a03188a5d..36eded36b 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -117,7 +117,8 @@ namespace API.Services { var result = entryFullNames .FirstOrDefault(x => !Path.EndsInDirectorySeparator(x) && !Parser.Parser.HasBlacklistedFolderInPath(x) - && Parser.Parser.IsCoverImage(x)); + && Parser.Parser.IsCoverImage(x) + && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); return string.IsNullOrEmpty(result) ? null : result; } @@ -131,7 +132,8 @@ namespace API.Services { var result = entryFullNames.OrderBy(Path.GetFileName, _comparer) .FirstOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x) - && Parser.Parser.IsImage(x)); + && Parser.Parser.IsImage(x) + && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); return string.IsNullOrEmpty(result) ? null : result; } @@ -295,7 +297,11 @@ namespace API.Services { foreach (var entry in entries) { - if (Path.GetFileNameWithoutExtension(entry.Key).ToLower().EndsWith("comicinfo") && !Parser.Parser.HasBlacklistedFolderInPath(entry.Key) && Parser.Parser.IsXml(entry.Key)) + var filename = Path.GetFileNameWithoutExtension(entry.Key).ToLower(); + if (filename.EndsWith("comicinfo") + && !filename.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith) + && !Parser.Parser.HasBlacklistedFolderInPath(entry.Key) + && Parser.Parser.IsXml(entry.Key)) { using var ms = StreamManager.GetStream(); entry.WriteTo(ms); @@ -328,7 +334,10 @@ namespace API.Services { _logger.LogDebug("Using default compression handling"); using var archive = ZipFile.OpenRead(archivePath); - var entry = archive.Entries.SingleOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x.FullName) && Path.GetFileNameWithoutExtension(x.Name).ToLower() == "comicinfo" && Parser.Parser.IsXml(x.FullName)); + var entry = archive.Entries.SingleOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x.FullName) + && Path.GetFileNameWithoutExtension(x.Name).ToLower() == "comicinfo" + && !Path.GetFileNameWithoutExtension(x.Name).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith) + && Parser.Parser.IsXml(x.FullName)); if (entry != null) { using var stream = entry.Open(); @@ -343,6 +352,7 @@ namespace API.Services using var archive = ArchiveFactory.Open(archivePath); info = FindComicInfoXml(archive.Entries.Where(entry => !entry.IsDirectory && !Parser.Parser.HasBlacklistedFolderInPath(Path.GetDirectoryName(entry.Key) ?? string.Empty) + && !Path.GetFileNameWithoutExtension(entry.Key).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith) && Parser.Parser.IsXml(entry.Key))); break; } diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index d0e5cce84..80156bd2a 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -25,6 +25,7 @@ namespace API.Services /// /// Given a set of regex search criteria, get files in the given path. /// + /// This will always exclude patterns /// Directory to search /// Regex version of search pattern (ie \.mp3|\.mp4). Defaults to * meaning all files. /// SearchOption to use, defaults to TopDirectoryOnly @@ -35,9 +36,10 @@ namespace API.Services { if (!Directory.Exists(path)) return ImmutableList.Empty; var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase); + return Directory.EnumerateFiles(path, "*", searchOption) .Where(file => - reSearchPattern.IsMatch(Path.GetExtension(file))); + reSearchPattern.IsMatch(Path.GetExtension(file)) && !Path.GetFileName(file).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); } @@ -98,7 +100,7 @@ namespace API.Services var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase); return Directory.EnumerateFiles(path, "*", searchOption) .Where(file => - reSearchPattern.IsMatch(file)); + reSearchPattern.IsMatch(file) && !file.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); } return !Directory.Exists(path) ? Array.Empty() : Directory.GetFiles(path); diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index dd2a776da..b24530f56 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,7 +4,7 @@ net5.0 kavitareader.com Kavita - 0.4.3.3 + 0.4.3.4 en