From 65ef01871901a1020b1b4d87ecadf6983c30e16c Mon Sep 17 00:00:00 2001 From: Mbucari Date: Mon, 13 Feb 2023 10:09:13 -0700 Subject: [PATCH] Move NameListFormatter to its own class --- Source/LibationFileManager/NameListFormat.cs | 95 ++++++++++++++++++++ Source/LibationFileManager/Templates.cs | 90 +------------------ 2 files changed, 98 insertions(+), 87 deletions(-) create mode 100644 Source/LibationFileManager/NameListFormat.cs diff --git a/Source/LibationFileManager/NameListFormat.cs b/Source/LibationFileManager/NameListFormat.cs new file mode 100644 index 00000000..2ca5f94b --- /dev/null +++ b/Source/LibationFileManager/NameListFormat.cs @@ -0,0 +1,95 @@ +using FileManager.NamingTemplate; +using NameParser; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace LibationFileManager +{ + internal partial class NameListFormat + { + public static string Formatter(ITemplateTag _, IEnumerable names, string formatString) + { + var humanNames = names.Select(n => new HumanName(RemoveSuffix(n), Prefer.FirstOverPrefix)); + + var sortedNames = Sort(humanNames, formatString); + var nameFormatString = Format(formatString, defaultValue: "{T} {F} {M} {L} {S}"); + var separatorString = Separator(formatString, defaultValue: ", "); + var maxNames = Max(formatString, defaultValue: humanNames.Count()); + + var formattedNames = string.Join(separatorString, sortedNames.Take(maxNames).Select(n => FormatName(n, nameFormatString))); + + while (formattedNames.Contains(" ")) + formattedNames = formattedNames.Replace(" ", " "); + + return formattedNames; + } + + private static string RemoveSuffix(string namesString) + { + namesString = namesString.Replace('’', '\'').Replace(" - Ret.", ", Ret."); + int dashIndex = namesString.IndexOf(" - "); + return (dashIndex > 0 ? namesString[..dashIndex] : namesString).Trim(); + } + + private static IEnumerable Sort(IEnumerable humanNames, string formatString) + { + var sortMatch = SortRegex().Match(formatString); + return + sortMatch.Success + ? sortMatch.Groups[1].Value == "F" ? humanNames.OrderBy(n => n.First) + : sortMatch.Groups[1].Value == "M" ? humanNames.OrderBy(n => n.Middle) + : sortMatch.Groups[1].Value == "L" ? humanNames.OrderBy(n => n.Last) + : humanNames + : humanNames; + } + + private static string Format(string formatString, string defaultValue) + { + var formatMatch = FormatRegex().Match(formatString); + return formatMatch.Success ? formatMatch.Groups[1].Value : defaultValue; + } + + private static string Separator(string formatString, string defaultValue) + { + var separatorMatch = SeparatorRegex().Match(formatString); + return separatorMatch.Success ? separatorMatch.Groups[1].Value : defaultValue; + } + + private static int Max(string formatString, int defaultValue) + { + var maxMatch = MaxRegex().Match(formatString); + return maxMatch.Success && int.TryParse(maxMatch.Groups[1].Value, out var max) ? int.Max(1, max) : defaultValue; + } + + private static string FormatName(HumanName humanName, string nameFormatString) + { + //Single-word names parse as first names. Use it as last name. + var lastName = string.IsNullOrWhiteSpace(humanName.Last) ? humanName.First : humanName.Last; + + nameFormatString + = nameFormatString + .Replace("{T}", "{0}") + .Replace("{F}", "{1}") + .Replace("{M}", "{2}") + .Replace("{L}", "{3}") + .Replace("{S}", "{4}"); + + return string.Format(nameFormatString, humanName.Title, humanName.First, humanName.Middle, lastName, humanName.Suffix).Trim(); + } + + /// Sort must have exactly one of the characters F, M, or L + [GeneratedRegex(@"[Ss]ort\(\s*?([FML])\s*?\)")] + private static partial Regex SortRegex(); + /// Format must have at least one of the string {T}, {F}, {M}, {L}, or {S} + [GeneratedRegex(@"[Ff]ormat\((.*?(?:{[TFMLS]})+.*?)\)")] + private static partial Regex FormatRegex(); + /// Separator can be anything + [GeneratedRegex(@"[Ss]eparator\((.*?)\)")] + private static partial Regex SeparatorRegex(); + /// Max must have a 1 or 2-digit number + [GeneratedRegex(@"[Mm]ax\(\s*?(\d{1,2})\s*?\)")] + private static partial Regex MaxRegex(); + } +} diff --git a/Source/LibationFileManager/Templates.cs b/Source/LibationFileManager/Templates.cs index f714637e..f68abeb5 100644 --- a/Source/LibationFileManager/Templates.cs +++ b/Source/LibationFileManager/Templates.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using AaxDecrypter; using Dinah.Core; using FileManager; @@ -19,7 +18,7 @@ namespace LibationFileManager static abstract IEnumerable TagCollections { get; } } - public abstract partial class Templates + public abstract class Templates { public const string ERROR_FULL_PATH_IS_INVALID = @"No colons or full paths allowed. Eg: should not start with C:\"; public const string WARNING_NO_CHAPTER_NUMBER_TAG = "Should include chapter number tag in template used for naming files which are split by chapter. Ie: or "; @@ -203,9 +202,9 @@ namespace LibationFileManager { TemplateTags.Id, lb => lb.AudibleProductId, v => v }, { TemplateTags.Title, lb => lb.Title }, { TemplateTags.TitleShort, lb => getTitleShort(lb.Title) }, - { TemplateTags.Author, lb => lb.Authors, NameListFormatter }, + { TemplateTags.Author, lb => lb.Authors, NameListFormat.Formatter }, { TemplateTags.FirstAuthor, lb => lb.FirstAuthor }, - { TemplateTags.Narrator, lb => lb.Narrators, NameListFormatter }, + { TemplateTags.Narrator, lb => lb.Narrators, NameListFormat.Formatter }, { TemplateTags.FirstNarrator, lb => lb.FirstNarrator }, { TemplateTags.Series, lb => lb.SeriesName }, { TemplateTags.SeriesNumber, lb => lb.SeriesNumber }, @@ -252,89 +251,6 @@ namespace LibationFileManager #region Tag Formatters - /// Sort must have exactly one of the characters F, M, or L - [GeneratedRegex(@"[Ss]ort\(\s*?([FML])\s*?\)")] - private static partial Regex NamesSortRegex(); - /// Format must have at least one of the string {T}, {F}, {M}, {L}, or {S} - [GeneratedRegex(@"[Ff]ormat\((.*?(?:{[TFMLS]})+.*?)\)")] - private static partial Regex NamesFormatRegex(); - /// Separator can be anything - [GeneratedRegex(@"[Ss]eparator\((.*?)\)")] - private static partial Regex NamesSeparatorRegex(); - /// Max must have a 1 or 2-digit number - [GeneratedRegex(@"[Mm]ax\(\s*?(\d{1,2})\s*?\)")] - private static partial Regex NamesMaxRegex(); - - private static string NameListFormatter(ITemplateTag templateTag, IEnumerable names, string formatString) - { - var humanNames = names.Select(n => new HumanName(removeSuffix(n), Prefer.FirstOverPrefix)); - - var sortedNames = sort(humanNames, formatString); - var nameFormatString = format(formatString, defaultValue: "{T} {F} {M} {L} {S}"); - var separatorString = separator(formatString, defaultValue: ", "); - var maxNames = max(formatString, defaultValue: humanNames.Count()); - - var formattedNames = string.Join(separatorString, sortedNames.Take(maxNames).Select(n => formatName(n, nameFormatString))); - - while (formattedNames.Contains(" ")) - formattedNames = formattedNames.Replace(" ", " "); - - return formattedNames; - - static string removeSuffix(string namesString) - { - namesString = namesString.Replace('’', '\'').Replace(" - Ret.", ", Ret."); - int dashIndex = namesString.IndexOf(" - "); - return (dashIndex > 0 ? namesString[..dashIndex] : namesString).Trim(); - } - - static IEnumerable sort(IEnumerable humanNames, string formatString) - { - var sortMatch = NamesSortRegex().Match(formatString); - return - sortMatch.Success - ? sortMatch.Groups[1].Value == "F" ? humanNames.OrderBy(n => n.First) - : sortMatch.Groups[1].Value == "M" ? humanNames.OrderBy(n => n.Middle) - : sortMatch.Groups[1].Value == "L" ? humanNames.OrderBy(n => n.Last) - : humanNames - : humanNames; - } - - static string format(string formatString, string defaultValue) - { - var formatMatch = NamesFormatRegex().Match(formatString); - return formatMatch.Success ? formatMatch.Groups[1].Value : defaultValue; - } - - static string separator(string formatString, string defaultValue) - { - var separatorMatch = NamesSeparatorRegex().Match(formatString); - return separatorMatch.Success ? separatorMatch.Groups[1].Value : defaultValue; - } - - static int max(string formatString, int defaultValue) - { - var maxMatch = NamesMaxRegex().Match(formatString); - return maxMatch.Success && int.TryParse(maxMatch.Groups[1].Value, out var max) ? int.Max(1, max) : defaultValue; - } - - static string formatName(HumanName humanName, string nameFormatString) - { - //Single-word names parse as first names. Use it as last name. - var lastName = string.IsNullOrWhiteSpace(humanName.Last) ? humanName.First : humanName.Last; - - nameFormatString - = nameFormatString - .Replace("{T}", "{0}") - .Replace("{F}", "{1}") - .Replace("{M}", "{2}") - .Replace("{L}", "{3}") - .Replace("{S}", "{4}"); - - return string.Format(nameFormatString, humanName.Title, humanName.First, humanName.Middle, lastName, humanName.Suffix).Trim(); - } - } - private static string getTitleShort(string title) => title?.IndexOf(':') > 0 ? title.Substring(0, title.IndexOf(':')) : title;