diff --git a/Source/LibationAvalonia/ViewModels/MainVM.Liberate.cs b/Source/LibationAvalonia/ViewModels/MainVM.Liberate.cs index c5710980..267dc00b 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.Liberate.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.Liberate.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Threading.Tasks; using DataLayer; using LibationUiBase.Forms; +using LibationUiBase; +using System.Collections.Generic; #nullable enable namespace LibationAvalonia.ViewModels @@ -13,19 +15,14 @@ namespace LibationAvalonia.ViewModels { public void Configure_Liberate() { } - public void BackupAllBooks() + public async Task BackupAllBooks() { try { - setQueueCollapseState(false); + var unliberated = await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray()); - Serilog.Log.Logger.Information("Begin backing up all library books"); - - ProcessQueue.AddDownloadDecrypt( - DbContexts - .GetLibrary_Flat_NoTracking() - .UnLiberated() - ); + if (ProcessQueue.QueueDownloadDecrypt(unliberated)) + setQueueCollapseState(false); } catch (Exception ex) { @@ -33,10 +30,10 @@ namespace LibationAvalonia.ViewModels } } - public void BackupAllPdfs() + public async Task BackupAllPdfs() { - setQueueCollapseState(false); - ProcessQueue.AddDownloadPdf(DbContexts.GetLibrary_Flat_NoTracking().Where(lb => lb.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated)); + if (ProcessQueue.QueueDownloadPdf(await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking()))) + setQueueCollapseState(false); } public async Task ConvertAllToMp3Async() @@ -49,12 +46,8 @@ namespace LibationAvalonia.ViewModels "Convert all M4b => Mp3?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); - if (result == DialogResult.Yes) - { + if (result == DialogResult.Yes && ProcessQueue.QueueConvertToMp3(await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking()))) setQueueCollapseState(false); - ProcessQueue.AddConvertMp3(DbContexts.GetLibrary_Flat_NoTracking().Where(lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated && lb.Book.ContentType is ContentType.Product)); - } - //Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing. } private void setQueueCollapseState(bool collapsed) diff --git a/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs b/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs index 0b53df4f..a35f1036 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.ProcessQueue.cs @@ -1,10 +1,11 @@ -using LibationFileManager; -using System; -using System.Linq; -using DataLayer; +using DataLayer; using Dinah.Core; +using LibationFileManager; +using LibationUiBase; using LibationUiBase.GridView; using ReactiveUI; +using System; +using System.Linq; #nullable enable namespace LibationAvalonia.ViewModels @@ -37,54 +38,16 @@ namespace LibationAvalonia.ViewModels { try { - if (libraryBooks.Length == 1) + if (ProcessQueue.QueueDownloadDecrypt(libraryBooks)) + setQueueCollapseState(false); + else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists()) { - var item = libraryBooks[0]; - - void initiateSingleDownload() + // liberated: open explorer to file + var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId); + if (!Go.To.File(filePath?.ShortPathName)) { - //Remove this item from the queue if it's already present and completed. - //Only do this when adding a single book at a time to prevent accidental - //extra downloads when queueing in batches. - ProcessQueue.RemoveCompleted(item); - setQueueCollapseState(false); - } - - if (item.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload) - { - initiateSingleDownload(); - Serilog.Log.Logger.Information("Begin single book backup of {libraryBook}", item); - ProcessQueue.AddDownloadDecrypt(item); - } - else if (item.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) - { - initiateSingleDownload(); - Serilog.Log.Logger.Information("Begin single pdf backup of {libraryBook}", item); - ProcessQueue.AddDownloadPdf(item); - } - else if (item.Book.Audio_Exists()) - { - // liberated: open explorer to file - var filePath = AudibleFileStorage.Audio.GetPath(item.Book.AudibleProductId); - - if (!Go.To.File(filePath?.ShortPathName)) - { - var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; - await MessageBox.Show($"File not found" + suffix); - } - } - } - else - { - var toLiberate - = libraryBooks - .Where(x => x.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload || x.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) - .ToArray(); - - if (toLiberate.Length > 0) - { - setQueueCollapseState(false); - ProcessQueue.AddDownloadDecrypt(toLiberate); + var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; + await MessageBox.Show($"File not found" + suffix); } } } @@ -98,11 +61,10 @@ namespace LibationAvalonia.ViewModels { try { - setQueueCollapseState(false); - Serilog.Log.Logger.Information("Begin backing up all {series} episodes", series.LibraryBook); - ProcessQueue.AddDownloadDecrypt(series.Children.Select(c => c.LibraryBook).UnLiberated()); + if (ProcessQueue.QueueDownloadDecrypt(series.Children.Select(c => c.LibraryBook).UnLiberated().ToArray())) + setQueueCollapseState(false); } catch (Exception ex) { @@ -114,13 +76,8 @@ namespace LibationAvalonia.ViewModels { try { - var preLiberated = libraryBooks.Where(lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated).ToArray(); - if (preLiberated.Length > 0) - { - Serilog.Log.Logger.Information("Begin convert {count} books to mp3", preLiberated.Length); + if (ProcessQueue.QueueConvertToMp3(libraryBooks)) setQueueCollapseState(false); - ProcessQueue.AddConvertMp3(preLiberated); - } } catch (Exception ex) { diff --git a/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs b/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs index 75d59a18..728a0b1f 100644 --- a/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs +++ b/Source/LibationAvalonia/ViewModels/MainVM.VisibleBooks.cs @@ -6,6 +6,8 @@ using Avalonia.Threading; using LibationAvalonia.Dialogs; using ReactiveUI; using LibationUiBase.Forms; +using System.Linq; +using LibationUiBase; #nullable enable namespace LibationAvalonia.ViewModels @@ -72,15 +74,8 @@ namespace LibationAvalonia.ViewModels { try { - setQueueCollapseState(false); - - Serilog.Log.Logger.Information("Begin backing up visible library books"); - - ProcessQueue.AddDownloadDecrypt( - ProductsDisplay - .GetVisibleBookEntries() - .UnLiberated() - ); + if (ProcessQueue.QueueDownloadDecrypt(ProductsDisplay.GetVisibleBookEntries().UnLiberated().ToArray())) + setQueueCollapseState(false); } catch (Exception ex) { diff --git a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs index ed5b6501..7c9430aa 100644 --- a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs +++ b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs @@ -17,7 +17,7 @@ using System.Threading.Tasks; namespace LibationAvalonia.ViewModels { - public class ProcessQueueViewModel : ViewModelBase, ILogForm + public class ProcessQueueViewModel : ViewModelBase, ILogForm, IProcessQueue { public ObservableCollection LogEntries { get; } = new(); public AvaloniaList Items { get; } = new(); @@ -136,15 +136,6 @@ namespace LibationAvalonia.ViewModels && entry.Status is ProcessBookStatus.Completed && Queue.RemoveCompleted(entry); - public void AddDownloadPdf(LibraryBook libraryBook) - => AddDownloadPdf(new List() { libraryBook }); - - public void AddDownloadDecrypt(LibraryBook libraryBook) - => AddDownloadDecrypt(new List() { libraryBook }); - - public void AddConvertMp3(LibraryBook libraryBook) - => AddConvertMp3(new List() { libraryBook }); - public void AddDownloadPdf(IEnumerable entries) { List procs = new(); diff --git a/Source/LibationUiBase/IProcessQueue.cs b/Source/LibationUiBase/IProcessQueue.cs new file mode 100644 index 00000000..84b21e0f --- /dev/null +++ b/Source/LibationUiBase/IProcessQueue.cs @@ -0,0 +1,82 @@ +using DataLayer; +using System.Collections.Generic; +using System.Linq; + +namespace LibationUiBase; + +public interface IProcessQueue +{ + bool RemoveCompleted(LibraryBook libraryBook); + void AddDownloadPdf(IEnumerable entries); + void AddConvertMp3(IEnumerable entries); + void AddDownloadDecrypt(IEnumerable entries); +} + +public static class ProcessQueueExtensions +{ + + public static bool QueueDownloadPdf(this IProcessQueue queue, IList libraryBooks) + { + var needsPdf = libraryBooks.Where(lb => !lb.AbsentFromLastScan && lb.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated).ToArray(); + if (needsPdf.Length > 0) + { + Serilog.Log.Logger.Information("Begin download {count} pdfs", needsPdf.Length); + queue.AddDownloadPdf(needsPdf); + return true; + } + return false; + } + + public static bool QueueConvertToMp3(this IProcessQueue queue, IList libraryBooks) + { + //Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing. + var preLiberated = libraryBooks.Where(lb => !lb.AbsentFromLastScan && lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product).ToArray(); + if (preLiberated.Length > 0) + { + Serilog.Log.Logger.Information("Begin convert {count} books to mp3", preLiberated.Length); + queue.AddConvertMp3(preLiberated); + return true; + } + return false; + } + + public static bool QueueDownloadDecrypt(this IProcessQueue queue, IList libraryBooks) + { + if (libraryBooks.Count == 1) + { + var item = libraryBooks[0]; + + if (item.AbsentFromLastScan) + return false; + else if(item.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload) + { + queue.RemoveCompleted(item); + Serilog.Log.Logger.Information("Begin single library book backup of {libraryBook}", item); + queue.AddDownloadDecrypt([item]); + return true; + } + else if (item.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) + { + queue.RemoveCompleted(item); + Serilog.Log.Logger.Information("Begin single pdf backup of {libraryBook}", item); + queue.AddDownloadPdf([item]); + return true; + } + } + else + { + var toLiberate + = libraryBooks + .Where(x => !x.AbsentFromLastScan && x.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload || x.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) + .ToArray(); + + if (toLiberate.Length > 0) + { + Serilog.Log.Logger.Information("Begin backup of {count} library books", toLiberate.Length); + queue.AddDownloadDecrypt(toLiberate); + return true; + } + } + return false; + } +} diff --git a/Source/LibationWinForms/Form1.Liberate.cs b/Source/LibationWinForms/Form1.Liberate.cs index 256b977e..2bda3e52 100644 --- a/Source/LibationWinForms/Form1.Liberate.cs +++ b/Source/LibationWinForms/Form1.Liberate.cs @@ -1,4 +1,5 @@ using DataLayer; +using LibationUiBase; using System; using System.Linq; using System.Threading.Tasks; @@ -11,19 +12,13 @@ namespace LibationWinForms private void Configure_Liberate() { } //GetLibrary_Flat_NoTracking() may take a long time on a hugh library. so run in new thread - private void beginBookBackupsToolStripMenuItem_Click(object _ = null, EventArgs __ = null) + private async void beginBookBackupsToolStripMenuItem_Click(object _ = null, EventArgs __ = null) { try { - SetQueueCollapseState(false); - - Serilog.Log.Logger.Information("Begin backing up all library books"); - - processBookQueue1.AddDownloadDecrypt( - ApplicationServices.DbContexts - .GetLibrary_Flat_NoTracking() - .UnLiberated() - ); + var unliberated = await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray()); + if (processBookQueue1.QueueDownloadDecrypt(unliberated)) + SetQueueCollapseState(false); } catch (Exception ex) { @@ -33,9 +28,8 @@ namespace LibationWinForms private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e) { - SetQueueCollapseState(false); - await Task.Run(() => processBookQueue1.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() - .Where(lb => lb.Book.UserDefinedItem.PdfStatus is DataLayer.LiberatedStatus.NotLiberated))); + if (processBookQueue1.QueueDownloadPdf(await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking()))) + SetQueueCollapseState(false); } private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e) @@ -48,13 +42,8 @@ namespace LibationWinForms "Convert all M4b => Mp3?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); - if (result == DialogResult.Yes) - { + if (result == DialogResult.Yes && processBookQueue1.QueueConvertToMp3(await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking()))) SetQueueCollapseState(false); - await Task.Run(() => processBookQueue1.AddConvertMp3(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() - .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. } } } diff --git a/Source/LibationWinForms/Form1.ProcessQueue.cs b/Source/LibationWinForms/Form1.ProcessQueue.cs index a19ce0b6..41d28080 100644 --- a/Source/LibationWinForms/Form1.ProcessQueue.cs +++ b/Source/LibationWinForms/Form1.ProcessQueue.cs @@ -1,6 +1,8 @@ using DataLayer; using Dinah.Core; using LibationFileManager; +using LibationUiBase; +using LibationUiBase.Forms; using LibationUiBase.GridView; using LibationWinForms.ProcessQueue; using System; @@ -27,53 +29,16 @@ namespace LibationWinForms { try { - if (libraryBooks.Length == 1) + if (processBookQueue1.QueueDownloadDecrypt(libraryBooks)) + SetQueueCollapseState(false); + else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists()) { - var item = libraryBooks[0]; - - void initiateSingleDownload() + // liberated: open explorer to file + var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId); + if (!Go.To.File(filePath?.ShortPathName)) { - //Remove this item from the queue if it's already present and completed. - //Only do this when adding a single book at a time to prevent accidental - //extra downloads when queueing in batches. - processBookQueue1.RemoveCompleted(item); - SetQueueCollapseState(false); - } - - if (item.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload) - { - initiateSingleDownload(); - Serilog.Log.Logger.Information("Begin single book backup of {libraryBook}", item); - processBookQueue1.AddDownloadDecrypt(item); - } - else if (item.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) - { - initiateSingleDownload(); - Serilog.Log.Logger.Information("Begin single pdf backup of {libraryBook}", item); - processBookQueue1.AddDownloadPdf(item); - } - else if (item.Book.Audio_Exists()) - { - // liberated: open explorer to file - var filePath = AudibleFileStorage.Audio.GetPath(item.Book.AudibleProductId); - if (!Go.To.File(filePath?.ShortPathName)) - { - var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; - MessageBox.Show($"File not found" + suffix); - } - } - } - else - { - var toLiberate - = libraryBooks - .Where(x => x.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload || x.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) - .ToArray(); - - if (toLiberate.Length > 0) - { - SetQueueCollapseState(false); - processBookQueue1.AddDownloadDecrypt(toLiberate); + var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}"; + MessageBox.Show($"File not found" + suffix); } } } @@ -87,11 +52,10 @@ namespace LibationWinForms { try { - SetQueueCollapseState(false); - Serilog.Log.Logger.Information("Begin backing up all {series} episodes", series.LibraryBook); - processBookQueue1.AddDownloadDecrypt(series.Children.Select(c => c.LibraryBook).UnLiberated()); + if (processBookQueue1.QueueDownloadDecrypt(series.Children.Select(c => c.LibraryBook).UnLiberated().ToArray())) + SetQueueCollapseState(false); } catch (Exception ex) { @@ -103,13 +67,8 @@ namespace LibationWinForms { try { - var preLiberated = libraryBooks.Where(lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated).ToArray(); - if (preLiberated.Length > 0) - { - Serilog.Log.Logger.Information("Begin convert {count} books to mp3", preLiberated.Length); + if (processBookQueue1.QueueConvertToMp3(libraryBooks)) SetQueueCollapseState(false); - processBookQueue1.AddConvertMp3(preLiberated); - } } catch (Exception ex) { diff --git a/Source/LibationWinForms/Form1.VisibleBooks.cs b/Source/LibationWinForms/Form1.VisibleBooks.cs index aeaf4be6..a72bb40b 100644 --- a/Source/LibationWinForms/Form1.VisibleBooks.cs +++ b/Source/LibationWinForms/Form1.VisibleBooks.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using ApplicationServices; using DataLayer; using Dinah.Core.Threading; +using LibationUiBase; using LibationWinForms.Dialogs; namespace LibationWinForms @@ -58,15 +59,8 @@ namespace LibationWinForms { try { - SetQueueCollapseState(false); - - Serilog.Log.Logger.Information("Begin backing up visible library books"); - - processBookQueue1.AddDownloadDecrypt( - productsDisplay - .GetVisible() - .UnLiberated() - ); + if (processBookQueue1.QueueDownloadDecrypt(productsDisplay.GetVisible().UnLiberated().ToArray())) + SetQueueCollapseState(false); } catch (Exception ex) { diff --git a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs index 5f10bc04..fce5420a 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs @@ -11,7 +11,7 @@ using LibationUiBase; namespace LibationWinForms.ProcessQueue { - internal partial class ProcessQueueControl : UserControl, ILogForm + internal partial class ProcessQueueControl : UserControl, ILogForm, IProcessQueue { private TrackedQueue Queue = new(); private readonly LogMe Logger; @@ -97,15 +97,6 @@ namespace LibationWinForms.ProcessQueue && entry.Status is ProcessBookStatus.Completed && Queue.RemoveCompleted(entry); - public void AddDownloadPdf(DataLayer.LibraryBook libraryBook) - => AddDownloadPdf(new List() { libraryBook }); - - public void AddDownloadDecrypt(DataLayer.LibraryBook libraryBook) - => AddDownloadDecrypt(new List() { libraryBook }); - - public void AddConvertMp3(DataLayer.LibraryBook libraryBook) - => AddConvertMp3(new List() { libraryBook }); - public void AddDownloadPdf(IEnumerable entries) { List procs = new(); @@ -162,6 +153,9 @@ namespace LibationWinForms.ProcessQueue } private void AddToQueue(IEnumerable pbook) { + if (!IsHandleCreated) + CreateControl(); + BeginInvoke(() => { Queue.Enqueue(pbook);