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();