diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs index 9ea59a239..e448ddf1c 100644 --- a/API.Tests/Services/ArchiveServiceTests.cs +++ b/API.Tests/Services/ArchiveServiceTests.cs @@ -1,6 +1,7 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.IO; +using System.IO.Compression; +using API.Archive; using API.Interfaces.Services; using API.Services; using Microsoft.Extensions.Logging; @@ -22,18 +23,18 @@ namespace API.Tests.Services _archiveService = new ArchiveService(_logger); } - // [Theory] - // [InlineData("flat file.zip", false)] - // [InlineData("file in folder in folder.zip", true)] - // [InlineData("file in folder.zip", true)] - // [InlineData("file in folder_alt.zip", true)] - // public void ArchiveNeedsFlatteningTest(string archivePath, bool expected) - // { - // var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); - // var file = Path.Join(testDirectory, archivePath); - // using ZipArchive archive = ZipFile.OpenRead(file); - // Assert.Equal(expected, _archiveService.ArchiveNeedsFlattening(archive)); - // } + [Theory] + [InlineData("flat file.zip", false)] + [InlineData("file in folder in folder.zip", true)] + [InlineData("file in folder.zip", true)] + [InlineData("file in folder_alt.zip", true)] + public void ArchiveNeedsFlatteningTest(string archivePath, bool expected) + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); + var file = Path.Join(testDirectory, archivePath); + using ZipArchive archive = ZipFile.OpenRead(file); + Assert.Equal(expected, _archiveService.ArchiveNeedsFlattening(archive)); + } [Theory] [InlineData("non existent file.zip", false)] @@ -68,19 +69,19 @@ namespace API.Tests.Services [Theory] - [InlineData("non existent file.zip", false)] - [InlineData("winrar.rar", true)] - //[InlineData("empty.zip", false)] - [InlineData("flat file.zip", true)] - [InlineData("file in folder in folder.zip", true)] - [InlineData("file in folder.zip", true)] - [InlineData("file in folder_alt.zip", true)] - public void CanOpenArchive(string archivePath, bool expected) + [InlineData("non existent file.zip", ArchiveLibrary.NotSupported)] + [InlineData("winrar.rar", ArchiveLibrary.SharpCompress)] + [InlineData("empty.zip", ArchiveLibrary.Default)] + [InlineData("flat file.zip", ArchiveLibrary.Default)] + [InlineData("file in folder in folder.zip", ArchiveLibrary.Default)] + [InlineData("file in folder.zip", ArchiveLibrary.Default)] + [InlineData("file in folder_alt.zip", ArchiveLibrary.Default)] + public void CanOpenArchive(string archivePath, ArchiveLibrary expected) { var sw = Stopwatch.StartNew(); var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); - Assert.Equal(expected, _archiveService.IsValidArchive(Path.Join(testDirectory, archivePath))); + Assert.Equal(expected, _archiveService.CanOpen(Path.Join(testDirectory, archivePath))); _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms"); } @@ -98,7 +99,8 @@ namespace API.Tests.Services var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); var extractDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives/Extraction"); - DirectoryService.ClearDirectory(extractDirectory); + + DirectoryService.ClearAndDeleteDirectory(extractDirectory); Stopwatch sw = Stopwatch.StartNew(); _archiveService.ExtractArchive(Path.Join(testDirectory, archivePath), extractDirectory); diff --git a/API/Archive/Archive.cs b/API/Archive/Archive.cs deleted file mode 100644 index 9f55c8153..000000000 --- a/API/Archive/Archive.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using SharpCompress.Archives; - -namespace API.Archive -{ - public static class Archive - { - /// - /// Checks if a File can be opened. Requires up to 2 opens of the filestream. - /// - /// - /// - public static ArchiveLibrary CanOpen(string archivePath) - { - // TODO: Should I introduce something for NotFound? - if (!File.Exists(archivePath) || !Parser.Parser.IsArchive(archivePath)) return ArchiveLibrary.NotSupported; - - try - { - using var a2 = ZipFile.OpenRead(archivePath); - return ArchiveLibrary.Default; - - } - catch (Exception) - { - try - { - using var a1 = ArchiveFactory.Open(archivePath); - return ArchiveLibrary.SharpCompress; - } - catch (Exception) - { - return ArchiveLibrary.NotSupported; - } - } - } - - - } -} \ No newline at end of file diff --git a/API/Archive/ArchiveMetadata.cs b/API/Archive/ArchiveMetadata.cs deleted file mode 100644 index 3f6b5d03b..000000000 --- a/API/Archive/ArchiveMetadata.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace API.Archive -{ - public class ArchiveMetadata - { - public byte[] CoverImage { get; set; } - public string Summary { get; set; } - public int Pages { get; set; } - //public string Format { get; set; } - } -} \ No newline at end of file diff --git a/API/Interfaces/Services/IArchiveService.cs b/API/Interfaces/Services/IArchiveService.cs index 427b16f37..640991db6 100644 --- a/API/Interfaces/Services/IArchiveService.cs +++ b/API/Interfaces/Services/IArchiveService.cs @@ -1,4 +1,5 @@ -using API.Archive; +using System.IO.Compression; +using API.Archive; namespace API.Interfaces.Services { @@ -9,6 +10,7 @@ namespace API.Interfaces.Services byte[] GetCoverImage(string filepath, bool createThumbnail = false); bool IsValidArchive(string archivePath); string GetSummaryInfo(string archivePath); - ArchiveMetadata GetArchiveData(string archivePath, bool createThumbnail); + ArchiveLibrary CanOpen(string archivePath); + bool ArchiveNeedsFlattening(ZipArchive archive); } } \ No newline at end of file diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 550e9fb8f..960fa2627 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -12,12 +11,7 @@ using API.Interfaces.Services; using API.Services.Tasks; using Microsoft.Extensions.Logging; using SharpCompress.Archives; -using SharpCompress.Archives.GZip; -using SharpCompress.Archives.Rar; -using SharpCompress.Archives.SevenZip; -using SharpCompress.Archives.Tar; using SharpCompress.Common; -using SharpCompress.Readers; using Image = NetVips.Image; namespace API.Services @@ -35,6 +29,35 @@ namespace API.Services _logger = logger; } + /// + /// Checks if a File can be opened. Requires up to 2 opens of the filestream. + /// + /// + /// + public ArchiveLibrary CanOpen(string archivePath) + { + if (!File.Exists(archivePath) || !Parser.Parser.IsArchive(archivePath)) return ArchiveLibrary.NotSupported; + + try + { + using var a2 = ZipFile.OpenRead(archivePath); + return ArchiveLibrary.Default; + + } + catch (Exception) + { + try + { + using var a1 = ArchiveFactory.Open(archivePath); + return ArchiveLibrary.SharpCompress; + } + catch (Exception) + { + return ArchiveLibrary.NotSupported; + } + } + } + public int GetNumberOfPagesFromArchive(string archivePath) { if (!IsValidArchive(archivePath)) @@ -48,7 +71,7 @@ namespace API.Services try { - var libraryHandler = Archive.Archive.CanOpen(archivePath); + var libraryHandler = CanOpen(archivePath); switch (libraryHandler) { case ArchiveLibrary.Default: @@ -70,85 +93,14 @@ namespace API.Services _logger.LogError("[GetNumberOfPagesFromArchive] There was an exception when reading archive stream: {ArchivePath}. Defaulting to 0 pages", archivePath); return 0; } - - - // using Stream stream = File.OpenRead(archivePath); - // using (var reader = ReaderFactory.Open(stream)) - // { - // try - // { - // _logger.LogDebug("{ArchivePath}'s Type: {ArchiveType}", archivePath, reader.ArchiveType); - // } - // catch (InvalidOperationException ex) - // { - // _logger.LogError(ex, "Could not parse the archive. Please validate it is not corrupted, {ArchivePath}", archivePath); - // return 0; - // } - // - // while (reader.MoveToNextEntry()) - // { - // if (!reader.Entry.IsDirectory && Parser.Parser.IsImage(reader.Entry.Key)) - // { - // count++; - // } - // } - // } } catch (Exception ex) { _logger.LogError(ex, "[GetNumberOfPagesFromArchive] There was an exception when reading archive stream: {ArchivePath}. Defaulting to 0 pages", archivePath); return 0; } - - - - - try - { - using var archive = ArchiveFactory.Open(archivePath); - return archive.Entries.Where(entry => !entry.IsDirectory && Parser.Parser.IsImage(entry.Key)).Count(); - - // using Stream stream = File.OpenRead(archivePath); - // using (var reader = ReaderFactory.Open(stream)) - // { - // try - // { - // _logger.LogDebug("{ArchivePath}'s Type: {ArchiveType}", archivePath, reader.ArchiveType); - // } - // catch (InvalidOperationException ex) - // { - // _logger.LogError(ex, "Could not parse the archive. Please validate it is not corrupted, {ArchivePath}", archivePath); - // return 0; - // } - // - // while (reader.MoveToNextEntry()) - // { - // if (!reader.Entry.IsDirectory && Parser.Parser.IsImage(reader.Entry.Key)) - // { - // count++; - // } - // } - // } - } - catch (Exception ex) - { - _logger.LogError(ex, "[GetNumberOfPagesFromArchive] There was an exception when reading archive stream: {ArchivePath}. Defaulting to 0 pages", archivePath); - return 0; - } - - return count; } - - public ArchiveMetadata GetArchiveData(string archivePath, bool createThumbnail) - { - return new ArchiveMetadata() - { - Pages = GetNumberOfPagesFromArchive(archivePath), - //Summary = GetSummaryInfo(archivePath), - CoverImage = GetCoverImage(archivePath, createThumbnail) - }; - } - + /// /// Generates byte array of cover image. /// Given a path to a compressed file (zip, rar, cbz, cbr, etc), will ensure the first image is returned unless @@ -159,13 +111,10 @@ namespace API.Services /// public byte[] GetCoverImage(string archivePath, bool createThumbnail = false) { + if (archivePath == null || !IsValidArchive(archivePath)) return Array.Empty(); try { - if (!IsValidArchive(archivePath)) return Array.Empty(); - - var libraryHandler = Archive.Archive.CanOpen(archivePath); - - + var libraryHandler = CanOpen(archivePath); switch (libraryHandler) { case ArchiveLibrary.Default: @@ -228,26 +177,6 @@ namespace API.Services return Array.Empty(); } - private byte[] CreateThumbnail(byte[] entry, string formatExtension = ".jpg") - { - if (!formatExtension.StartsWith(".")) - { - formatExtension = "." + formatExtension; - } - // TODO: Validate if jpeg is same as jpg - try - { - using var thumbnail = Image.ThumbnailBuffer(entry, ThumbnailWidth); - return thumbnail.WriteToBuffer(formatExtension); - } - catch (Exception ex) - { - _logger.LogError(ex, "[CreateThumbnail] There was a critical error and prevented thumbnail generation. Defaulting to no cover image"); - } - - return Array.Empty(); - } - private static byte[] ConvertEntryToByteArray(ZipArchiveEntry entry) { using var stream = entry.Open(); @@ -272,6 +201,25 @@ namespace API.Services archive.Entries.Any(e => e.FullName.Contains(Path.AltDirectorySeparatorChar)); } + private byte[] CreateThumbnail(byte[] entry, string formatExtension = ".jpg") + { + if (!formatExtension.StartsWith(".")) + { + formatExtension = "." + formatExtension; + } + // TODO: Validate if jpeg is same as jpg + try + { + using var thumbnail = Image.ThumbnailBuffer(entry, ThumbnailWidth); + return thumbnail.WriteToBuffer(formatExtension); + } + catch (Exception ex) + { + _logger.LogError(ex, "[CreateThumbnail] There was a critical error and prevented thumbnail generation. Defaulting to no cover image"); + } + + return Array.Empty(); + } private byte[] CreateThumbnail(ZipArchiveEntry entry, string formatExtension = ".jpg") { @@ -344,7 +292,7 @@ namespace API.Services { if (!File.Exists(archivePath)) return summary; - var libraryHandler = Archive.Archive.CanOpen(archivePath); + var libraryHandler = CanOpen(archivePath); switch (libraryHandler) { case ArchiveLibrary.Default: @@ -403,9 +351,6 @@ namespace API.Services Overwrite = false }); } - - // using ZipArchive archive = ZipFile.OpenRead(archivePath); - // archive.ExtractToDirectory(extractPath, true); } private void ExtractArchiveEntries(ZipArchive archive, string extractPath) @@ -431,7 +376,7 @@ namespace API.Services /// public void ExtractArchive(string archivePath, string extractPath) { - if (!File.Exists(archivePath)) return; + if (!IsValidArchive(archivePath)) return; if (Directory.Exists(extractPath)) return; @@ -439,7 +384,7 @@ namespace API.Services try { - var libraryHandler = Archive.Archive.CanOpen(archivePath); + var libraryHandler = CanOpen(archivePath); switch (libraryHandler) { case ArchiveLibrary.Default: @@ -473,4 +418,5 @@ namespace API.Services _logger.LogDebug("Extracted archive to {ExtractPath} in {ElapsedMilliseconds} milliseconds", extractPath, sw.ElapsedMilliseconds); } } + } \ No newline at end of file diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 89025cb92..7ba691bc9 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -97,6 +97,8 @@ namespace API.Services /// public static void ClearAndDeleteDirectory(string directoryPath) { + if (!Directory.Exists(directoryPath)) return; + DirectoryInfo di = new DirectoryInfo(directoryPath); ClearDirectory(directoryPath);