Add unicode replacements for illegal characters

This commit is contained in:
Michael Bucari-Tovo 2022-06-19 16:57:44 -06:00
parent 45c5efffbd
commit 490d121db3
12 changed files with 71 additions and 58 deletions

View File

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AAXClean.Codecs" Version="0.2.8" />
<PackageReference Include="AAXClean.Codecs" Version="0.2.9" />
</ItemGroup>
<ItemGroup>

View File

@ -42,10 +42,10 @@ namespace AaxDecrypter
var outDir = Path.GetDirectoryName(OutputFileName);
if (!Directory.Exists(outDir))
throw new DirectoryNotFoundException($"Directory does not exist: {nameof(outDir)}");
Directory.CreateDirectory(outDir);
if (!Directory.Exists(cacheDirectory))
throw new DirectoryNotFoundException($"Directory does not exist: {nameof(cacheDirectory)}");
Directory.CreateDirectory(cacheDirectory);
jsonDownloadState = Path.Combine(cacheDirectory, Path.GetFileName(Path.ChangeExtension(OutputFileName, ".json")));
TempFilePath = Path.ChangeExtension(jsonDownloadState, ".aaxc");

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AAXClean;
using AAXClean.Codecs;
@ -19,12 +20,12 @@ namespace FileLiberator
private long fileSize;
private static string Mp3FileName(string m4bPath) => Path.ChangeExtension(m4bPath ?? "", ".mp3");
public override Task CancelAsync() => m4bBook?.CancelAsync();
public override Task CancelAsync() => m4bBook?.CancelAsync() ?? Task.CompletedTask;
public static bool ValidateMp3(LibraryBook libraryBook)
{
var path = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId);
return path?.ToString()?.ToLower()?.EndsWith(".m4b") == true && !File.Exists(Mp3FileName(path));
var paths = AudibleFileStorage.Audio.GetPaths(libraryBook.Book.AudibleProductId);
return paths.Any(path => path?.ToString()?.ToLower()?.EndsWith(".m4b") == true && !File.Exists(Mp3FileName(path)));
}
public override bool Validate(LibraryBook libraryBook) => ValidateMp3(libraryBook);
@ -35,33 +36,38 @@ namespace FileLiberator
try
{
var m4bPath = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId);
m4bBook = new Mp4File(m4bPath, FileAccess.Read);
m4bBook.ConversionProgressUpdate += M4bBook_ConversionProgressUpdate;
var m4bPaths = AudibleFileStorage.Audio.GetPaths(libraryBook.Book.AudibleProductId);
fileSize = m4bBook.InputStream.Length;
foreach (var m4bPath in m4bPaths)
{
var proposedMp3Path = Mp3FileName(m4bPath);
if (File.Exists(proposedMp3Path) || !File.Exists(m4bPath)) continue;
OnTitleDiscovered(m4bBook.AppleTags.Title);
OnAuthorsDiscovered(m4bBook.AppleTags.FirstAuthor);
OnNarratorsDiscovered(m4bBook.AppleTags.Narrator);
OnCoverImageDiscovered(m4bBook.AppleTags.Cover);
m4bBook = new Mp4File(m4bPath, FileAccess.Read);
m4bBook.ConversionProgressUpdate += M4bBook_ConversionProgressUpdate;
using var mp3File = File.OpenWrite(Path.GetTempFileName());
var lameConfig = GetLameOptions(Configuration.Instance);
var result = await Task.Run(() => m4bBook.ConvertToMp3(mp3File, lameConfig));
m4bBook.InputStream.Close();
mp3File.Close();
fileSize = m4bBook.InputStream.Length;
var proposedMp3Path = Mp3FileName(m4bPath);
var realMp3Path = FileUtility.SaferMoveToValidPath(mp3File.Name, proposedMp3Path);
OnFileCreated(libraryBook, realMp3Path);
OnTitleDiscovered(m4bBook.AppleTags.Title);
OnAuthorsDiscovered(m4bBook.AppleTags.FirstAuthor);
OnNarratorsDiscovered(m4bBook.AppleTags.Narrator);
OnCoverImageDiscovered(m4bBook.AppleTags.Cover);
if (result == ConversionResult.Failed)
return new StatusHandler { "Conversion failed" };
else if (result == ConversionResult.Cancelled)
return new StatusHandler { "Cancelled" };
else
return new StatusHandler();
using var mp3File = File.OpenWrite(Path.GetTempFileName());
var lameConfig = GetLameOptions(Configuration.Instance);
var result = await Task.Run(() => m4bBook.ConvertToMp3(mp3File, lameConfig));
m4bBook.InputStream.Close();
mp3File.Close();
var realMp3Path = FileUtility.SaferMoveToValidPath(mp3File.Name, proposedMp3Path);
OnFileCreated(libraryBook, realMp3Path);
if (result == ConversionResult.Failed)
return new StatusHandler { "Conversion failed" };
else if (result == ConversionResult.Cancelled)
return new StatusHandler { "Cancelled" };
}
return new StatusHandler();
}
finally
{

View File

@ -21,7 +21,7 @@ namespace FileLiberator
public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists();
public override Task CancelAsync() => abDownloader?.CancelAsync();
public override Task CancelAsync() => abDownloader?.CancelAsync() ?? Task.CompletedTask;
public override async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
{

View File

@ -32,12 +32,18 @@ namespace FileManager
Init();
}
public string FindFile(System.Text.RegularExpressions.Regex regex)
public LongPath FindFile(System.Text.RegularExpressions.Regex regex)
{
lock (fsCacheLocker)
return fsCache.FirstOrDefault(s => regex.IsMatch(s));
}
public List<LongPath> FindFiles(System.Text.RegularExpressions.Regex regex)
{
lock (fsCacheLocker)
return fsCache.Where(s => regex.IsMatch(s)).ToList();
}
public void RefreshFiles()
{
lock (fsCacheLocker)

View File

@ -90,9 +90,9 @@ namespace FileManager
var pathNoPrefix = path.PathWithoutPrefix;
pathNoPrefix = pathNoPrefix?.Replace(':', '')?.Replace('?', '︖')?.Replace('*', '');
pathNoPrefix = replaceInvalidChars(pathNoPrefix, illegalCharacterReplacements);
pathNoPrefix = standardizeSlashes(pathNoPrefix);
pathNoPrefix = replaceColons(pathNoPrefix, illegalCharacterReplacements);
pathNoPrefix = removeDoubleSlashes(pathNoPrefix);
return pathNoPrefix;
@ -107,24 +107,6 @@ namespace FileManager
private static string replaceInvalidChars(string path, string illegalCharacterReplacements)
=> string.Join(illegalCharacterReplacements ?? "", path.Split(invalidChars));
private static string standardizeSlashes(string path)
=> path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
private static string replaceColons(string path, string illegalCharacterReplacements)
{
// replace all colons except within the first 2 chars
var builder = new System.Text.StringBuilder();
for (var i = 0; i < path.Length; i++)
{
var c = path[i];
if (i >= 2 && c == ':')
builder.Append(illegalCharacterReplacements);
else
builder.Append(c);
}
return builder.ToString();
}
private static string removeDoubleSlashes(string path)
{
if (path.Length < 2)

View File

@ -27,7 +27,7 @@ namespace FileManager
//File I/O functions in the Windows API convert "/" to "\" as part of converting
//the name to an NT-style name, except when using the "\\?\" prefix
path = path.Replace('/', '\\');
path = path.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
if (path.StartsWith(LONG_PATH_PREFIX))
return new LongPath { Path = path };

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -9,6 +10,7 @@ namespace LibationFileManager
public abstract class AudibleFileStorage
{
protected abstract LongPath GetFilePathCustom(string productId);
protected abstract List<LongPath> GetFilePathsCustom(string productId);
#region static
public static LongPath DownloadsInProgressDirectory => Directory.CreateDirectory(Path.Combine(Configuration.Instance.InProgress, "DownloadsInProgress")).FullName;
@ -57,6 +59,9 @@ namespace LibationFileManager
return firstOrNull;
}
public List<LongPath> GetPaths(string productId)
=> GetFilePathsCustom(productId);
protected Regex GetBookSearchRegex(string productId)
{
var pattern = string.Format(regexTemplate, productId);
@ -70,11 +75,14 @@ namespace LibationFileManager
internal AaxcFileStorage() : base(FileType.AAXC) { }
protected override LongPath GetFilePathCustom(string productId)
=> GetFilePathsCustom(productId).FirstOrDefault();
protected override List<LongPath> GetFilePathsCustom(string productId)
{
var regex = GetBookSearchRegex(productId);
return FileUtility
.SaferEnumerateFiles(DownloadsInProgressDirectory, "*.*", SearchOption.AllDirectories)
.FirstOrDefault(s => regex.IsMatch(s));
.Where(s => regex.IsMatch(s)).ToList();
}
public bool Exists(string productId) => GetFilePath(productId) is not null;
@ -87,7 +95,11 @@ namespace LibationFileManager
private static BackgroundFileSystem BookDirectoryFiles { get; set; }
private static object bookDirectoryFilesLocker { get; } = new();
protected override LongPath GetFilePathCustom(string productId)
=> GetFilePathsCustom(productId).FirstOrDefault();
protected override List<LongPath> GetFilePathsCustom(string productId)
{
// If user changed the BooksDirectory: reinitialize
lock (bookDirectoryFilesLocker)
@ -95,11 +107,12 @@ namespace LibationFileManager
BookDirectoryFiles = new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
var regex = GetBookSearchRegex(productId);
return BookDirectoryFiles.FindFile(regex);
return BookDirectoryFiles.FindFiles(regex);
}
public void Refresh() => BookDirectoryFiles.RefreshFiles();
public LongPath GetPath(string productId) => GetFilePath(productId);
}
}
}

View File

@ -38,7 +38,7 @@ namespace LibationWinForms
{
SetQueueCollapseState(false);
await Task.Run(() => processBookQueue1.AddConvertMp3(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking()
.Where(lb => lb.Book.UserDefinedItem.BookStatus is DataLayer.LiberatedStatus.Liberated)));
.Where(lb => lb.Book.UserDefinedItem.BookStatus is DataLayer.LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product)));
}
//Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing.
}

View File

@ -43,6 +43,12 @@
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Dialogs\SettingsDialog.*.cs">
<DependentUpon>Dialogs\SettingsDialog.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">

View File

@ -138,7 +138,7 @@ namespace LibationWinForms.ProcessQueue
return Result;
}
public async Task Cancel()
public async Task CancelAsync()
{
try
{

View File

@ -212,7 +212,7 @@ namespace LibationWinForms.ProcessQueue
private void cancelAllBtn_Click(object sender, EventArgs e)
{
Queue.ClearQueue();
Queue.Current?.Cancel();
Queue.Current?.CancelAsync();
virtualFlowControl2.VirtualControlCount = Queue.Count;
UpdateAllControls();
}
@ -331,7 +331,7 @@ namespace LibationWinForms.ProcessQueue
ProcessBook item = Queue[queueIndex];
if (buttonName == nameof(panelClicked.cancelBtn))
{
await item.Cancel();
await item.CancelAsync();
Queue.RemoveQueued(item);
virtualFlowControl2.VirtualControlCount = Queue.Count;
}