diff --git a/API.Tests/ParserTest.cs b/API.Tests/ParserTest.cs index 392cbd15d..6e126c2d8 100644 --- a/API.Tests/ParserTest.cs +++ b/API.Tests/ParserTest.cs @@ -303,6 +303,7 @@ namespace API.Tests [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "1")] [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "2")] + [InlineData("Superman v1 024 (09-10 1943)", "1")] public void ParseComicVolumeTest(string filename, string expected) { Assert.Equal(expected, ParseComicVolume(filename)); @@ -322,6 +323,7 @@ namespace API.Tests [InlineData("Babe 01", "0")] [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "0")] [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] + [InlineData("Superman v1 024 (09-10 1943)", "24")] public void ParseComicChapterTest(string filename, string expected) { Assert.Equal(expected, ParseComicChapter(filename)); @@ -336,6 +338,22 @@ namespace API.Tests { Assert.Equal(expected, IsImage(filename)); } + + [Theory] + [InlineData("C:/", "C:/Love Hina/Love Hina - Special.cbz", "Love Hina")] + [InlineData("C:/", "C:/Love Hina/Specials/Ani-Hina Art Collection.cbz", "Love Hina")] + [InlineData("C:/", "C:/Mujaki no Rakuen Something/Mujaki no Rakuen Vol12 ch76.cbz", "Mujaki no Rakuen")] + public void FallbackTest(string rootDir, string inputPath, string expectedSeries) + { + var actual = Parse(inputPath, rootDir); + if (actual == null) + { + Assert.NotNull(actual); + return; + } + + Assert.Equal(expectedSeries, actual.Series); + } [Fact] diff --git a/API.Tests/Services/DirectoryServiceTests.cs b/API.Tests/Services/DirectoryServiceTests.cs index 39ff717c5..7c21ae927 100644 --- a/API.Tests/Services/DirectoryServiceTests.cs +++ b/API.Tests/Services/DirectoryServiceTests.cs @@ -74,5 +74,17 @@ namespace API.Tests.Services Assert.DoesNotContain(dirs, s => s.Contains("regex")); } + + [Theory] + [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake/", "Omake,Specials,Love Hina")] + [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake", "Omake,Specials,Love Hina")] + [InlineData("C:/Manga", "C:/Manga/Love Hina/Specials/Omake/", "Omake,Specials,Love Hina")] + [InlineData("C:/Manga", @"C:\Manga\Love Hina\Specials\Omake\", "Omake,Specials,Love Hina")] + [InlineData(@"/manga/", @"/manga/Love Hina/Specials/Omake/", "Omake,Specials,Love Hina")] + public void GetFoldersTillRoot_Test(string rootPath, string fullpath, string expectedArray) + { + var expected = expectedArray.Split(","); + Assert.Equal(expected, DirectoryService.GetFoldersTillRoot(rootPath, fullpath)); + } } } \ No newline at end of file diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 1a9ac444b..b064a536e 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using API.Entities.Enums; +using API.Services; namespace API.Parser { @@ -343,9 +344,7 @@ namespace API.Parser public static ParserInfo Parse(string filePath, string rootPath, LibraryType type = LibraryType.Manga) { var fileName = Path.GetFileName(filePath); - var directoryName = (new FileInfo(filePath)).Directory?.Name; - var rootName = (new DirectoryInfo(rootPath)).Name; - + var ret = new ParserInfo() { Chapters = type == LibraryType.Manga ? ParseChapter(fileName) : ParseComicChapter(fileName), @@ -355,11 +354,32 @@ namespace API.Parser Format = ParseFormat(filePath), FullFilePath = filePath }; - - if (ret.Series == string.Empty && directoryName != null && directoryName != rootName) + + if (ret.Series == string.Empty) { - ret.Series = ParseSeries(directoryName); - if (ret.Series == string.Empty) ret.Series = CleanTitle(directoryName); + // Try to parse information out of each folder all the way to rootPath + var fallbackFolders = DirectoryService.GetFoldersTillRoot(rootPath, Path.GetDirectoryName(filePath)).ToList(); + for (var i = 0; i < fallbackFolders.Count; i++) + { + var folder = fallbackFolders[i]; + if (!string.IsNullOrEmpty(ParseMangaSpecial(folder))) continue; + if (ParseVolume(folder) != "0" || ParseChapter(folder) != "0") continue; + + var series = ParseSeries(folder); + + if ((string.IsNullOrEmpty(series) && i == fallbackFolders.Count - 1)) + { + ret.Series = CleanTitle(folder); + break; + } + + if (!string.IsNullOrEmpty(series)) + { + ret.Series = series; + break; + } + } + } var edition = ParseEdition(fileName); @@ -562,7 +582,7 @@ namespace API.Parser { if (match.Success) { - title = title.Replace(match.Value, ""); + title = title.Replace(match.Value, "").Trim(); } } } @@ -574,7 +594,7 @@ namespace API.Parser { if (match.Success) { - title = title.Replace(match.Value, ""); + title = title.Replace(match.Value, "").Trim(); } } } @@ -591,7 +611,7 @@ namespace API.Parser { if (match.Success) { - title = title.Replace(match.Value, ""); + title = title.Replace(match.Value, "").Trim(); } } } diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 7ba691bc9..69a1b17dd 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -40,6 +40,40 @@ namespace API.Services reSearchPattern.IsMatch(Path.GetExtension(file))); } + /// + /// Returns a list of folders from end of fullPath to rootPath. + /// + /// Example) (C:/Manga/, C:/Manga/Love Hina/Specials/Omake/) returns [Omake, Specials, Love Hina] + /// + /// + /// + /// + public static IEnumerable GetFoldersTillRoot(string rootPath, string fullPath) + { + var separator = Path.AltDirectorySeparatorChar; + if (fullPath.Contains(Path.DirectorySeparatorChar)) + { + fullPath = fullPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + } + + if (rootPath.Contains(Path.DirectorySeparatorChar)) + { + rootPath = rootPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + } + + var path = fullPath.EndsWith(separator) ? fullPath.Substring(0, fullPath.Length - 1) : fullPath; + var root = rootPath.EndsWith(separator) ? rootPath.Substring(0, rootPath.Length - 1) : rootPath; + var paths = new List(); + while (Path.GetDirectoryName(path) != Path.GetDirectoryName(root)) + { + var folder = new DirectoryInfo(path).Name; + paths.Add(folder); + path = path.Replace(separator + folder, string.Empty); + } + + return paths; + } + public bool Exists(string directory) { var di = new DirectoryInfo(directory);