diff --git a/ComicNodes/Comics/CreateComicInfo.cs b/ComicNodes/Comics/CreateComicInfo.cs index 6ad07377..7d3fca78 100644 --- a/ComicNodes/Comics/CreateComicInfo.cs +++ b/ComicNodes/Comics/CreateComicInfo.cs @@ -183,16 +183,23 @@ public class CreateComicInfo : Node { if (issueDigits > 0) { - // Pad the number with leading zeros based on the specified number of digits - string paddedNumber = info.Number.Value.ToString().PadLeft(issueDigits, '0'); - - // Add the padded number to the name - name += $" - #{paddedNumber}"; - - // Optionally add information about the count - if (info.Count > 0) + if (info.Volume == "Annual") { - name += $" (of {info.Count})"; + name += " - Annual " + info.Number; + } + else + { + // Pad the number with leading zeros based on the specified number of digits + string paddedNumber = info.Number.Value.ToString().PadLeft(issueDigits, '0'); + + // Add the padded number to the name + name += $" - #{paddedNumber}"; + + // Optionally add information about the count + if (info.Count > 0) + { + name += $" (of {info.Count})"; + } } } else @@ -226,10 +233,12 @@ public class CreateComicInfo : Node info.Series = FileHelper.GetDirectoryName(libraryFile); var yearMatch = Regex.Match(info.Series, @"\((?(19|20)\d{2})\)"); + int? year = null; if (yearMatch.Success) { - info.Volume = yearMatch.Groups["year"].Value; + year = int.Parse(yearMatch.Groups["year"].Value); + info.Volume = year.ToString(); // info.Series = Regex.Replace(info.Series, @"\((19|20)\d{2}\)", "").Trim(); } @@ -239,7 +248,8 @@ public class CreateComicInfo : Node string shortname = FileHelper.GetShortFileName(libraryFile); info.Tags = GetTags(ref shortname); shortname = shortname[..shortname.LastIndexOf('.')]; - (shortname, _) = ExtractYear(shortname); + (shortname, int? year2) = ExtractYear(shortname); + year ??= year2; // Title - #number (of #) - Issue Title var parts = shortname.Split(" - "); if (parts.Length < 2) @@ -255,6 +265,13 @@ public class CreateComicInfo : Node info.Number = int.Parse(lastChanceMatch.Value); return info; } + + if (shortname.ToLowerInvariant().Contains("annual") && year != null) + { + info.Volume = "Annual"; + info.Number = year.Value; + return info; + } return Result.Fail("Invalid filename: " + shortname); } @@ -296,9 +313,9 @@ public class CreateComicInfo : Node /// /// the name of the file /// the new name and the year if found - private static (string Name, string? Year) ExtractYear(string shortname) + private static (string Name, int? Year) ExtractYear(string shortname) { - string? year = null; + int? year = null; // Regular expression to match the year in the specified formats Match match = Regex.Match(shortname, @"(?:(?:19|20)\d{2})|\((?:19|20)\d{2}\)|-(?:\s)?(?:19|20)\d{2}(?:\s)?-"); @@ -306,11 +323,25 @@ public class CreateComicInfo : Node if (match.Success) { // Extract the matched year - year = match.Value.Trim('(', ')', '-', ' '); + year = int.Parse(match.Value.Trim('(', ')', '-', ' ')); // Remove the matched year from the input string shortname = shortname.Remove(match.Index, match.Length).Trim(); } + else + { + match = Regex.Match(shortname, @"'(\d{2})\b"); + + if (match.Success) + { + // Extract the matched year + int number = int.Parse(match.Groups[1].Value); + // Determine the year + year = number > 50 ? 1900 + number : 2000 + number; + // Remove the matched year from the input string + shortname = shortname.Remove(match.Index, match.Length).Trim(); + } + } return (shortname, year); } diff --git a/ComicNodes/Tests/ComicInfoTests.cs b/ComicNodes/Tests/ComicInfoTests.cs index 4fade6b7..0e3c60f0 100644 --- a/ComicNodes/Tests/ComicInfoTests.cs +++ b/ComicNodes/Tests/ComicInfoTests.cs @@ -146,7 +146,90 @@ public class ComicInfoTests : TestBase Assert.AreEqual("X-Man - #005.cbz", name.Value); } + [TestMethod] + public void Annual1900s() + { + var result = CreateComicInfo.GetInfo(Logger, + "/home/john/Comics/Marvel/X-Men/X-Man/X-Man Annual '97.cbz", + "/home/john/Comics", + true); + + TestContext.WriteLine(Logger.ToString()); + + Assert.IsFalse(result.IsFailed); + var info = result.Value; + Assert.IsNotNull(info); + Assert.AreEqual("Marvel", info.Publisher); + Assert.AreEqual("X-Man", info.Series); + Assert.AreEqual("Annual", info.Volume); + Assert.AreEqual(1997, info.Number); + + var xml = CreateComicInfo.SerializeToXml(info); + Assert.IsFalse(string.IsNullOrWhiteSpace(xml)); + TestContext.WriteLine(new string('-', 70)); + TestContext.WriteLine(xml); + + var name = CreateComicInfo.GetNewName(info, "cbz", 3); + Assert.AreEqual("X-Man - Annual 1997.cbz", name.Value); + } + + [TestMethod] + public void Annual2000s() + { + var result = CreateComicInfo.GetInfo(Logger, + "/home/john/Comics/Marvel/X-Men/X-Man/X-Man Annual '04.cbz", + "/home/john/Comics", + true); + + TestContext.WriteLine(Logger.ToString()); + + Assert.IsFalse(result.IsFailed); + var info = result.Value; + Assert.IsNotNull(info); + Assert.AreEqual("Marvel", info.Publisher); + Assert.AreEqual("X-Man", info.Series); + Assert.AreEqual("Annual", info.Volume); + Assert.AreEqual(2004, info.Number); + + var xml = CreateComicInfo.SerializeToXml(info); + Assert.IsFalse(string.IsNullOrWhiteSpace(xml)); + TestContext.WriteLine(new string('-', 70)); + TestContext.WriteLine(xml); + + var name = CreateComicInfo.GetNewName(info, "cbz", 3); + Assert.AreEqual("X-Man - Annual 2004.cbz", name.Value); + } + + + [TestMethod] + public void AnnualFullYear() + { + var result = CreateComicInfo.GetInfo(Logger, + "/home/john/Comics/Marvel/X-Men/X-Man/X-Man Annual 2004.cbz", + "/home/john/Comics", + true); + + TestContext.WriteLine(Logger.ToString()); + + Assert.IsFalse(result.IsFailed); + var info = result.Value; + Assert.IsNotNull(info); + Assert.AreEqual("Marvel", info.Publisher); + Assert.AreEqual("X-Man", info.Series); + Assert.AreEqual("Annual", info.Volume); + Assert.AreEqual(2004, info.Number); + + var xml = CreateComicInfo.SerializeToXml(info); + Assert.IsFalse(string.IsNullOrWhiteSpace(xml)); + TestContext.WriteLine(new string('-', 70)); + TestContext.WriteLine(xml); + + var name = CreateComicInfo.GetNewName(info, "cbz", 3); + Assert.AreEqual("X-Man - Annual 2004.cbz", name.Value); + } + + // [TestMethod] public void PhysicalFileTest() { const string FILE = diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index 58095230..0076af7f 100644 Binary files a/FileFlows.Plugin.dll and b/FileFlows.Plugin.dll differ diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index 284f805a..41f9dad2 100644 Binary files a/FileFlows.Plugin.pdb and b/FileFlows.Plugin.pdb differ