Implemented the ability to flatten directories, esp useful with nested folders in archives.

This commit is contained in:
Joseph Milazzo 2021-01-14 10:02:56 -06:00
parent 56e8a0059e
commit 7f404a0ce9
7 changed files with 91 additions and 22 deletions

View File

@ -19,8 +19,7 @@ namespace API.Tests
[InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip", "1")] [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip", "1")]
public void ParseVolumeTest(string filename, string expected) public void ParseVolumeTest(string filename, string expected)
{ {
var result = ParseVolume(filename); Assert.Equal(expected, ParseVolume(filename));
Assert.Equal(expected, result);
} }
[Theory] [Theory]
@ -36,8 +35,7 @@ namespace API.Tests
[InlineData("Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)", "Akame ga KILL! ZERO")] [InlineData("Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)", "Akame ga KILL! ZERO")]
public void ParseSeriesTest(string filename, string expected) public void ParseSeriesTest(string filename, string expected)
{ {
var result = ParseSeries(filename); Assert.Equal(expected, ParseSeries(filename));
Assert.Equal(expected, result);
} }
[Theory] [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")] [InlineData("Adding volume 1 with File: Ana Satsujin Vol. 1 Ch. 5 - Manga Box (gb).cbz", "5")]
public void ParseChaptersTest(string filename, string expected) public void ParseChaptersTest(string filename, string expected)
{ {
var result = ParseChapter(filename); Assert.Equal(expected, ParseChapter(filename));
Assert.Equal(expected, result);
} }
@ -91,6 +88,7 @@ namespace API.Tests
[InlineData("test.cbr", true)] [InlineData("test.cbr", true)]
[InlineData("test.zip", true)] [InlineData("test.zip", true)]
[InlineData("test.rar", true)] [InlineData("test.rar", true)]
[InlineData("test.rar.!qb", false)]
public void IsArchiveTest(string input, bool expected) public void IsArchiveTest(string input, bool expected)
{ {
Assert.Equal(expected, IsArchive(input)); Assert.Equal(expected, IsArchive(input));

View File

@ -30,7 +30,7 @@ namespace API.Comparators
{ {
bool c1 = Char.IsDigit(s1, i1); bool c1 = Char.IsDigit(s1, i1);
bool c2 = Char.IsDigit(s2, i2); bool c2 = Char.IsDigit(s2, i2);
var r = 0; // temp result int r; // temp result
if(!c1 && !c2) if(!c1 && !c2)
{ {
bool letter1 = Char.IsLetter(s1, i1); bool letter1 = Char.IsLetter(s1, i1);

View File

@ -1,7 +1,5 @@
using System.Linq; using System.Threading.Tasks;
using System.Threading.Tasks;
using API.DTOs; using API.DTOs;
using API.Entities;
using API.Interfaces; using API.Interfaces;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -1,11 +1,65 @@
namespace API.Extensions using System;
using System.IO;
namespace API.Extensions
{ {
public static class DirectoryInfoExtensions 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(FileInfo file in directory.EnumerateFiles()) file.Delete();
foreach(System.IO.DirectoryInfo subDirectory in directory.EnumerateDirectories()) subDirectory.Delete(true); foreach(DirectoryInfo subDirectory in directory.EnumerateDirectories()) subDirectory.Delete(true);
}
/// <summary>
/// Flattens all files in subfolders to the passed directory recursively.
///
///
/// foo<para />
/// ├── 1.txt<para />
/// ├── 2.txt<para />
/// ├── 3.txt<para />
/// ├── 4.txt<para />
/// └── bar<para />
/// ├── 1.txt<para />
/// ├── 2.txt<para />
/// └── 5.txt<para />
///
/// becomes:<para />
/// foo<para />
/// ├── 1.txt<para />
/// ├── 2.txt<para />
/// ├── 3.txt<para />
/// ├── 4.txt<para />
/// ├── bar_1.txt<para />
/// ├── bar_2.txt<para />
/// └── bar_5.txt<para />
/// </summary>
/// <param name="directory"></param>
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);
}
} }
} }
} }

View File

@ -4,7 +4,6 @@ using API.DTOs;
namespace API.Interfaces namespace API.Interfaces
{ {
// TODO: Refactor this into IDiskService to encapsulate all disk based IO
public interface IDirectoryService public interface IDirectoryService
{ {
/// <summary> /// <summary>

View File

@ -42,7 +42,7 @@ namespace API.Services
foreach (var file in volume.Files) foreach (var file in volume.Files)
{ {
var extractPath = GetVolumeCachePath(volumeId, file); var extractPath = GetVolumeCachePath(volumeId, file);
_directoryService.ExtractArchive(file.FilePath, extractPath); _directoryService.ExtractArchive(file.FilePath, extractPath);
} }

View File

@ -137,6 +137,7 @@ namespace API.Services
{ {
FilePath = info.FullFilePath, FilePath = info.FullFilePath,
Chapter = chapter, Chapter = chapter,
Format = info.Format,
NumberOfPages = GetNumberOfPagesFromArchive(info.FullFilePath) NumberOfPages = GetNumberOfPagesFromArchive(info.FullFilePath)
}; };
} }
@ -284,7 +285,13 @@ namespace API.Services
return Path.Join(Directory.GetCurrentDirectory(), $"../cache/{volumeId}/"); return Path.Join(Directory.GetCurrentDirectory(), $"../cache/{volumeId}/");
} }
public string ExtractArchive(string archivePath, int volumeId) /// <summary>
/// TODO: Delete this method
/// </summary>
/// <param name="archivePath"></param>
/// <param name="volumeId"></param>
/// <returns></returns>
private string ExtractArchive(string archivePath, int volumeId)
{ {
if (!File.Exists(archivePath) || !Parser.Parser.IsArchive(archivePath)) if (!File.Exists(archivePath) || !Parser.Parser.IsArchive(archivePath))
{ {
@ -302,10 +309,18 @@ namespace API.Services
using ZipArchive archive = ZipFile.OpenRead(archivePath); 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); archive.ExtractToDirectory(extractPath);
_logger.LogInformation($"Extracting archive to {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; return extractPath;
} }
@ -325,12 +340,18 @@ namespace API.Services
} }
using ZipArchive archive = ZipFile.OpenRead(archivePath); using ZipArchive archive = ZipFile.OpenRead(archivePath);
// TODO: Throw error if we couldn't extract
if (!archive.HasFiles()) return ""; var needsFlattening = archive.Entries.Count > 0 && !Path.HasExtension(archive.Entries.ElementAt(0).FullName);
if (!archive.HasFiles() && !needsFlattening) return "";
archive.ExtractToDirectory(extractPath); archive.ExtractToDirectory(extractPath);
_logger.LogDebug($"Extracting archive to {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; return extractPath;
} }
@ -343,7 +364,6 @@ namespace API.Services
} }
using ZipArchive archive = ZipFile.OpenRead(archivePath); using ZipArchive archive = ZipFile.OpenRead(archivePath);
Console.WriteLine();
return archive.Entries.Count(e => Parser.Parser.IsImage(e.FullName)); return archive.Entries.Count(e => Parser.Parser.IsImage(e.FullName));
} }