Move NameListFormatter to its own class
This commit is contained in:
parent
f0ca349539
commit
65ef018719
95
Source/LibationFileManager/NameListFormat.cs
Normal file
95
Source/LibationFileManager/NameListFormat.cs
Normal file
@ -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<string> 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<HumanName> Sort(IEnumerable<HumanName> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Sort must have exactly one of the characters F, M, or L </summary>
|
||||||
|
[GeneratedRegex(@"[Ss]ort\(\s*?([FML])\s*?\)")]
|
||||||
|
private static partial Regex SortRegex();
|
||||||
|
/// <summary> Format must have at least one of the string {T}, {F}, {M}, {L}, or {S} </summary>
|
||||||
|
[GeneratedRegex(@"[Ff]ormat\((.*?(?:{[TFMLS]})+.*?)\)")]
|
||||||
|
private static partial Regex FormatRegex();
|
||||||
|
/// <summary> Separator can be anything </summary>
|
||||||
|
[GeneratedRegex(@"[Ss]eparator\((.*?)\)")]
|
||||||
|
private static partial Regex SeparatorRegex();
|
||||||
|
/// <summary> Max must have a 1 or 2-digit number </summary>
|
||||||
|
[GeneratedRegex(@"[Mm]ax\(\s*?(\d{1,2})\s*?\)")]
|
||||||
|
private static partial Regex MaxRegex();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using AaxDecrypter;
|
using AaxDecrypter;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
@ -19,7 +18,7 @@ namespace LibationFileManager
|
|||||||
static abstract IEnumerable<TagCollection> TagCollections { get; }
|
static abstract IEnumerable<TagCollection> 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 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: <ch#> or <ch# 0>";
|
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: <ch#> or <ch# 0>";
|
||||||
@ -203,9 +202,9 @@ namespace LibationFileManager
|
|||||||
{ TemplateTags.Id, lb => lb.AudibleProductId, v => v },
|
{ TemplateTags.Id, lb => lb.AudibleProductId, v => v },
|
||||||
{ TemplateTags.Title, lb => lb.Title },
|
{ TemplateTags.Title, lb => lb.Title },
|
||||||
{ TemplateTags.TitleShort, lb => getTitleShort(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.FirstAuthor, lb => lb.FirstAuthor },
|
||||||
{ TemplateTags.Narrator, lb => lb.Narrators, NameListFormatter },
|
{ TemplateTags.Narrator, lb => lb.Narrators, NameListFormat.Formatter },
|
||||||
{ TemplateTags.FirstNarrator, lb => lb.FirstNarrator },
|
{ TemplateTags.FirstNarrator, lb => lb.FirstNarrator },
|
||||||
{ TemplateTags.Series, lb => lb.SeriesName },
|
{ TemplateTags.Series, lb => lb.SeriesName },
|
||||||
{ TemplateTags.SeriesNumber, lb => lb.SeriesNumber },
|
{ TemplateTags.SeriesNumber, lb => lb.SeriesNumber },
|
||||||
@ -252,89 +251,6 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
#region Tag Formatters
|
#region Tag Formatters
|
||||||
|
|
||||||
/// <summary> Sort must have exactly one of the characters F, M, or L </summary>
|
|
||||||
[GeneratedRegex(@"[Ss]ort\(\s*?([FML])\s*?\)")]
|
|
||||||
private static partial Regex NamesSortRegex();
|
|
||||||
/// <summary> Format must have at least one of the string {T}, {F}, {M}, {L}, or {S} </summary>
|
|
||||||
[GeneratedRegex(@"[Ff]ormat\((.*?(?:{[TFMLS]})+.*?)\)")]
|
|
||||||
private static partial Regex NamesFormatRegex();
|
|
||||||
/// <summary> Separator can be anything </summary>
|
|
||||||
[GeneratedRegex(@"[Ss]eparator\((.*?)\)")]
|
|
||||||
private static partial Regex NamesSeparatorRegex();
|
|
||||||
/// <summary> Max must have a 1 or 2-digit number </summary>
|
|
||||||
[GeneratedRegex(@"[Mm]ax\(\s*?(\d{1,2})\s*?\)")]
|
|
||||||
private static partial Regex NamesMaxRegex();
|
|
||||||
|
|
||||||
private static string NameListFormatter(ITemplateTag templateTag, IEnumerable<string> 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<HumanName> sort(IEnumerable<HumanName> 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)
|
private static string getTitleShort(string title)
|
||||||
=> title?.IndexOf(':') > 0 ? title.Substring(0, title.IndexOf(':')) : title;
|
=> title?.IndexOf(':') > 0 ? title.Substring(0, title.IndexOf(':')) : title;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user