From d636ceed8e489955fe0caca0b2906be27411b289 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Thu, 21 Oct 2021 14:38:59 -0400 Subject: [PATCH] File naming stuff is (finally) centralized under AudioFileStorageExt --- AaxDecrypter/AaxcDownloadMultiConverter.cs | 6 +- AaxDecrypter/AudiobookDownloadBase.cs | 5 +- AppScaffolding/AppScaffolding.csproj | 2 +- AppScaffolding/LibationScaffolding.cs | 4 +- DataLayer/Utilities/LocalDatabaseInfo.cs | 38 ---------- FileLiberator/AudioFileStorageExt.cs | 69 +++++++++++++++++++ FileLiberator/DownloadDecryptBook.cs | 57 +++++++-------- FileLiberator/DownloadPdf.cs | 2 +- FileManager/FileTemplate.cs | 2 +- FileManager/FileUtility.cs | 15 ---- Libation.sln | 21 ++++-- LibationFileManager/AudibleFileStorage.cs | 36 +++++----- .../AudioFileStorageExtTests.cs | 45 ++++++++++++ .../FileLiberator.Tests.csproj | 24 +++++++ .../FileManager.Tests.csproj | 2 +- .../FileManager.Tests}/FileTemplateTests.cs | 6 +- .../FileManager.Tests}/FileUtilityTests.cs | 31 --------- 17 files changed, 208 insertions(+), 157 deletions(-) delete mode 100644 DataLayer/Utilities/LocalDatabaseInfo.cs create mode 100644 FileLiberator/AudioFileStorageExt.cs create mode 100644 _Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs create mode 100644 _Tests/FileLiberator.Tests/FileLiberator.Tests.csproj rename {FileManager.Tests => _Tests/FileManager.Tests}/FileManager.Tests.csproj (91%) rename {FileManager.Tests => _Tests/FileManager.Tests}/FileTemplateTests.cs (97%) rename {FileManager.Tests => _Tests/FileManager.Tests}/FileUtilityTests.cs (68%) diff --git a/AaxDecrypter/AaxcDownloadMultiConverter.cs b/AaxDecrypter/AaxcDownloadMultiConverter.cs index 494f35eb..3d297f1b 100644 --- a/AaxDecrypter/AaxcDownloadMultiConverter.cs +++ b/AaxDecrypter/AaxcDownloadMultiConverter.cs @@ -13,7 +13,7 @@ namespace AaxDecrypter protected override StepSequence Steps { get; } private Func multipartFileNameCallback { get; } - private static string DefaultMultipartFileName(string outputFileName, int partsPosition, int partsTotal, NewSplitCallback newSplitCallback) + private static string DefaultMultipartFilename(string outputFileName, int partsPosition, int partsTotal, NewSplitCallback newSplitCallback) { var template = Path.ChangeExtension(outputFileName, null) + " - - " + Path.GetExtension(outputFileName); @@ -21,7 +21,7 @@ namespace AaxDecrypter fileTemplate.AddParameterReplacement("chapter", FileUtility.GetSequenceFormatted(partsPosition, partsTotal)); fileTemplate.AddParameterReplacement("title", newSplitCallback?.Chapter?.Title ?? ""); - return fileTemplate.GetFilename(); + return fileTemplate.GetFilePath(); } private static TimeSpan minChapterLength { get; } = TimeSpan.FromSeconds(3); @@ -39,7 +39,7 @@ namespace AaxDecrypter ["Step 2: Download Decrypted Audiobook"] = Step_DownloadAudiobookAsMultipleFilesPerChapter, ["Step 3: Cleanup"] = Step_Cleanup, }; - this.multipartFileNameCallback = multipartFileNameCallback ?? DefaultMultipartFileName; + this.multipartFileNameCallback = multipartFileNameCallback ?? DefaultMultipartFilename; } /* diff --git a/AaxDecrypter/AudiobookDownloadBase.cs b/AaxDecrypter/AudiobookDownloadBase.cs index 5d1b9b99..8a20b5c5 100644 --- a/AaxDecrypter/AudiobookDownloadBase.cs +++ b/AaxDecrypter/AudiobookDownloadBase.cs @@ -30,8 +30,7 @@ namespace AaxDecrypter protected abstract StepSequence Steps { get; } private NetworkFileStreamPersister nfsPersister; - private string cacheDir { get; } - private string jsonDownloadState => Path.Combine(cacheDir, Path.ChangeExtension(OutputFileName, ".json")); + private string jsonDownloadState { get; } private string tempFile => Path.ChangeExtension(jsonDownloadState, ".tmp"); protected AudiobookDownloadBase(string outFileName, string cacheDirectory, DownloadLicense dlLic) @@ -44,7 +43,7 @@ namespace AaxDecrypter if (!Directory.Exists(cacheDirectory)) throw new DirectoryNotFoundException($"Directory does not exist: {nameof(cacheDirectory)}"); - cacheDir = cacheDirectory; + jsonDownloadState = Path.Combine(cacheDirectory, Path.ChangeExtension(OutputFileName, ".json")); DownloadLicense = ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic)); diff --git a/AppScaffolding/AppScaffolding.csproj b/AppScaffolding/AppScaffolding.csproj index de90058b..e8098a05 100644 --- a/AppScaffolding/AppScaffolding.csproj +++ b/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> - <Version>6.2.7.3</Version> + <Version>6.2.8.1</Version> </PropertyGroup> <ItemGroup> diff --git a/AppScaffolding/LibationScaffolding.cs b/AppScaffolding/LibationScaffolding.cs index 4088a059..53927b24 100644 --- a/AppScaffolding/LibationScaffolding.cs +++ b/AppScaffolding/LibationScaffolding.cs @@ -211,10 +211,10 @@ namespace AppScaffolding config.InProgress, - DownloadsInProgressDirectory = AudibleFileStorage.DownloadsInProgressDirectory, + AudibleFileStorage.DownloadsInProgressDirectory, DownloadsInProgressFiles = Directory.EnumerateFiles(AudibleFileStorage.DownloadsInProgressDirectory).Count(), - DecryptInProgressDirectory = AudibleFileStorage.DecryptInProgressDirectory, + AudibleFileStorage.DecryptInProgressDirectory, DecryptInProgressFiles = Directory.EnumerateFiles(AudibleFileStorage.DecryptInProgressDirectory).Count(), }); } diff --git a/DataLayer/Utilities/LocalDatabaseInfo.cs b/DataLayer/Utilities/LocalDatabaseInfo.cs deleted file mode 100644 index cab98cb7..00000000 --- a/DataLayer/Utilities/LocalDatabaseInfo.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace DataLayer.Utilities -{ - public static class LocalDatabaseInfo - { - public static List<string> GetLocalDBInstances() - { - // Start the child process. - using var p = new System.Diagnostics.Process - { - StartInfo = new System.Diagnostics.ProcessStartInfo - { - UseShellExecute = false, - RedirectStandardOutput = true, - FileName = "cmd.exe", - Arguments = "/C sqllocaldb info", - CreateNoWindow = true, - WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden - } - }; - p.Start(); - var output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); - - // if LocalDb is not installed then it will return that 'sqllocaldb' is not recognized as an internal or external command operable program or batch file - return string.IsNullOrWhiteSpace(output) || output.Contains("not recognized") - ? new List<string>() - : output - .Split(new string[] { Environment.NewLine }, StringSplitOptions.None) - .Select(i => i.Trim()) - .Where(i => !string.IsNullOrEmpty(i)) - .ToList(); - } - } -} diff --git a/FileLiberator/AudioFileStorageExt.cs b/FileLiberator/AudioFileStorageExt.cs new file mode 100644 index 00000000..6c3c1ea1 --- /dev/null +++ b/FileLiberator/AudioFileStorageExt.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using DataLayer; +using Dinah.Core; +using FileManager; +using LibationFileManager; + +namespace FileLiberator +{ + public static class AudioFileStorageExt + { + public static string MultipartFilename(this AudioFileStorage _, string outputFileName, int partsPosition, int partsTotal, AAXClean.NewSplitCallback newSplitCallback) + => MultipartFilename(outputFileName, partsPosition, partsTotal, newSplitCallback); + public static string MultipartFilename(string outputFileName, int partsPosition, int partsTotal, AAXClean.NewSplitCallback newSplitCallback) + { + var template = Path.ChangeExtension(outputFileName, null) + " - <chapter> - <title>" + Path.GetExtension(outputFileName); + + var fileTemplate = new FileTemplate(template) { IllegalCharacterReplacements = " " }; + fileTemplate.AddParameterReplacement("chapter", FileUtility.GetSequenceFormatted(partsPosition, partsTotal)); + fileTemplate.AddParameterReplacement("title", newSplitCallback?.Chapter?.Title ?? ""); + + return fileTemplate.GetFilePath(); + } + + public static string GetInProgressFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension) + => GetInProgressFilename(libraryBook, extension); + public static string GetInProgressFilename(LibraryBook libraryBook, string extension) + => GetValidFilename(AudibleFileStorage.DecryptInProgressDirectory, libraryBook.Book.Title, extension, libraryBook); + + public static string GetBooksDirectoryFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension) + => GetBooksDirectoryFilename(libraryBook, extension); + public static string GetBooksDirectoryFilename(LibraryBook libraryBook, string extension) + => GetValidFilename(AudibleFileStorage.BooksDirectory, libraryBook.Book.Title, extension, libraryBook); + + public static string CreateDestinationDirectory(this AudioFileStorage _, LibraryBook libraryBook) + => CreateDestinationDirectory(libraryBook); + public static string CreateDestinationDirectory(LibraryBook libraryBook) + { + var title = libraryBook.Book.Title; + + // to prevent the paths from getting too long, we don't need after the 1st ":" for the folder + var underscoreIndex = title.IndexOf(':'); + var titleDir + = underscoreIndex < 4 + ? title + : title.Substring(0, underscoreIndex); + var destinationDir = GetValidFilename(AudibleFileStorage.BooksDirectory, titleDir, null, libraryBook); + Directory.CreateDirectory(destinationDir); + return destinationDir; + } + + public static string GetValidFilename(string dirFullPath, string filename, string extension, LibraryBook libraryBook) + { + ArgumentValidator.EnsureNotNullOrWhiteSpace(dirFullPath, nameof(dirFullPath)); + ArgumentValidator.EnsureNotNullOrWhiteSpace(filename, nameof(filename)); + + var template = $"<title> [<id>]"; + + var fullfilename = Path.Combine(dirFullPath, template + FileUtility.GetStandardizedExtension(extension)); + + var fileTemplate = new FileTemplate(fullfilename) { IllegalCharacterReplacements = "_" }; + fileTemplate.AddParameterReplacement("title", filename); + fileTemplate.AddParameterReplacement("id", libraryBook.Book.AudibleProductId); + return fileTemplate.GetFilePath(); + } + } +} diff --git a/FileLiberator/DownloadDecryptBook.cs b/FileLiberator/DownloadDecryptBook.cs index 2ce82168..42d0bce7 100644 --- a/FileLiberator/DownloadDecryptBook.cs +++ b/FileLiberator/DownloadDecryptBook.cs @@ -64,7 +64,7 @@ namespace FileLiberator return new StatusHandler { "Decrypt failed" }; // moves new files from temp dir to final dest - var movedAudioFile = moveFilesToBooksDir(libraryBook.Book, entries); + var movedAudioFile = moveFilesToBooksDir(libraryBook, entries); // decrypt failed if (!movedAudioFile) @@ -114,14 +114,14 @@ namespace FileLiberator foreach (var chap in contentLic.ContentMetadata?.ChapterInfo?.Chapters) audiobookDlLic.ChapterInfo.AddChapter(chap.Title, TimeSpan.FromMilliseconds(chap.LengthMs)); } - - var outFileName = FileUtility.GetValidFilename(AudibleFileStorage.DecryptInProgressDirectory, libraryBook.Book.Title, outputFormat.ToString().ToLower(), libraryBook.Book.AudibleProductId); + + var outFileName = AudibleFileStorage.Audio.GetInProgressFilename(libraryBook, outputFormat.ToString().ToLower()); var cacheDir = AudibleFileStorage.DownloadsInProgressDirectory; abDownloader = contentLic.DrmType != AudibleApi.Common.DrmType.Adrm ? new UnencryptedAudiobookDownloader(outFileName, cacheDir, audiobookDlLic) - : Configuration.Instance.SplitFilesByChapter ? new AaxcDownloadMultiConverter(outFileName, cacheDir, audiobookDlLic, outputFormat) + : Configuration.Instance.SplitFilesByChapter ? new AaxcDownloadMultiConverter(outFileName, cacheDir, audiobookDlLic, outputFormat, AudibleFileStorage.Audio.MultipartFilename) : new AaxcDownloadSingleConverter(outFileName, cacheDir, audiobookDlLic, outputFormat); abDownloader.DecryptProgressUpdate += (_, progress) => OnStreamingProgressChanged(progress); abDownloader.DecryptTimeRemaining += (_, remaining) => OnStreamingTimeRemaining(remaining); @@ -173,43 +173,34 @@ namespace FileLiberator /// <summary>Move new files to 'Books' directory</summary> /// <returns>True if audiobook file(s) were successfully created and can be located on disk. Else false.</returns> - private static bool moveFilesToBooksDir(Book book, List<FilePathCache.CacheEntry> entries) + private static bool moveFilesToBooksDir(LibraryBook libraryBook, List<FilePathCache.CacheEntry> entries) { // create final directory. move each file into it - var title = book.Title; - var asin = book.AudibleProductId; - // to prevent the paths from getting too long, we don't need after the 1st ":" for the folder - var underscoreIndex = title.IndexOf(':'); - var titleDir - = underscoreIndex < 4 - ? title - : title.Substring(0, underscoreIndex); - var destinationDir = FileUtility.GetValidFilename(AudibleFileStorage.BooksDirectory, titleDir, null, asin); - Directory.CreateDirectory(destinationDir); + var destinationDir = AudibleFileStorage.Audio.CreateDestinationDirectory(libraryBook); - FilePathCache.CacheEntry getFirstAudio() => entries.FirstOrDefault(f => f.FileType == FileType.Audio); + FilePathCache.CacheEntry getFirstAudio() => entries.FirstOrDefault(f => f.FileType == FileType.Audio); - if (getFirstAudio() == default) - return false; + if (getFirstAudio() == default) + return false; - for (var i = 0; i < entries.Count; i++) - { - var entry = entries[i]; + for (var i = 0; i < entries.Count; i++) + { + var entry = entries[i]; - var realDest = FileUtility.SaferMoveToValidPath(entry.Path, Path.Combine(destinationDir, Path.GetFileName(entry.Path))); - FilePathCache.Insert(book.AudibleProductId, realDest); + var realDest = FileUtility.SaferMoveToValidPath(entry.Path, Path.Combine(destinationDir, Path.GetFileName(entry.Path))); + FilePathCache.Insert(libraryBook.Book.AudibleProductId, realDest); - // propogate corrected path. Must update cache with corrected path. Also want updated path for cue file (after this for-loop) - entries[i] = entry with { Path = realDest }; - } + // propogate corrected path. Must update cache with corrected path. Also want updated path for cue file (after this for-loop) + entries[i] = entry with { Path = realDest }; + } - var cue = entries.FirstOrDefault(f => f.FileType == FileType.Cue); - if (cue != default) - Cue.UpdateFileName(cue.Path, getFirstAudio().Path); + var cue = entries.FirstOrDefault(f => f.FileType == FileType.Cue); + if (cue != default) + Cue.UpdateFileName(cue.Path, getFirstAudio().Path); - AudibleFileStorage.Audio.Refresh(); + AudibleFileStorage.Audio.Refresh(); - return true; - } - } + return true; + } + } } diff --git a/FileLiberator/DownloadPdf.cs b/FileLiberator/DownloadPdf.cs index 9640a6b3..18d27114 100644 --- a/FileLiberator/DownloadPdf.cs +++ b/FileLiberator/DownloadPdf.cs @@ -47,7 +47,7 @@ namespace FileLiberator if (existingPath != null) return Path.Combine(existingPath, Path.GetFileName(file)); - return FileUtility.GetValidFilename(AudibleFileStorage.BooksDirectory, libraryBook.Book.Title, Path.GetExtension(file), libraryBook.Book.AudibleProductId); + return AudibleFileStorage.Audio.GetBooksDirectoryFilename(libraryBook, Path.GetExtension(file)); } private static string getdownloadUrl(LibraryBook libraryBook) diff --git a/FileManager/FileTemplate.cs b/FileManager/FileTemplate.cs index 940ddf3d..138bbfc5 100644 --- a/FileManager/FileTemplate.cs +++ b/FileManager/FileTemplate.cs @@ -28,7 +28,7 @@ namespace FileManager public string IllegalCharacterReplacements { get; set; } /// <summary>Generate a valid path for this file or directory</summary> - public string GetFilename() + public string GetFilePath() { var filename = Template; diff --git a/FileManager/FileUtility.cs b/FileManager/FileUtility.cs index 8d57b447..163d29f6 100644 --- a/FileManager/FileUtility.cs +++ b/FileManager/FileUtility.cs @@ -20,21 +20,6 @@ namespace FileManager ? (extension ?? "")?.Trim() : '.' + extension.Trim('.'); - public static string GetValidFilename(string dirFullPath, string filename, string extension, string metadataSuffix) - { - ArgumentValidator.EnsureNotNullOrWhiteSpace(dirFullPath, nameof(dirFullPath)); - ArgumentValidator.EnsureNotNullOrWhiteSpace(filename, nameof(filename)); - - var template = $"<title> [<id>]"; - - var fullfilename = Path.Combine(dirFullPath, template + GetStandardizedExtension(extension)); - - var fileTemplate = new FileTemplate(fullfilename) { IllegalCharacterReplacements = "_" }; - fileTemplate.AddParameterReplacement("title", filename); - fileTemplate.AddParameterReplacement("id", metadataSuffix); - return fileTemplate.GetFilename(); - } - /// <summary> /// Return position with correct number of leading zeros. /// <br />- 2 of 9 => "2" diff --git a/Libation.sln b/Libation.sln index 15c1b43b..6729b1cd 100644 --- a/Libation.sln +++ b/Libation.sln @@ -56,10 +56,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppScaffolding", "AppScaffo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileManager", "FileManager\FileManager.csproj", "{E86014F9-E4B3-4CD4-A210-2B3DB571DD86}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileManager.Tests", "FileManager.Tests\FileManager.Tests.csproj", "{3B58450C-FBDA-4D48-8418-A3C750596D7D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudibleUtilities.Tests", "_Tests\AudibleUtilities.Tests\AudibleUtilities.Tests.csproj", "{788294BE-0D8E-40D4-9CEE-67896FBB52CE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileLiberator.Tests", "_Tests\FileLiberator.Tests\FileLiberator.Tests.csproj", "{5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileManager.Tests", "_Tests\FileManager.Tests\FileManager.Tests.csproj", "{F2E04270-4551-41C4-99FF-E7125BED708C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -122,14 +124,18 @@ Global {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Debug|Any CPU.Build.0 = Debug|Any CPU {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Release|Any CPU.ActiveCfg = Release|Any CPU {E86014F9-E4B3-4CD4-A210-2B3DB571DD86}.Release|Any CPU.Build.0 = Release|Any CPU - {3B58450C-FBDA-4D48-8418-A3C750596D7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B58450C-FBDA-4D48-8418-A3C750596D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B58450C-FBDA-4D48-8418-A3C750596D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B58450C-FBDA-4D48-8418-A3C750596D7D}.Release|Any CPU.Build.0 = Release|Any CPU {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {788294BE-0D8E-40D4-9CEE-67896FBB52CE}.Release|Any CPU.Build.0 = Release|Any CPU + {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E}.Release|Any CPU.Build.0 = Release|Any CPU + {F2E04270-4551-41C4-99FF-E7125BED708C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2E04270-4551-41C4-99FF-E7125BED708C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2E04270-4551-41C4-99FF-E7125BED708C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2E04270-4551-41C4-99FF-E7125BED708C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -149,8 +155,9 @@ Global {428163C3-D558-4914-B570-A92069521877} = {8679CAC8-9164-4007-BDD2-F004810EDA14} {595E7C4D-506D-486D-98B7-5FDDF398D033} = {8679CAC8-9164-4007-BDD2-F004810EDA14} {E86014F9-E4B3-4CD4-A210-2B3DB571DD86} = {43E3ACB3-E0BC-4370-8DBB-E3720C8C8FD1} - {3B58450C-FBDA-4D48-8418-A3C750596D7D} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} {788294BE-0D8E-40D4-9CEE-67896FBB52CE} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} + {5B8FC827-BF58-4CB1-A59E-BDEB9C62A05E} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} + {F2E04270-4551-41C4-99FF-E7125BED708C} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {615E00ED-BAEF-4E8E-A92A-9B82D87942A9} diff --git a/LibationFileManager/AudibleFileStorage.cs b/LibationFileManager/AudibleFileStorage.cs index 6e6a5be5..0b18404b 100644 --- a/LibationFileManager/AudibleFileStorage.cs +++ b/LibationFileManager/AudibleFileStorage.cs @@ -66,8 +66,26 @@ namespace LibationFileManager #endregion } + internal class AaxcFileStorage : AudibleFileStorage + { + internal AaxcFileStorage() : base(FileType.AAXC) { } + + protected override string GetFilePathCustom(string productId) + { + var regex = GetBookSearchRegex(productId); + return Directory + .EnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories) + .FirstOrDefault(s => regex.IsMatch(s)); + } + + public bool Exists(string productId) => GetFilePath(productId) != null; + } + public class AudioFileStorage : AudibleFileStorage { + internal AudioFileStorage() : base(FileType.Audio) + => BookDirectoryFiles ??= new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories); + private static BackgroundFileSystem BookDirectoryFiles { get; set; } private static object bookDirectoryFilesLocker { get; } = new(); protected override string GetFilePathCustom(string productId) @@ -81,26 +99,8 @@ namespace LibationFileManager return BookDirectoryFiles.FindFile(regex); } - internal AudioFileStorage() : base(FileType.Audio) - => BookDirectoryFiles ??= new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories); - public void Refresh() => BookDirectoryFiles.RefreshFiles(); public string GetPath(string productId) => GetFilePath(productId); } - - internal class AaxcFileStorage : AudibleFileStorage - { - protected override string GetFilePathCustom(string productId) - { - var regex = GetBookSearchRegex(productId); - return Directory - .EnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories) - .FirstOrDefault(s => regex.IsMatch(s)); - } - - internal AaxcFileStorage() : base(FileType.AAXC) { } - - public bool Exists(string productId) => GetFilePath(productId) != null; - } } diff --git a/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs b/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs new file mode 100644 index 00000000..7b8b4efe --- /dev/null +++ b/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Dinah.Core; +using FileLiberator; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace AudioFileStorageExtTests +{ + [TestClass] + public class GetValidFilename + { + private DataLayer.LibraryBook GetLibraryBook(string asin) + { + var book = new DataLayer.Book(new DataLayer.AudibleProductId(asin), "title", "desc", 1, DataLayer.ContentType.Product, new List<DataLayer.Contributor> { new DataLayer.Contributor("author") }, new List<DataLayer.Contributor> { new DataLayer.Contributor("narrator") }, new DataLayer.Category(new DataLayer.AudibleCategoryId("seriesId") , "name"), "us"); + var libraryBook = new DataLayer.LibraryBook(book, DateTime.Now, "my us"); + return libraryBook; + } + + [TestMethod] + [DataRow(null, "name", "ext", "suffix")] + [DataRow(@"C:\", null, "ext", "suffix")] + [ExpectedException(typeof(ArgumentNullException))] + public void arg_null_exception(string dirFullPath, string filename, string extension, string metadataSuffix) + => AudioFileStorageExt.GetValidFilename(dirFullPath, filename, extension, GetLibraryBook(metadataSuffix)); + + [TestMethod] + [DataRow("", "name", "ext", "suffix")] + [DataRow(" ", "name", "ext", "suffix")] + [DataRow(@"C:\", "", "ext", "suffix")] + [DataRow(@"C:\", " ", "ext", "suffix")] + [ExpectedException(typeof(ArgumentException))] + public void arg_exception(string dirFullPath, string filename, string extension, string metadataSuffix) + => AudioFileStorageExt.GetValidFilename(dirFullPath, filename, extension, GetLibraryBook(metadataSuffix)); + + [TestMethod] + public void null_extension() => Tests(@"C:\foo\bar", "my file", null, "meta", @"C:\foo\bar\my file [meta]"); + + [TestMethod] + [DataRow(@"C:\foo\bar", "my file", "txt", "my id", @"C:\foo\bar\my file [my id].txt")] + public void Tests(string dirFullPath, string filename, string extension, string metadataSuffix, string expected) + => AudioFileStorageExt.GetValidFilename(dirFullPath, filename, extension, GetLibraryBook(metadataSuffix)).Should().Be(expected); + } +} diff --git a/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj b/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj new file mode 100644 index 00000000..62cbcbfe --- /dev/null +++ b/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj @@ -0,0 +1,24 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net5.0</TargetFramework> + + <IsPackable>false</IsPackable> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="FluentAssertions" Version="6.1.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> + <PackageReference Include="MSTest.TestAdapter" Version="2.2.7" /> + <PackageReference Include="MSTest.TestFramework" Version="2.2.7" /> + <PackageReference Include="coverlet.collector" Version="3.1.0"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\FileLiberator\FileLiberator.csproj" /> + </ItemGroup> + +</Project> diff --git a/FileManager.Tests/FileManager.Tests.csproj b/_Tests/FileManager.Tests/FileManager.Tests.csproj similarity index 91% rename from FileManager.Tests/FileManager.Tests.csproj rename to _Tests/FileManager.Tests/FileManager.Tests.csproj index ec4c77ee..9e7514f3 100644 --- a/FileManager.Tests/FileManager.Tests.csproj +++ b/_Tests/FileManager.Tests/FileManager.Tests.csproj @@ -18,7 +18,7 @@ </ItemGroup> <ItemGroup> - <ProjectReference Include="..\FileManager\FileManager.csproj" /> + <ProjectReference Include="..\..\FileManager\FileManager.csproj" /> </ItemGroup> </Project> diff --git a/FileManager.Tests/FileTemplateTests.cs b/_Tests/FileManager.Tests/FileTemplateTests.cs similarity index 97% rename from FileManager.Tests/FileTemplateTests.cs rename to _Tests/FileManager.Tests/FileTemplateTests.cs index 061b50c0..5567795a 100644 --- a/FileManager.Tests/FileTemplateTests.cs +++ b/_Tests/FileManager.Tests/FileTemplateTests.cs @@ -10,7 +10,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FileTemplateTests { [TestClass] - public class GetFilename + public class GetFilePath { [TestMethod] public void equiv_GetValidFilename() @@ -58,7 +58,7 @@ namespace FileTemplateTests var fileTemplate = new FileTemplate(fullfilename) { IllegalCharacterReplacements = "_" }; fileTemplate.AddParameterReplacement("title", filename); fileTemplate.AddParameterReplacement("id", metadataSuffix); - return fileTemplate.GetFilename(); + return fileTemplate.GetFilePath(); } [TestMethod] @@ -102,7 +102,7 @@ namespace FileTemplateTests fileTemplate.AddParameterReplacement("chapter", chapterCountLeadingZeros); fileTemplate.AddParameterReplacement("title", suffix); - return fileTemplate.GetFilename(); + return fileTemplate.GetFilePath(); } } } diff --git a/FileManager.Tests/FileUtilityTests.cs b/_Tests/FileManager.Tests/FileUtilityTests.cs similarity index 68% rename from FileManager.Tests/FileUtilityTests.cs rename to _Tests/FileManager.Tests/FileUtilityTests.cs index 637597f0..1eabebc3 100644 --- a/FileManager.Tests/FileUtilityTests.cs +++ b/_Tests/FileManager.Tests/FileUtilityTests.cs @@ -54,37 +54,6 @@ namespace FileUtilityTests public void ReplacementTests(string inStr, string replacement, string outStr) => FileUtility.GetSafeFileName(inStr, replacement).Should().Be(outStr); } - [TestClass] - public class GetValidFilename - { - [TestMethod] - [DataRow(null, "name", "ext", "suffix")] - [DataRow(@"C:\", null, "ext", "suffix")] - [ExpectedException(typeof(ArgumentNullException))] - public void arg_null_exception(string dirFullPath, string filename, string extension, string metadataSuffix) - => FileUtility.GetValidFilename(dirFullPath, filename, extension, metadataSuffix); - - [TestMethod] - [DataRow("", "name", "ext", "suffix")] - [DataRow(" ", "name", "ext", "suffix")] - [DataRow(@"C:\", "", "ext", "suffix")] - [DataRow(@"C:\", " ", "ext", "suffix")] - [ExpectedException(typeof(ArgumentException))] - public void arg_exception(string dirFullPath, string filename, string extension, string metadataSuffix) - => FileUtility.GetValidFilename(dirFullPath, filename, extension, metadataSuffix); - - [TestMethod] - public void null_extension() => Tests(@"C:\foo\bar", "my file", null, "meta", @"C:\foo\bar\my file [meta]"); - [TestMethod] - public void null_metadataSuffix() => Tests(@"C:\foo\bar", "my file", "txt", null, @"C:\foo\bar\my file [].txt"); - - [TestMethod] - [DataRow(@"C:\foo\bar", "my file", "txt", "my id", @"C:\foo\bar\my file [my id].txt")] - [DataRow(@"C:\foo\bar", "my file", "txt", "", @"C:\foo\bar\my file [].txt")] - public void Tests(string dirFullPath, string filename, string extension, string metadataSuffix, string expected) - => FileUtility.GetValidFilename(dirFullPath, filename, extension, metadataSuffix).Should().Be(expected); - } - [TestClass] public class GetSequenceFormatted {