mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
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:
parent
46b60405b1
commit
584348c6ad
@ -145,6 +145,7 @@ namespace API.Tests.Parser
|
|||||||
[InlineData("X-Men v1 #201 (September 2007).cbz", "X-Men")]
|
[InlineData("X-Men v1 #201 (September 2007).cbz", "X-Men")]
|
||||||
[InlineData("Kodoja #001 (March 2016)", "Kodoja")]
|
[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("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)
|
public void ParseSeriesTest(string filename, string expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename));
|
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("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", true)]
|
||||||
[InlineData("A Town Where You Live - Bonus Chapter.zip", true)]
|
[InlineData("A Town Where You Live - Bonus Chapter.zip", true)]
|
||||||
[InlineData("Yuki Merry - 4-Komga Anthology", false)]
|
[InlineData("Yuki Merry - 4-Komga Anthology", false)]
|
||||||
[InlineData("Beastars - SP01", true)]
|
[InlineData("Beastars - SP01", false)]
|
||||||
[InlineData("Beastars SP01", true)]
|
[InlineData("Beastars SP01", false)]
|
||||||
public void ParseMangaSpecialTest(string input, bool expected)
|
public void ParseMangaSpecialTest(string input, bool expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, !string.IsNullOrEmpty(API.Parser.Parser.ParseMangaSpecial(input)));
|
Assert.Equal(expected, !string.IsNullOrEmpty(API.Parser.Parser.ParseMangaSpecial(input)));
|
||||||
|
@ -5,6 +5,16 @@ namespace API.Tests.Parser
|
|||||||
{
|
{
|
||||||
public class ParserTests
|
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]
|
[Theory]
|
||||||
[InlineData("0001", "1")]
|
[InlineData("0001", "1")]
|
||||||
|
@ -9,9 +9,12 @@ namespace API.Parser
|
|||||||
{
|
{
|
||||||
public static class Parser
|
public static class Parser
|
||||||
{
|
{
|
||||||
public static readonly string ArchiveFileExtensions = @"\.cbz|\.zip|\.rar|\.cbr|\.tar.gz|\.7zip|\.7z|.cb7";
|
public const string DefaultChapter = "0";
|
||||||
public static readonly string BookFileExtensions = @"\.epub";
|
public const string DefaultVolume = "0";
|
||||||
public static readonly string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg)";
|
|
||||||
|
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 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);
|
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),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
// Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)
|
// Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)
|
||||||
new Regex(
|
new Regex(
|
||||||
@"(?<Series>.*) (\b|_|-)v",
|
@"(?<Series>.*) (\b|_|-)(v|ch\.?|c)\d+",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
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
|
//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.
|
// due to duplicate version identifiers in file.
|
||||||
@ -374,12 +377,14 @@ namespace API.Parser
|
|||||||
new Regex(
|
new Regex(
|
||||||
@"(?<Special>Specials?|OneShot|One\-Shot|Omake|Extra( Chapter)?|Art Collection|Side( |_)Stories|Bonus)",
|
@"(?<Special>Specials?|OneShot|One\-Shot|Omake|Extra( Chapter)?|Art Collection|Side( |_)Stories|Bonus)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
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>
|
/// <summary>
|
||||||
/// Parses information out of a file path. Will fallback to using directory name if Series couldn't be parsed
|
/// 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];
|
var folder = fallbackFolders[i];
|
||||||
if (!string.IsNullOrEmpty(ParseMangaSpecial(folder))) continue;
|
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);
|
var series = ParseSeries(folder);
|
||||||
|
|
||||||
@ -457,10 +462,17 @@ namespace API.Parser
|
|||||||
var isSpecial = ParseMangaSpecial(fileName);
|
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
|
// 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.
|
// 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;
|
ret.IsSpecial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasSpecialMarker(fileName))
|
||||||
|
{
|
||||||
|
ret.IsSpecial = true;
|
||||||
|
ret.Chapters = DefaultChapter;
|
||||||
|
ret.Volumes = DefaultVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -495,6 +507,25 @@ namespace API.Parser
|
|||||||
return string.Empty;
|
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)
|
public static string ParseMangaSpecial(string filePath)
|
||||||
{
|
{
|
||||||
foreach (var regex in MangaSpecialRegex)
|
foreach (var regex in MangaSpecialRegex)
|
||||||
@ -564,7 +595,7 @@ namespace API.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0";
|
return DefaultVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ParseComicVolume(string filename)
|
public static string ParseComicVolume(string filename)
|
||||||
@ -586,7 +617,7 @@ namespace API.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0";
|
return DefaultVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ParseChapter(string filename)
|
public static string ParseChapter(string filename)
|
||||||
@ -614,7 +645,7 @@ namespace API.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0";
|
return DefaultChapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string AddChapterPart(string value)
|
private static string AddChapterPart(string value)
|
||||||
@ -652,7 +683,7 @@ namespace API.Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0";
|
return DefaultChapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string RemoveEditionTagHolders(string title)
|
private static string RemoveEditionTagHolders(string title)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace API.Parser
|
namespace API.Parser
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This represents a single file
|
/// This represents all parsed information from a single file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ParserInfo
|
public class ParserInfo
|
||||||
{
|
{
|
||||||
|
@ -466,7 +466,7 @@ namespace API.Services.Tasks
|
|||||||
return;
|
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);
|
info = Parser.Parser.Parse(path, rootPath, type);
|
||||||
var info2 = _bookService.ParseInfo(path);
|
var info2 = _bookService.ParseInfo(path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user