Special Marker Changes (#306)

* SP# is now a way to force the file to be a special rather than pushing it into a Specials folder.

* Made it so if there is a Special (for any Parse call), volume and chapters will be ignored.

* Fixed a unit test missing Theory and fixed a regex case
This commit is contained in:
Joseph Milazzo 2021-06-14 21:12:37 -05:00 committed by GitHub
parent 46b60405b1
commit 584348c6ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 18 deletions

View File

@ -145,6 +145,7 @@ namespace API.Tests.Parser
[InlineData("X-Men v1 #201 (September 2007).cbz", "X-Men")]
[InlineData("Kodoja #001 (March 2016)", "Kodoja")]
[InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "Boku No Kokoro No Yabai Yatsu")]
[InlineData("Kiss x Sis - Ch.36 - A Cold Home Visit.cbz", "Kiss x Sis")]
public void ParseSeriesTest(string filename, string expected)
{
Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename));
@ -242,8 +243,8 @@ namespace API.Tests.Parser
[InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", true)]
[InlineData("A Town Where You Live - Bonus Chapter.zip", true)]
[InlineData("Yuki Merry - 4-Komga Anthology", false)]
[InlineData("Beastars - SP01", true)]
[InlineData("Beastars SP01", true)]
[InlineData("Beastars - SP01", false)]
[InlineData("Beastars SP01", false)]
public void ParseMangaSpecialTest(string input, bool expected)
{
Assert.Equal(expected, !string.IsNullOrEmpty(API.Parser.Parser.ParseMangaSpecial(input)));

View File

@ -6,6 +6,16 @@ namespace API.Tests.Parser
public class ParserTests
{
[Theory]
[InlineData("Beastars - SP01", true)]
[InlineData("Beastars SP01", true)]
[InlineData("Beastars Special 01", false)]
[InlineData("Beastars Extra 01", false)]
public void HasSpecialTest(string input, bool expected)
{
Assert.Equal(expected, HasSpecialMarker(input));
}
[Theory]
[InlineData("0001", "1")]
[InlineData("1", "1")]

View File

@ -9,9 +9,12 @@ namespace API.Parser
{
public static class Parser
{
public static readonly string ArchiveFileExtensions = @"\.cbz|\.zip|\.rar|\.cbr|\.tar.gz|\.7zip|\.7z|.cb7";
public static readonly string BookFileExtensions = @"\.epub";
public static readonly string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg)";
public const string DefaultChapter = "0";
public const string DefaultVolume = "0";
public const string ArchiveFileExtensions = @"\.cbz|\.zip|\.rar|\.cbr|\.tar.gz|\.7zip|\.7z|.cb7";
public const string BookFileExtensions = @"\.epub";
public const string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg)";
public static readonly Regex FontSrcUrlRegex = new Regex("(src:url\\(\"?'?)([a-z0-9/\\._]+)(\"?'?\\))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static readonly Regex CssImportUrlRegex = new Regex("(@import\\s[\"|'])(?<Filename>[\\w\\d/\\._-]+)([\"|'];?)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
@ -92,7 +95,7 @@ namespace API.Parser
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)
new Regex(
@"(?<Series>.*) (\b|_|-)v",
@"(?<Series>.*) (\b|_|-)(v|ch\.?|c)\d+",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip must be before [Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip
// due to duplicate version identifiers in file.
@ -374,12 +377,14 @@ namespace API.Parser
new Regex(
@"(?<Special>Specials?|OneShot|One\-Shot|Omake|Extra( Chapter)?|Art Collection|Side( |_)Stories|Bonus)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// If SP\d+ is in the filename, we force treat it as a special regardless if volume or chapter might have been found.
new Regex(
@"(?<Special>SP\d+)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
};
// If SP\d+ is in the filename, we force treat it as a special regardless if volume or chapter might have been found.
private static readonly Regex SpecialMarkerRegex = new Regex(
@"(?<Special>SP\d+)",
RegexOptions.IgnoreCase | RegexOptions.Compiled
);
/// <summary>
/// Parses information out of a file path. Will fallback to using directory name if Series couldn't be parsed
@ -428,7 +433,7 @@ namespace API.Parser
{
var folder = fallbackFolders[i];
if (!string.IsNullOrEmpty(ParseMangaSpecial(folder))) continue;
if (ParseVolume(folder) != "0" || ParseChapter(folder) != "0") continue;
if (ParseVolume(folder) != DefaultVolume || ParseChapter(folder) != DefaultChapter) continue;
var series = ParseSeries(folder);
@ -457,11 +462,18 @@ namespace API.Parser
var isSpecial = ParseMangaSpecial(fileName);
// We must ensure that we can only parse a special out. As some files will have v20 c171-180+Omake and that
// could cause a problem as Omake is a special term, but there is valid volume/chapter information.
if (ret.Chapters == "0" && ret.Volumes == "0" && !string.IsNullOrEmpty(isSpecial))
if (ret.Chapters == DefaultChapter && ret.Volumes == DefaultVolume && !string.IsNullOrEmpty(isSpecial))
{
ret.IsSpecial = true;
}
if (HasSpecialMarker(fileName))
{
ret.IsSpecial = true;
ret.Chapters = DefaultChapter;
ret.Volumes = DefaultVolume;
}
return ret.Series == string.Empty ? null : ret;
@ -495,6 +507,25 @@ namespace API.Parser
return string.Empty;
}
/// <summary>
/// If the file has SP marker.
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static bool HasSpecialMarker(string filePath)
{
var matches = SpecialMarkerRegex.Matches(filePath);
foreach (Match match in matches)
{
if (match.Groups["Special"].Success && match.Groups["Special"].Value != string.Empty)
{
return true;
}
}
return false;
}
public static string ParseMangaSpecial(string filePath)
{
foreach (var regex in MangaSpecialRegex)
@ -564,7 +595,7 @@ namespace API.Parser
}
}
return "0";
return DefaultVolume;
}
public static string ParseComicVolume(string filename)
@ -586,7 +617,7 @@ namespace API.Parser
}
}
return "0";
return DefaultVolume;
}
public static string ParseChapter(string filename)
@ -614,7 +645,7 @@ namespace API.Parser
}
}
return "0";
return DefaultChapter;
}
private static string AddChapterPart(string value)
@ -652,7 +683,7 @@ namespace API.Parser
}
}
return "0";
return DefaultChapter;
}
private static string RemoveEditionTagHolders(string title)

View File

@ -3,7 +3,7 @@
namespace API.Parser
{
/// <summary>
/// This represents a single file
/// This represents all parsed information from a single file
/// </summary>
public class ParserInfo
{

View File

@ -466,7 +466,7 @@ namespace API.Services.Tasks
return;
}
if (type == LibraryType.Book && Parser.Parser.IsEpub(path) && Parser.Parser.ParseVolume(info.Series) != "0")
if (type == LibraryType.Book && Parser.Parser.IsEpub(path) && Parser.Parser.ParseVolume(info.Series) != Parser.Parser.DefaultVolume)
{
info = Parser.Parser.Parse(path, rootPath, type);
var info2 = _bookService.ParseInfo(path);