diff --git a/API/Data/Metadata/ComicInfo.cs b/API/Data/Metadata/ComicInfo.cs
index 0c236fd58..167638a01 100644
--- a/API/Data/Metadata/ComicInfo.cs
+++ b/API/Data/Metadata/ComicInfo.cs
@@ -62,6 +62,11 @@ namespace API.Data.Metadata
/// Represents the sort order for the title
///
public string TitleSort { get; set; } = string.Empty;
+ ///
+ /// This comes from ComicInfo and is free form text. We use this to validate against a set of tags and mark a file as
+ /// special.
+ ///
+ public string Format { get; set; } = string.Empty;
///
/// The translator, can be comma separated. This is part of ComicInfo.xml draft v2.1
diff --git a/API/Parser/DefaultParser.cs b/API/Parser/DefaultParser.cs
index 9477fa072..161a1533b 100644
--- a/API/Parser/DefaultParser.cs
+++ b/API/Parser/DefaultParser.cs
@@ -85,7 +85,7 @@ public class DefaultParser
if (ret.Chapters == Parser.DefaultChapter && ret.Volumes == Parser.DefaultVolume && !string.IsNullOrEmpty(isSpecial))
{
ret.IsSpecial = true;
- ParseFromFallbackFolders(filePath, rootPath, type, ref ret);
+ ParseFromFallbackFolders(filePath, rootPath, type, ref ret); // NOTE: This can cause some complications, we should try to be a bit less aggressive to fallback to folder
}
// If we are a special with marker, we need to ensure we use the correct series name. we can do this by falling back to Folder name
diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs
index 3edcf5d7c..76b517adf 100644
--- a/API/Parser/Parser.cs
+++ b/API/Parser/Parser.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -512,6 +513,11 @@ namespace API.Parser
MatchOptions, RegexTimeout
);
+ private static readonly ImmutableArray FormatTagSpecialKeyowrds = ImmutableArray.Create(
+ "Special", "Reference", "Director's Cut", "Box Set", "Box-Set", "Annual", "Anthology", "Epilogue",
+ "One Shot", "One-Shot", "Prologue", "TPB", "Trade Paper Back", "Omnibus", "Compendium", "Absolute", "Graphic Novel",
+ "GN", "FCBD");
+
public static MangaFormat ParseFormat(string filePath)
{
if (IsArchive(filePath)) return MangaFormat.Archive;
@@ -1034,5 +1040,15 @@ namespace API.Parser
{
return path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}
+
+ ///
+ /// Checks against a set of strings to validate if a ComicInfo.Format should receive special treatment
+ ///
+ ///
+ ///
+ public static bool HasComicInfoSpecial(string comicInfoFormat)
+ {
+ return FormatTagSpecialKeyowrds.Contains(comicInfoFormat);
+ }
}
}
diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs
index 92c0d6e1d..16dd6c932 100644
--- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs
+++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs
@@ -122,6 +122,13 @@ namespace API.Services.Tasks.Scanner
info.SeriesSort = info.ComicInfo.TitleSort.Trim();
}
+ if (!string.IsNullOrEmpty(info.ComicInfo.Format) && Parser.Parser.HasComicInfoSpecial(info.ComicInfo.Format))
+ {
+ info.IsSpecial = true;
+ info.Chapters = Parser.Parser.DefaultChapter;
+ info.Volumes = Parser.Parser.DefaultVolume;
+ }
+
if (!string.IsNullOrEmpty(info.ComicInfo.SeriesSort))
{
info.SeriesSort = info.ComicInfo.SeriesSort.Trim();