diff --git a/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs index 598de80e..688b845b 100644 --- a/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/LocateAudiobooksDialog.axaml.cs @@ -83,7 +83,7 @@ namespace LibationAvalonia.Dialogs using var context = DbContexts.GetContext(); - await foreach (var book in AudioFileLocator.FindAudiobooks(uri.LocalPath, tokenSource.Token)) + await foreach (var book in AudioFileStorage.FindAudiobooksAsync(uri.LocalPath, tokenSource.Token)) { try { diff --git a/Source/LibationFileManager/AudibleFileStorage.cs b/Source/LibationFileManager/AudibleFileStorage.cs index f2cbda41..1cb587aa 100644 --- a/Source/LibationFileManager/AudibleFileStorage.cs +++ b/Source/LibationFileManager/AudibleFileStorage.cs @@ -2,7 +2,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Text.RegularExpressions; +using Dinah.Core; +using System.Threading.Tasks; +using System.Threading; using FileManager; namespace LibationFileManager @@ -104,8 +108,14 @@ namespace LibationFileManager private static BackgroundFileSystem BookDirectoryFiles { get; set; } private static object bookDirectoryFilesLocker { get; } = new(); + private static EnumerationOptions enumerationOptions { get; } = new() + { + RecurseSubdirectories = true, + IgnoreInaccessible = true, + MatchCasing = MatchCasing.CaseInsensitive + }; - protected override LongPath GetFilePathCustom(string productId) + protected override LongPath GetFilePathCustom(string productId) => GetFilePathsCustom(productId).FirstOrDefault(); protected override List GetFilePathsCustom(string productId) @@ -122,5 +132,43 @@ namespace LibationFileManager public void Refresh() => BookDirectoryFiles.RefreshFiles(); public LongPath GetPath(string productId) => GetFilePath(productId); + + public static async IAsyncEnumerable FindAudiobooksAsync(LongPath searchDirectory, [EnumeratorCancellation] CancellationToken cancellationToken) + { + ArgumentValidator.EnsureNotNull(searchDirectory, nameof(searchDirectory)); + + foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.M4B", enumerationOptions)) + { + if (cancellationToken.IsCancellationRequested) + yield break; + + int generation = 0; + FilePathCache.CacheEntry audioFile = default; + + try + { + using var fileStream = File.OpenRead(path); + + var mp4File = await Task.Run(() => new AAXClean.Mp4File(fileStream), cancellationToken); + + generation = GC.GetGeneration(mp4File); + + if (mp4File?.AppleTags?.Asin is not null) + audioFile = new FilePathCache.CacheEntry(mp4File.AppleTags.Asin, FileType.Audio, path); + + } + catch (Exception ex) + { + Serilog.Log.Error(ex, "Error checking for asin in {@file}", path); + } + finally + { + GC.Collect(generation); + } + + if (audioFile is not null) + yield return audioFile; + } + } } } diff --git a/Source/LibationFileManager/AudioFileLocator.cs b/Source/LibationFileManager/AudioFileLocator.cs deleted file mode 100644 index 8413de6c..00000000 --- a/Source/LibationFileManager/AudioFileLocator.cs +++ /dev/null @@ -1,60 +0,0 @@ -using AAXClean; -using Dinah.Core; -using FileManager; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -namespace LibationFileManager -{ - public static class AudioFileLocator - { - private static EnumerationOptions enumerationOptions { get; } = new() - { - RecurseSubdirectories = true, - IgnoreInaccessible = true, - MatchCasing = MatchCasing.CaseInsensitive - }; - - public static async IAsyncEnumerable FindAudiobooks(LongPath searchDirectory, [EnumeratorCancellation] CancellationToken cancellationToken) - { - ArgumentValidator.EnsureNotNull(searchDirectory, nameof(searchDirectory)); - - foreach (LongPath path in Directory.EnumerateFiles(searchDirectory, "*.M4B", enumerationOptions)) - { - if (cancellationToken.IsCancellationRequested) - yield break; - - int generation = 0; - FilePathCache.CacheEntry audioFile = default; - - try - { - using var fileStream = File.OpenRead(path); - - var mp4File = await Task.Run(() => new Mp4File(fileStream), cancellationToken); - - generation = GC.GetGeneration(mp4File); - - if (mp4File?.AppleTags?.Asin is not null) - audioFile = new FilePathCache.CacheEntry(mp4File.AppleTags.Asin, FileType.Audio, path); - - } - catch(Exception ex) - { - Serilog.Log.Error(ex, "Error checking for asin in {@file}", path); - } - finally - { - GC.Collect(generation); - } - - if (audioFile is not null) - yield return audioFile; - } - } - } -} diff --git a/Source/LibationFileManager/Templates.cs b/Source/LibationFileManager/Templates.cs index 198e74b5..70be7bac 100644 --- a/Source/LibationFileManager/Templates.cs +++ b/Source/LibationFileManager/Templates.cs @@ -278,9 +278,9 @@ namespace LibationFileManager var sortedNames = sortMatch.Success ? ( - sortMatch.Groups[1].Value.ToUpper() == "F" ? names.OrderBy(n => n.First) - : sortMatch.Groups[1].Value.ToUpper() == "M" ? names.OrderBy(n => n.Middle) - : sortMatch.Groups[1].Value.ToUpper() == "L" ? names.OrderBy(n => n.Last) + sortMatch.Groups[1].Value == "F" ? names.OrderBy(n => n.First) + : sortMatch.Groups[1].Value == "M" ? names.OrderBy(n => n.Middle) + : sortMatch.Groups[1].Value == "L" ? names.OrderBy(n => n.Last) : names ) : names; diff --git a/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs b/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs index 5df7b0fc..abaca53d 100644 --- a/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs +++ b/Source/LibationWinForms/Dialogs/LocateAudiobooksDialog.cs @@ -73,7 +73,7 @@ namespace LibationWinForms.Dialogs using var context = DbContexts.GetContext(); - await foreach (var book in AudioFileLocator.FindAudiobooks(fbd.SelectedPath, tokenSource.Token)) + await foreach (var book in AudioFileStorage.FindAudiobooksAsync(fbd.SelectedPath, tokenSource.Token)) { try {