diff --git a/Source/AaxDecrypter/MultiConvertFileProperties.cs b/Source/AaxDecrypter/MultiConvertFileProperties.cs
index 71bafe21..1618884b 100644
--- a/Source/AaxDecrypter/MultiConvertFileProperties.cs
+++ b/Source/AaxDecrypter/MultiConvertFileProperties.cs
@@ -10,6 +10,6 @@ namespace AaxDecrypter
public int PartsPosition { get; set; }
public int PartsTotal { get; set; }
public string Title { get; set; }
-
+ public DateTime FileDate { get; } = DateTime.Now;
}
}
diff --git a/Source/FileLiberator/UtilityExtensions.cs b/Source/FileLiberator/UtilityExtensions.cs
index 37fba4c8..d1820922 100644
--- a/Source/FileLiberator/UtilityExtensions.cs
+++ b/Source/FileLiberator/UtilityExtensions.cs
@@ -27,11 +27,13 @@ namespace FileLiberator
public static LibraryBookDto ToDto(this LibraryBook libraryBook) => new()
{
Account = libraryBook.Account,
+ DateAdded = libraryBook.DateAdded,
AudibleProductId = libraryBook.Book.AudibleProductId,
Title = libraryBook.Book.Title ?? "",
Locale = libraryBook.Book.Locale,
YearPublished = libraryBook.Book.DatePublished?.Year,
+ DatePublished = libraryBook.Book.DatePublished,
Authors = libraryBook.Book.Authors.Select(c => c.Name).ToList(),
diff --git a/Source/FileManager/FileNamingTemplate.cs b/Source/FileManager/FileNamingTemplate.cs
index 29bde7e6..2ce85c0d 100644
--- a/Source/FileManager/FileNamingTemplate.cs
+++ b/Source/FileManager/FileNamingTemplate.cs
@@ -9,11 +9,15 @@ namespace FileManager
/// Get valid filename. Advanced features incl. parameterized template
public class FileNamingTemplate : NamingTemplate
{
+ public ReplacementCharacters ReplacementCharacters { get; }
/// Proposed file name with optional html-styled template tags.
- public FileNamingTemplate(string template) : base(template) { }
+ public FileNamingTemplate(string template, ReplacementCharacters replacement) : base(template)
+ {
+ ReplacementCharacters = replacement ?? ReplacementCharacters.Default;
+ }
/// Generate a valid path for this file or directory
- public LongPath GetFilePath(ReplacementCharacters replacements, string fileExtension, bool returnFirstExisting = false)
+ public LongPath GetFilePath(string fileExtension, bool returnFirstExisting = false)
{
string fileName =
Template.EndsWith(Path.DirectorySeparatorChar) || Template.EndsWith(Path.AltDirectorySeparatorChar) ?
@@ -22,7 +26,7 @@ namespace FileManager
List pathParts = new();
- var paramReplacements = ParameterReplacements.ToDictionary(r => $"<{formatKey(r.Key)}>", r => formatValue(r.Value, replacements));
+ var paramReplacements = ParameterReplacements.ToDictionary(r => $"<{formatKey(r.Key)}>", r => formatValue(r.Value, ReplacementCharacters));
while (!string.IsNullOrEmpty(fileName))
{
@@ -54,7 +58,7 @@ namespace FileManager
return FileUtility
.GetValidFilename(
Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - fileExtension.Length - 5)) + fileExtension,
- replacements,
+ ReplacementCharacters,
fileExtension,
returnFirstExisting
);
diff --git a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
index 14c7ce99..5bbf9eb4 100644
--- a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
@@ -50,7 +50,9 @@ namespace LibationAvalonia.Dialogs
{
var dataGrid = sender as DataGrid;
- var item = (dataGrid.SelectedItem as Tuple).Item1.Replace("\x200C", "").Replace("...", "");
+ var item = (dataGrid.SelectedItem as Tuple).Item3;
+ if (string.IsNullOrWhiteSpace(item)) return;
+
var text = userEditTbox.Text;
userEditTbox.Text = text.Insert(Math.Min(Math.Max(0, userEditTbox.CaretIndex), text.Length), item);
@@ -84,13 +86,14 @@ namespace LibationAvalonia.Dialogs
Template = templates;
Description = templates.Description;
ListItems
- = new AvaloniaList>(
+ = new AvaloniaList>(
Template
.GetTemplateTags()
.Select(
- t => new Tuple(
+ t => new Tuple(
$"<{t.TagName.Replace("->", "-\x200C>").Replace("<-", "<\x200C-")}>",
- t.Description)
+ t.Description,
+ t.DefaultValue)
)
);
@@ -108,13 +111,13 @@ namespace LibationAvalonia.Dialogs
}
}
- public string workingTemplateText => Template.Sanitize(UserTemplateText);
+ public string workingTemplateText => Template.Sanitize(UserTemplateText, Configuration.Instance.ReplacementCharacters);
private string _warningText;
public string WarningText { get => _warningText; set => this.RaiseAndSetIfChanged(ref _warningText, value); }
public string Description { get; }
- public AvaloniaList> ListItems { get; set; }
+ public AvaloniaList> ListItems { get; set; }
public void resetTextBox(string value) => UserTemplateText = value;
@@ -138,6 +141,8 @@ namespace LibationAvalonia.Dialogs
var libraryBookDto = new LibraryBookDto
{
Account = "my account",
+ DateAdded = new DateTime(2022, 6, 9, 0, 0, 0),
+ DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
AudibleProductId = "123456789",
Title = "A Study in Scarlet: A Sherlock Holmes Novel",
Locale = "us",
diff --git a/Source/LibationFileManager/LibraryBookDto.cs b/Source/LibationFileManager/LibraryBookDto.cs
index d24d7ef7..31fc1565 100644
--- a/Source/LibationFileManager/LibraryBookDto.cs
+++ b/Source/LibationFileManager/LibraryBookDto.cs
@@ -25,10 +25,14 @@ namespace LibationFileManager
public int BitRate { get; set; }
public int SampleRate { get; set; }
public int Channels { get; set; }
- }
+ public DateTime FileDate { get; set; } = DateTime.Now;
+ public DateTime? DatePublished { get; set; }
+
+ }
public class LibraryBookDto : BookDto
- {
- public string Account { get; set; }
+ {
+ public DateTime? DateAdded { get; set; }
+ public string Account { get; set; }
}
}
diff --git a/Source/LibationFileManager/TemplateTags.cs b/Source/LibationFileManager/TemplateTags.cs
index 764f1ea8..e4146d28 100644
--- a/Source/LibationFileManager/TemplateTags.cs
+++ b/Source/LibationFileManager/TemplateTags.cs
@@ -7,16 +7,19 @@ namespace LibationFileManager
{
public sealed class TemplateTags : Enumeration
{
- public string TagName => DisplayName;
+ public string TagName => DisplayName;
+ public string DefaultValue { get; }
public string Description { get; }
public bool IsChapterOnly { get; }
private static int value = 0;
- private TemplateTags(string tagName, string description, bool isChapterOnly = false) : base(value++, tagName)
+ private TemplateTags(string tagName, string description, bool isChapterOnly = false, string defaultValue = null) : base(value++, tagName)
{
Description = description;
IsChapterOnly = isChapterOnly;
- }
+ DefaultValue = defaultValue ?? $"<{tagName}>";
+
+ }
// putting these first is the incredibly lazy way to make them show up first in the EditTemplateDialog
public static TemplateTags ChCount { get; } = new TemplateTags("ch count", "Number of chapters", true);
@@ -43,7 +46,9 @@ namespace LibationFileManager
// Special cases. Aren't mapped to replacements in Templates.cs
// Included here for display by EditTemplateDialog
- public static TemplateTags Date { get; } = new TemplateTags("date[...]", "File date/time. e.g. yyyy-MM-dd HH-mm");
- public static TemplateTags IfSeries { get; } = new TemplateTags("if series->...<-if series", "Only include if part of a series");
+ public static TemplateTags FileDate { get; } = new TemplateTags("file date [...]", "File date/time. e.g. yyyy-MM-dd HH-mm", false, $"");
+ public static TemplateTags DatePublished { get; } = new TemplateTags("pub date [...]", "Publication date. e.g. yyyy-MM-dd", false, $"");
+ public static TemplateTags DateAdded { get; } = new TemplateTags("date added [...]", "Date added to you Audible account. e.g. yyyy-MM-dd", false, $"");
+ public static TemplateTags IfSeries { get; } = new TemplateTags("if series->...<-if series", "Only include if part of a series", false, "<-if series>");
}
}
diff --git a/Source/LibationFileManager/Templates.cs b/Source/LibationFileManager/Templates.cs
index 6047cfe9..19dc62d9 100644
--- a/Source/LibationFileManager/Templates.cs
+++ b/Source/LibationFileManager/Templates.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Dinah.Core;
+using Dinah.Core.Collections.Generic;
using FileManager;
namespace LibationFileManager
@@ -102,17 +103,21 @@ namespace LibationFileManager
public string GetPortionFilename(LibraryBookDto libraryBookDto, string template, string fileExtension)
=> string.IsNullOrWhiteSpace(template)
? ""
- : getFileNamingTemplate(libraryBookDto, template, null, fileExtension)
- .GetFilePath(Configuration.Instance.ReplacementCharacters, fileExtension).PathWithoutPrefix;
+ : getFileNamingTemplate(libraryBookDto, template, null, fileExtension, Configuration.Instance.ReplacementCharacters)
+ .GetFilePath(fileExtension).PathWithoutPrefix;
- private static Regex dateFormatRegex { get; } = new Regex(@"", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ public const string DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
+ private static Regex fileDateTagRegex { get; } = new Regex(@"", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ private static Regex dateAddedTagRegex { get; } = new Regex(@"", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ private static Regex datePublishedTagRegex { get; } = new Regex(@"", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static Regex ifSeriesRegex { get; } = new Regex("(.*?)<-if series>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
- internal static FileNamingTemplate getFileNamingTemplate(LibraryBookDto libraryBookDto, string template, string dirFullPath, string extension)
+ internal static FileNamingTemplate getFileNamingTemplate(LibraryBookDto libraryBookDto, string template, string dirFullPath, string extension, ReplacementCharacters replacements)
{
ArgumentValidator.EnsureNotNullOrWhiteSpace(template, nameof(template));
ArgumentValidator.EnsureNotNull(libraryBookDto, nameof(libraryBookDto));
+ replacements ??= Configuration.Instance.ReplacementCharacters;
dirFullPath = dirFullPath?.Trim() ?? "";
// for non-series, remove and <-if series> tags and everything in between
@@ -121,12 +126,16 @@ namespace LibationFileManager
template,
string.IsNullOrWhiteSpace(libraryBookDto.SeriesName) ? "" : "$1");
- template = dateFormatRegex.Replace(template, dateMatchEvaluator);
+ //Get date replacement parameters. Sanitizes the format text and replaces
+ //the template with the sanitized text before creating FileNamingTemplate
+ var fileDateParams = getSanitizeDateReplacementParameters(fileDateTagRegex, ref template, replacements, libraryBookDto.FileDate);
+ var dateAddedParams = getSanitizeDateReplacementParameters(dateAddedTagRegex, ref template, replacements, libraryBookDto.DateAdded);
+ var pubDateParams = getSanitizeDateReplacementParameters(datePublishedTagRegex, ref template, replacements, libraryBookDto.DatePublished);
var t = template + FileUtility.GetStandardizedExtension(extension);
var fullfilename = dirFullPath == "" ? t : Path.Combine(dirFullPath, t);
- var fileNamingTemplate = new FileNamingTemplate(fullfilename);
+ var fileNamingTemplate = new FileNamingTemplate(fullfilename, replacements);
var title = libraryBookDto.Title ?? "";
var titleShort = title.IndexOf(':') < 1 ? title : title.Substring(0, title.IndexOf(':'));
@@ -147,31 +156,92 @@ namespace LibationFileManager
fileNamingTemplate.AddParameterReplacement(TemplateTags.Locale, libraryBookDto.Locale);
fileNamingTemplate.AddParameterReplacement(TemplateTags.YearPublished, libraryBookDto.YearPublished?.ToString() ?? "1900");
- return fileNamingTemplate;
+ //Add the sanitized replacement parameters
+ foreach (var param in fileDateParams)
+ fileNamingTemplate.ParameterReplacements.AddIfNotContains(param);
+ foreach (var param in dateAddedParams)
+ fileNamingTemplate.ParameterReplacements.AddIfNotContains(param);
+ foreach (var param in pubDateParams)
+ fileNamingTemplate.ParameterReplacements.AddIfNotContains(param);
+
+ return fileNamingTemplate;
}
#endregion
- private static string dateMatchEvaluator(Match match)
+ #region DateTime Tags
+
+ /// the file naming template. Any found date tags will be sanitized,
+ /// and the template's original date tag will be replaced with the sanitized tag.
+ /// A list of parameter replacement key-value pairs
+ private static List> getSanitizeDateReplacementParameters(Regex datePattern, ref string template, ReplacementCharacters replacements, DateTime? dateTime)
{
+ List> dateParams = new();
+
+ foreach (Match dateTag in datePattern.Matches(template))
+ {
+ var sanitizedTag = sanitizeDateParameterTag(dateTag, replacements, out var sanitizedFormatter);
+ if (tryFormatDateTime(dateTime, sanitizedFormatter, replacements, out var formattedDateString))
+ {
+ dateParams.Add(new(sanitizedTag, formattedDateString));
+ template = template.Replace(dateTag.Value, sanitizedTag);
+ }
+ }
+ return dateParams;
+ }
+
+ /// a date parameter replacement tag with the format string sanitized
+ private static string sanitizeDateParameterTag(Match dateTag, ReplacementCharacters replacements, out string sanitizedFormatter)
+ {
+ if (dateTag.Groups.Count < 2 || string.IsNullOrWhiteSpace(dateTag.Groups[1].Value))
+ {
+ sanitizedFormatter = DEFAULT_DATE_FORMAT;
+ return dateTag.Value;
+ }
+
+ var formatter = dateTag.Groups[1].Value;
+
+ sanitizedFormatter = replacements.ReplaceFilenameChars(formatter).Trim();
+
+ return dateTag.Value.Replace(formatter, sanitizedFormatter);
+ }
+
+ private static bool tryFormatDateTime(DateTime? dateTime, string sanitizedFormatter, ReplacementCharacters replacements, out string formattedDateString)
+ {
+ if (!dateTime.HasValue)
+ {
+ formattedDateString = string.Empty;
+ return true;
+ }
+
try
{
- return DateTime.Now.ToString(match.Groups[1].Value);
+ formattedDateString = replacements.ReplaceFilenameChars(dateTime.Value.ToString(sanitizedFormatter)).Trim();
+ return true;
}
catch
{
- return match.Value;
+ formattedDateString = null;
+ return false;
}
}
+ #endregion
public virtual IEnumerable GetTemplateTags()
=> TemplateTags.GetAll()
// yeah, this line is a little funky but it works when you think through it. also: trust the unit tests
.Where(t => IsChapterized || !t.IsChapterOnly);
- public string Sanitize(string template)
+ public string Sanitize(string template, ReplacementCharacters replacements)
{
var value = template ?? "";
+ // Replace invalid filename characters in the DateTime format provider so we don't trip any alarms.
+ // Illegal filename characters in the formatter are allowed because they will be replaced by
+ // getFileNamingTemplate()
+ value = fileDateTagRegex.Replace(value, m => sanitizeDateParameterTag(m, replacements, out _));
+ value = dateAddedTagRegex.Replace(value, m => sanitizeDateParameterTag(m, replacements, out _));
+ value = datePublishedTagRegex.Replace(value, m => sanitizeDateParameterTag(m, replacements, out _));
+
// don't use alt slash
value = value.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
@@ -218,7 +288,7 @@ namespace LibationFileManager
// must be relative. no colons. all other path chars are valid enough to pass this check and will be handled on final save.
if (ReplacementCharacters.ContainsInvalidPathChar(template.Replace("<", "").Replace(">", "")))
- return new[] { ERROR_INVALID_FILE_NAME_CHAR };
+ return new[] { ERROR_INVALID_FILE_NAME_CHAR };
return Valid;
}
@@ -229,8 +299,8 @@ namespace LibationFileManager
#region to file name
/// USES LIVE CONFIGURATION VALUES
public string GetFilename(LibraryBookDto libraryBookDto, string baseDir = null)
- => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FolderTemplate, baseDir ?? AudibleFileStorage.BooksDirectory, null)
- .GetFilePath(Configuration.Instance.ReplacementCharacters, string.Empty);
+ => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FolderTemplate, baseDir ?? AudibleFileStorage.BooksDirectory, null, Configuration.Instance.ReplacementCharacters)
+ .GetFilePath(string.Empty);
#endregion
}
@@ -252,8 +322,8 @@ namespace LibationFileManager
#region to file name
/// USES LIVE CONFIGURATION VALUES
public string GetFilename(LibraryBookDto libraryBookDto, string dirFullPath, string extension, bool returnFirstExisting = false)
- => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FileTemplate, dirFullPath, extension)
- .GetFilePath(Configuration.Instance.ReplacementCharacters, extension, returnFirstExisting);
+ => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FileTemplate, dirFullPath, extension, Configuration.Instance.ReplacementCharacters)
+ .GetFilePath(extension, returnFirstExisting);
#endregion
}
@@ -294,14 +364,21 @@ namespace LibationFileManager
replacements ??= Configuration.Instance.ReplacementCharacters;
var fileExtension = Path.GetExtension(props.OutputFileName);
- var fileNamingTemplate = getFileNamingTemplate(libraryBookDto, template, fullDirPath, fileExtension);
+ var fileNamingTemplate = getFileNamingTemplate(libraryBookDto, template, fullDirPath, fileExtension, replacements);
fileNamingTemplate.AddParameterReplacement(TemplateTags.ChCount, props.PartsTotal);
fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber, props.PartsPosition);
fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber0, FileUtility.GetSequenceFormatted(props.PartsPosition, props.PartsTotal));
fileNamingTemplate.AddParameterReplacement(TemplateTags.ChTitle, props.Title ?? "");
- return fileNamingTemplate.GetFilePath(replacements, fileExtension).PathWithoutPrefix;
+ foreach (Match dateTag in fileDateTagRegex.Matches(fileNamingTemplate.Template))
+ {
+ var sanitizedTag = sanitizeDateParameterTag(dateTag, replacements, out string sanitizedFormatter);
+ if (tryFormatDateTime(props.FileDate, sanitizedFormatter, replacements, out var formattedDateString))
+ fileNamingTemplate.ParameterReplacements[sanitizedTag] = formattedDateString;
+ }
+
+ return fileNamingTemplate.GetFilePath(fileExtension).PathWithoutPrefix;
}
#endregion
}
diff --git a/Source/LibationFileManager/UtilityExtensions.cs b/Source/LibationFileManager/UtilityExtensions.cs
index 5c322a03..8ffe8c9e 100644
--- a/Source/LibationFileManager/UtilityExtensions.cs
+++ b/Source/LibationFileManager/UtilityExtensions.cs
@@ -9,5 +9,8 @@ namespace LibationFileManager
{
public static void AddParameterReplacement(this NamingTemplate fileNamingTemplate, TemplateTags templateTags, object value)
=> fileNamingTemplate.AddParameterReplacement(templateTags.TagName, value);
+
+ public static void AddUniqueParameterReplacement(this NamingTemplate namingTemplate, string key, object value)
+ => namingTemplate.ParameterReplacements[key] = value;
}
}
diff --git a/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs b/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
index a14005d0..e44c6e17 100644
--- a/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
+++ b/Source/LibationWinForms/Dialogs/EditTemplateDialog.cs
@@ -18,7 +18,7 @@ namespace LibationWinForms.Dialogs
private string workingTemplateText
{
get => _workingTemplateText;
- set => _workingTemplateText = template.Sanitize(value);
+ set => _workingTemplateText = template.Sanitize(value, Configuration.Instance.ReplacementCharacters);
}
private void resetTextBox(string value) => this.templateTb.Text = workingTemplateText = value;
@@ -59,7 +59,7 @@ namespace LibationWinForms.Dialogs
// populate list view
foreach (var tag in template.GetTemplateTags())
- listView1.Items.Add(new ListViewItem(new[] { $"<{tag.TagName}>", tag.Description }));
+ listView1.Items.Add(new ListViewItem(new[] { $"<{tag.TagName}>", tag.Description }) { Tag = tag.DefaultValue });
}
private void resetToDefaultBtn_Click(object sender, EventArgs e) => resetTextBox(template.DefaultTemplate);
@@ -73,6 +73,8 @@ namespace LibationWinForms.Dialogs
var libraryBookDto = new LibraryBookDto
{
Account = "my account",
+ DateAdded = new DateTime(2022, 6, 9, 0, 0, 0),
+ DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
AudibleProductId = "123456789",
Title = "A Study in Scarlet: A Sherlock Holmes Novel",
Locale = "us",
@@ -207,9 +209,11 @@ namespace LibationWinForms.Dialogs
private void listView1_DoubleClick(object sender, EventArgs e)
{
- var itemText = listView1.SelectedItems[0].Text.Replace("...", "");
- var text = templateTb.Text;
+ var itemText = listView1.SelectedItems[0].Tag as string;
+ if (string.IsNullOrEmpty(itemText)) return;
+
+ var text = templateTb.Text;
var selStart = Math.Min(Math.Max(0, templateTb.SelectionStart), text.Length);
templateTb.Text = text.Insert(selStart, itemText);
diff --git a/Source/_Tests/FileManager.Tests/FileNamingTemplateTests.cs b/Source/_Tests/FileManager.Tests/FileNamingTemplateTests.cs
index 54b0c375..b1822357 100644
--- a/Source/_Tests/FileManager.Tests/FileNamingTemplateTests.cs
+++ b/Source/_Tests/FileManager.Tests/FileNamingTemplateTests.cs
@@ -36,10 +36,10 @@ namespace FileNamingTemplateTests
extension = FileUtility.GetStandardizedExtension(extension);
var fullfilename = Path.Combine(dirFullPath, template + extension);
- var fileNamingTemplate = new FileNamingTemplate(fullfilename);
+ var fileNamingTemplate = new FileNamingTemplate(fullfilename, Replacements);
fileNamingTemplate.AddParameterReplacement("title", filename);
fileNamingTemplate.AddParameterReplacement("id", metadataSuffix);
- return fileNamingTemplate.GetFilePath(Replacements, extension).PathWithoutPrefix;
+ return fileNamingTemplate.GetFilePath(extension).PathWithoutPrefix;
}
[TestMethod]
@@ -61,10 +61,10 @@ namespace FileNamingTemplateTests
var estension = Path.GetExtension(originalPath);
var t = Path.ChangeExtension(originalPath, null) + " - - " + estension;
- var fileNamingTemplate = new FileNamingTemplate(t);
+ var fileNamingTemplate = new FileNamingTemplate(t, Replacements);
fileNamingTemplate.AddParameterReplacement("chapter", chapterCountLeadingZeros);
fileNamingTemplate.AddParameterReplacement("title", suffix);
- return fileNamingTemplate.GetFilePath(Replacements, estension).PathWithoutPrefix;
+ return fileNamingTemplate.GetFilePath(estension).PathWithoutPrefix;
}
[TestMethod]
@@ -74,9 +74,9 @@ namespace FileNamingTemplateTests
{
if (Environment.OSVersion.Platform == platformID)
{
- var fileNamingTemplate = new FileNamingTemplate(inStr);
+ var fileNamingTemplate = new FileNamingTemplate(inStr, Replacements);
fileNamingTemplate.AddParameterReplacement("title", @"s\l/a\s/h\e/s");
- fileNamingTemplate.GetFilePath(Replacements, "txt").PathWithoutPrefix.Should().Be(outStr);
+ fileNamingTemplate.GetFilePath("txt").PathWithoutPrefix.Should().Be(outStr);
}
}
}
diff --git a/Source/_Tests/LibationFileManager.Tests/TemplatesTests.cs b/Source/_Tests/LibationFileManager.Tests/TemplatesTests.cs
index 98a562f2..93759d85 100644
--- a/Source/_Tests/LibationFileManager.Tests/TemplatesTests.cs
+++ b/Source/_Tests/LibationFileManager.Tests/TemplatesTests.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -26,11 +26,32 @@ namespace TemplatesTests
=> new()
{
Account = "my account",
+ DateAdded = new DateTime(2022, 6, 9, 0, 0, 0),
+ DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
+ FileDate = new DateTime(2023, 1, 28, 0, 0, 0),
AudibleProductId = "asin",
Title = "A Study in Scarlet: A Sherlock Holmes Novel",
Locale = "us",
- YearPublished = 2017,
- Authors = new List { "Arthur Conan Doyle", "Stephen Fry - introductions" },
+ YearPublished = 2017,
+ Authors = new List { "Arthur Conan Doyle", "Stephen Fry - introductions" },
+ Narrators = new List { "Stephen Fry" },
+ SeriesName = seriesName ?? "",
+ SeriesNumber = "1",
+ BitRate = 128,
+ SampleRate = 44100,
+ Channels = 2
+ };
+
+ public static LibraryBookDto GetLibraryBookWithNullDates(string seriesName = "Sherlock Holmes")
+ => new()
+ {
+ Account = "my account",
+ FileDate = new DateTime(2023, 1, 28, 0, 0, 0),
+ AudibleProductId = "asin",
+ Title = "A Study in Scarlet: A Sherlock Holmes Novel",
+ Locale = "us",
+ YearPublished = 2017,
+ Authors = new List { "Arthur Conan Doyle", "Stephen Fry - introductions" },
Narrators = new List { "Stephen Fry" },
SeriesName = seriesName ?? "",
SeriesNumber = "1",
@@ -71,14 +92,14 @@ namespace TemplatesTests
[DataRow(null, @"C:\", "ext")]
[ExpectedException(typeof(ArgumentNullException))]
public void arg_null_exception(string template, string dirFullPath, string extension)
- => Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension);
+ => Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements);
[TestMethod]
[DataRow("", @"C:\foo\bar", "ext")]
[DataRow(" ", @"C:\foo\bar", "ext")]
[ExpectedException(typeof(ArgumentException))]
public void arg_exception(string template, string dirFullPath, string extension)
- => Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension);
+ => Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements);
[TestMethod]
[DataRow("f.txt", @"C:\foo\bar", "", @"C:\foo\bar\f.txt", PlatformID.Win32NT)]
@@ -98,20 +119,126 @@ namespace TemplatesTests
public void Tests(string template, string dirFullPath, string extension, string expected, PlatformID platformID)
{
if (Environment.OSVersion.Platform == platformID)
- Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension)
- .GetFilePath(Replacements, extension)
+ Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
.PathWithoutPrefix
.Should().Be(expected);
}
+ [TestMethod]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 23-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 23-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 23-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 23-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ [DataRow(" - ", @"C:\foo\bar", "m4b", @"C:\foo\bar\asin - 2023-01-28.m4b")]
+ public void DateFormat_pattern(string template, string dirFullPath, string extension, string expected)
+ {
+ if (Environment.OSVersion.Platform is not PlatformID.Win32NT)
+ {
+ dirFullPath = dirFullPath.Replace("C:", "").Replace('\\', '/');
+ expected = expected.Replace("C:", "").Replace('\\', '/');
+ }
+
+ Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
+ .PathWithoutPrefix
+ .Should().Be(expected);
+ }
+
+ [TestMethod]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<filedate[h]>.m4b")]
+ [DataRow("< filedate[yyyy]>", @"C:\foo\bar", ".m4b", @"C:\foo\bar\< filedate[yyyy]>.m4b")]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<filedate yyyy]>.m4b")]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<filedate [yyyy>.m4b")]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<filedate yyyy>.m4b")]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<fil edate[yyyy]>.m4b")]
+ [DataRow("", @"C:\foo\bar", ".m4b", @"C:\foo\bar\<filed ate[yyyy]>.m4b")]
+ public void DateFormat_invalid(string template, string dirFullPath, string extension, string expected)
+ {
+ if (Environment.OSVersion.Platform is not PlatformID.Win32NT)
+ {
+ dirFullPath = dirFullPath.Replace("C:", "").Replace('\\', '/');
+ expected = expected.Replace("C:", "").Replace('\\', '/').Replace('<', '<').Replace('>','>');
+ }
+
+ Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
+ .PathWithoutPrefix
+ .Should().Be(expected);
+ }
+
+ [TestMethod]
+ [DataRow(" ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\23-01-28 22-06-09 17-02.m4b")]
+ [DataRow(" ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\23-01-28 23-01-28 23-01-28.m4b")]
+ [DataRow(" ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\23-01-28 23-01-28 23-01-28.m4b")]
+ public void DateFormat_multiple(string template, string dirFullPath, string extension, string expected)
+ {
+ if (Environment.OSVersion.Platform is not PlatformID.Win32NT)
+ {
+ dirFullPath = dirFullPath.Replace("C:", "").Replace('\\', '/');
+ expected = expected.Replace("C:", "").Replace('\\', '/');
+ }
+
+ Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
+ .PathWithoutPrefix
+ .Should().Be(expected);
+ }
+
+ [TestMethod]
+ [DataRow(" - ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\asin - 02∕27∕17 00꞉00.m4b", PlatformID.Win32NT)]
+ [DataRow(" - ", @"/foo/bar", ".m4b", @"/foo/bar/asin - 02∕27∕17 00:00.m4b", PlatformID.Unix)]
+ [DataRow(" - ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\asin - 01∕28∕23 00꞉00.m4b", PlatformID.Win32NT)]
+ [DataRow(" - ", @"/foo/bar", ".m4b", @"/foo/bar/asin - 01∕28∕23 00:00.m4b", PlatformID.Unix)]
+ [DataRow(" - ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\asin - 06∕09∕22 00꞉00.m4b", PlatformID.Win32NT)]
+ [DataRow(" - ", @"/foo/bar", ".m4b", @"/foo/bar/asin - 06∕09∕22 00:00.m4b", PlatformID.Unix)]
+ public void DateFormat_illegal(string template, string dirFullPath, string extension, string expected, PlatformID platformID)
+ {
+ if (Environment.OSVersion.Platform == platformID)
+ {
+ Templates.File.HasWarnings(template).Should().BeTrue();
+ Templates.File.HasWarnings(Templates.File.Sanitize(template, Replacements)).Should().BeFalse();
+ Templates.getFileNamingTemplate(GetLibraryBook(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
+ .PathWithoutPrefix
+ .Should().Be(expected);
+
+ }
+ }
+
+
+ [TestMethod]
+ [DataRow(" ", @"C:\foo\bar", ".m4b", @"C:\foo\bar\23-01-28.m4b")]
+ public void DateFormat_null(string template, string dirFullPath, string extension, string expected)
+ {
+ if (Environment.OSVersion.Platform is not PlatformID.Win32NT)
+ {
+ dirFullPath = dirFullPath.Replace("C:", "").Replace('\\', '/');
+ expected = expected.Replace("C:", "").Replace('\\', '/');
+ }
+
+ Templates.getFileNamingTemplate(GetLibraryBookWithNullDates(), template, dirFullPath, extension, Replacements)
+ .GetFilePath(extension)
+ .PathWithoutPrefix
+ .Should().Be(expected);
+
+ }
+
[TestMethod]
[DataRow(@"C:\a\b", @"C:\a\b\foobar.ext", PlatformID.Win32NT)]
[DataRow(@"/a/b", @"/a/b/foobar.ext", PlatformID.Unix)]
public void IfSeries_empty(string directory, string expected, PlatformID platformID)
{
if (Environment.OSVersion.Platform == platformID)
- Templates.getFileNamingTemplate(GetLibraryBook(), "foo<-if series>bar", directory, "ext")
- .GetFilePath(Replacements, ".ext")
+ Templates.getFileNamingTemplate(GetLibraryBook(), "foo<-if series>bar", directory, "ext", Replacements)
+ .GetFilePath(".ext")
.PathWithoutPrefix
.Should().Be(expected);
}
@@ -122,8 +249,8 @@ namespace TemplatesTests
public void IfSeries_no_series(string directory, string expected, PlatformID platformID)
{
if (Environment.OSVersion.Platform == platformID)
- Templates.getFileNamingTemplate(GetLibraryBook(null), "foo---<-if series>bar", directory, "ext")
- .GetFilePath(Replacements, ".ext")
+ Templates.getFileNamingTemplate(GetLibraryBook(null), "foo---<-if series>bar", directory, "ext", Replacements)
+ .GetFilePath(".ext")
.PathWithoutPrefix
.Should().Be(expected);
}
@@ -134,8 +261,8 @@ namespace TemplatesTests
public void IfSeries_with_series(string directory, string expected, PlatformID platformID)
{
if (Environment.OSVersion.Platform == platformID)
- Templates.getFileNamingTemplate(GetLibraryBook(), "foo---<-if series>bar", directory, "ext")
- .GetFilePath(Replacements, ".ext")
+ Templates.getFileNamingTemplate(GetLibraryBook(), "foo---<-if series>bar", directory, "ext", Replacements)
+ .GetFilePath(".ext")
.PathWithoutPrefix
.Should().Be(expected);
}