diff --git a/API.Tests/ParserTest.cs b/API.Tests/ParserTest.cs index eaebc727a..d551c6393 100644 --- a/API.Tests/ParserTest.cs +++ b/API.Tests/ParserTest.cs @@ -19,8 +19,7 @@ namespace API.Tests [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip", "1")] public void ParseVolumeTest(string filename, string expected) { - var result = ParseVolume(filename); - Assert.Equal(expected, result); + Assert.Equal(expected, ParseVolume(filename)); } [Theory] @@ -36,8 +35,7 @@ namespace API.Tests [InlineData("Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)", "Akame ga KILL! ZERO")] public void ParseSeriesTest(string filename, string expected) { - var result = ParseSeries(filename); - Assert.Equal(expected, result); + Assert.Equal(expected, ParseSeries(filename)); } [Theory] @@ -53,8 +51,7 @@ namespace API.Tests [InlineData("Adding volume 1 with File: Ana Satsujin Vol. 1 Ch. 5 - Manga Box (gb).cbz", "5")] public void ParseChaptersTest(string filename, string expected) { - var result = ParseChapter(filename); - Assert.Equal(expected, result); + Assert.Equal(expected, ParseChapter(filename)); } @@ -91,6 +88,7 @@ namespace API.Tests [InlineData("test.cbr", true)] [InlineData("test.zip", true)] [InlineData("test.rar", true)] + [InlineData("test.rar.!qb", false)] public void IsArchiveTest(string input, bool expected) { Assert.Equal(expected, IsArchive(input)); diff --git a/API/Comparators/StringLogicalComparer.cs b/API/Comparators/StringLogicalComparer.cs index 957921c4c..f6a8c1249 100644 --- a/API/Comparators/StringLogicalComparer.cs +++ b/API/Comparators/StringLogicalComparer.cs @@ -30,7 +30,7 @@ namespace API.Comparators { bool c1 = Char.IsDigit(s1, i1); bool c2 = Char.IsDigit(s2, i2); - var r = 0; // temp result + int r; // temp result if(!c1 && !c2) { bool letter1 = Char.IsLetter(s1, i1); diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index b19daddb5..17a5d753d 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -1,7 +1,5 @@ -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; using API.DTOs; -using API.Entities; using API.Interfaces; using Microsoft.AspNetCore.Mvc; diff --git a/API/Extensions/DirectoryInfoExtensions.cs b/API/Extensions/DirectoryInfoExtensions.cs index ab5766962..257b7c045 100644 --- a/API/Extensions/DirectoryInfoExtensions.cs +++ b/API/Extensions/DirectoryInfoExtensions.cs @@ -1,11 +1,65 @@ -namespace API.Extensions +using System; +using System.IO; + +namespace API.Extensions { public static class DirectoryInfoExtensions { - public static void Empty(this System.IO.DirectoryInfo directory) + public static void Empty(this DirectoryInfo directory) { - foreach(System.IO.FileInfo file in directory.EnumerateFiles()) file.Delete(); - foreach(System.IO.DirectoryInfo subDirectory in directory.EnumerateDirectories()) subDirectory.Delete(true); + foreach(FileInfo file in directory.EnumerateFiles()) file.Delete(); + foreach(DirectoryInfo subDirectory in directory.EnumerateDirectories()) subDirectory.Delete(true); + } + + /// + /// Flattens all files in subfolders to the passed directory recursively. + /// + /// + /// foo + /// ├── 1.txt + /// ├── 2.txt + /// ├── 3.txt + /// ├── 4.txt + /// └── bar + /// ├── 1.txt + /// ├── 2.txt + /// └── 5.txt + /// + /// becomes: + /// foo + /// ├── 1.txt + /// ├── 2.txt + /// ├── 3.txt + /// ├── 4.txt + /// ├── bar_1.txt + /// ├── bar_2.txt + /// └── bar_5.txt + /// + /// + public static void Flatten(this DirectoryInfo directory) + { + FlattenDirectory(directory, directory); + } + + private static void FlattenDirectory(DirectoryInfo root, DirectoryInfo directory) + { + if (!root.FullName.Equals(directory.FullName)) // I might be able to replace this with root === directory + { + foreach (var file in directory.EnumerateFiles()) + { + if (file.Directory == null) continue; + var newName = $"{file.Directory.Name}_{file.Name}"; + var newPath = Path.Join(root.FullName, newName); + Console.WriteLine($"Renaming/Moving file to: {newPath}"); + file.MoveTo(newPath); + + } + } + + foreach (var subDirectory in directory.EnumerateDirectories()) + { + FlattenDirectory(root, subDirectory); + } } } } \ No newline at end of file diff --git a/API/Interfaces/IDirectoryService.cs b/API/Interfaces/IDirectoryService.cs index beeb7cfd0..9592292c4 100644 --- a/API/Interfaces/IDirectoryService.cs +++ b/API/Interfaces/IDirectoryService.cs @@ -4,7 +4,6 @@ using API.DTOs; namespace API.Interfaces { - // TODO: Refactor this into IDiskService to encapsulate all disk based IO public interface IDirectoryService { /// diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index 1a78f1293..a6372bb1f 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -42,7 +42,7 @@ namespace API.Services foreach (var file in volume.Files) { var extractPath = GetVolumeCachePath(volumeId, file); - + _directoryService.ExtractArchive(file.FilePath, extractPath); } diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 7081d1b49..02358862c 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -137,6 +137,7 @@ namespace API.Services { FilePath = info.FullFilePath, Chapter = chapter, + Format = info.Format, NumberOfPages = GetNumberOfPagesFromArchive(info.FullFilePath) }; } @@ -284,7 +285,13 @@ namespace API.Services return Path.Join(Directory.GetCurrentDirectory(), $"../cache/{volumeId}/"); } - public string ExtractArchive(string archivePath, int volumeId) + /// + /// TODO: Delete this method + /// + /// + /// + /// + private string ExtractArchive(string archivePath, int volumeId) { if (!File.Exists(archivePath) || !Parser.Parser.IsArchive(archivePath)) { @@ -302,10 +309,18 @@ namespace API.Services using ZipArchive archive = ZipFile.OpenRead(archivePath); - if (!archive.HasFiles()) return ""; - + // TODO: Throw error if we couldn't extract + var needsFlattening = archive.Entries.Count > 0 && !Path.HasExtension(archive.Entries.ElementAt(0).FullName); + if (!archive.HasFiles() && !needsFlattening) return ""; + archive.ExtractToDirectory(extractPath); _logger.LogInformation($"Extracting archive to {extractPath}"); + + if (needsFlattening) + { + _logger.LogInformation("Extracted archive is nested in root folder, flattening..."); + new DirectoryInfo(extractPath).Flatten(); + } return extractPath; } @@ -325,12 +340,18 @@ namespace API.Services } using ZipArchive archive = ZipFile.OpenRead(archivePath); - - if (!archive.HasFiles()) return ""; + // TODO: Throw error if we couldn't extract + var needsFlattening = archive.Entries.Count > 0 && !Path.HasExtension(archive.Entries.ElementAt(0).FullName); + if (!archive.HasFiles() && !needsFlattening) return ""; archive.ExtractToDirectory(extractPath); _logger.LogDebug($"Extracting archive to {extractPath}"); + if (!needsFlattening) return extractPath; + + _logger.LogInformation("Extracted archive is nested in root folder, flattening..."); + new DirectoryInfo(extractPath).Flatten(); + return extractPath; } @@ -343,7 +364,6 @@ namespace API.Services } using ZipArchive archive = ZipFile.OpenRead(archivePath); - Console.WriteLine(); return archive.Entries.Count(e => Parser.Parser.IsImage(e.FullName)); }