From 0f9f0d9eae637f2b1c21b507aed3290c01cb3d8a Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Thu, 5 Dec 2019 15:55:46 -0500 Subject: [PATCH] New feature: liberate individual book --- FileLiberator/UNTESTED/BackupBook.cs | 11 +- FileLiberator/UNTESTED/DecryptBook.cs | 10 +- FileLiberator/UNTESTED/DownloadableBase.cs | 10 +- FileLiberator/UNTESTED/IDownloadable.cs | 3 +- FileLiberator/UNTESTED/IProcessable.cs | 4 +- FileLiberator/UNTESTED/IProcessableExt.cs | 34 +++- .../BookLiberation/AutomatedBackupsForm.cs | 13 +- .../ProcessorAutomationController.Examples.cs | 65 ------ .../ProcessorAutomationController.cs | 190 +++++++++++------- LibationWinForm/UNTESTED/Form1.cs | 40 ++-- LibationWinForm/UNTESTED/ProductsGrid.cs | 34 +++- REFERENCE.txt | 1 + 12 files changed, 221 insertions(+), 194 deletions(-) delete mode 100644 LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.Examples.cs diff --git a/FileLiberator/UNTESTED/BackupBook.cs b/FileLiberator/UNTESTED/BackupBook.cs index c4b75639..72ff0dd3 100644 --- a/FileLiberator/UNTESTED/BackupBook.cs +++ b/FileLiberator/UNTESTED/BackupBook.cs @@ -17,9 +17,9 @@ namespace FileLiberator /// public class BackupBook : IProcessable { - public event EventHandler Begin; + public event EventHandler Begin; public event EventHandler StatusUpdate; - public event EventHandler Completed; + public event EventHandler Completed; public DownloadBook DownloadBook { get; } = new DownloadBook(); public DecryptBook DecryptBook { get; } = new DecryptBook(); @@ -32,10 +32,7 @@ namespace FileLiberator // often calls events which prints to forms in the UI context public async Task ProcessAsync(LibraryBook libraryBook) { - var productId = libraryBook.Book.AudibleProductId; - var displayMessage = $"[{productId}] {libraryBook.Book.Title}"; - - Begin?.Invoke(this, displayMessage); + Begin?.Invoke(this, libraryBook); try { @@ -61,7 +58,7 @@ namespace FileLiberator } finally { - Completed?.Invoke(this, displayMessage); + Completed?.Invoke(this, libraryBook); } } } diff --git a/FileLiberator/UNTESTED/DecryptBook.cs b/FileLiberator/UNTESTED/DecryptBook.cs index f799552c..91d92931 100644 --- a/FileLiberator/UNTESTED/DecryptBook.cs +++ b/FileLiberator/UNTESTED/DecryptBook.cs @@ -21,7 +21,7 @@ namespace FileLiberator /// public class DecryptBook : IDecryptable { - public event EventHandler Begin; + public event EventHandler Begin; public event EventHandler StatusUpdate; public event EventHandler DecryptBegin; @@ -32,7 +32,7 @@ namespace FileLiberator public event EventHandler UpdateProgress; public event EventHandler DecryptCompleted; - public event EventHandler Completed; + public event EventHandler Completed; public bool Validate(LibraryBook libraryBook) => AudibleFileStorage.AAX.Exists(libraryBook.Book.AudibleProductId) @@ -42,9 +42,7 @@ namespace FileLiberator // often calls events which prints to forms in the UI context public async Task ProcessAsync(LibraryBook libraryBook) { - var displayMessage = $"[{libraryBook.Book.AudibleProductId}] {libraryBook.Book.Title}"; - - Begin?.Invoke(this, displayMessage); + Begin?.Invoke(this, libraryBook); try { @@ -76,7 +74,7 @@ namespace FileLiberator } finally { - Completed?.Invoke(this, displayMessage); + Completed?.Invoke(this, libraryBook); } } diff --git a/FileLiberator/UNTESTED/DownloadableBase.cs b/FileLiberator/UNTESTED/DownloadableBase.cs index fe6632b7..43d1df44 100644 --- a/FileLiberator/UNTESTED/DownloadableBase.cs +++ b/FileLiberator/UNTESTED/DownloadableBase.cs @@ -8,8 +8,8 @@ namespace FileLiberator { public abstract class DownloadableBase : IDownloadable { - public event EventHandler Begin; - public event EventHandler Completed; + public event EventHandler Begin; + public event EventHandler Completed; public event EventHandler DownloadBegin; public event EventHandler DownloadProgressChanged; @@ -26,9 +26,7 @@ namespace FileLiberator // often calls events which prints to forms in the UI context public async Task ProcessAsync(LibraryBook libraryBook) { - var displayMessage = $"[{libraryBook.Book.AudibleProductId}] {libraryBook.Book.Title}"; - - Begin?.Invoke(this, displayMessage); + Begin?.Invoke(this, libraryBook); try { @@ -36,7 +34,7 @@ namespace FileLiberator } finally { - Completed?.Invoke(this, displayMessage); + Completed?.Invoke(this, libraryBook); } } diff --git a/FileLiberator/UNTESTED/IDownloadable.cs b/FileLiberator/UNTESTED/IDownloadable.cs index 22b51464..2fa35d72 100644 --- a/FileLiberator/UNTESTED/IDownloadable.cs +++ b/FileLiberator/UNTESTED/IDownloadable.cs @@ -1,11 +1,12 @@ using System; +using Dinah.Core.Net.Http; namespace FileLiberator { public interface IDownloadable : IProcessable { event EventHandler DownloadBegin; - event EventHandler DownloadProgressChanged; + event EventHandler DownloadProgressChanged; event EventHandler DownloadCompleted; } } diff --git a/FileLiberator/UNTESTED/IProcessable.cs b/FileLiberator/UNTESTED/IProcessable.cs index 63edc51a..9814f21d 100644 --- a/FileLiberator/UNTESTED/IProcessable.cs +++ b/FileLiberator/UNTESTED/IProcessable.cs @@ -7,12 +7,12 @@ namespace FileLiberator { public interface IProcessable { - event EventHandler Begin; + event EventHandler Begin; /// General string message to display. DON'T rely on this for success, failure, or control logic event EventHandler StatusUpdate; - event EventHandler Completed; + event EventHandler Completed; /// True == Valid bool Validate(LibraryBook libraryBook); diff --git a/FileLiberator/UNTESTED/IProcessableExt.cs b/FileLiberator/UNTESTED/IProcessableExt.cs index a5234dd7..cb94b78c 100644 --- a/FileLiberator/UNTESTED/IProcessableExt.cs +++ b/FileLiberator/UNTESTED/IProcessableExt.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using DataLayer; using Dinah.Core.ErrorHandling; @@ -17,19 +18,42 @@ namespace FileLiberator /// Returns either the status handler from the process, or null if all books have been processed public static async Task ProcessFirstValidAsync(this IProcessable processable) { - var libraryBook = processable.GetNextValid(); + var libraryBook = processable.getNextValidBook(); if (libraryBook == null) return null; - // this should never happen. check anyway. ProcessFirstValidAsync returning null is the signal that we're done. we can't let another IProcessable accidentally send this commans - var status = await processable.ProcessAsync(libraryBook); + return await processBookAsync(processable, libraryBook); + } + + /// Process the first valid product. Create default context + /// Returns either the status handler from the process, or null if all books have been processed + public static async Task ProcessSingleAsync(this IProcessable processable, string productId) + { + using var context = LibationContext.Create(); + var libraryBook = context + .Library + .GetLibrary() + .SingleOrDefault(lb => lb.Book.AudibleProductId == productId); + + if (libraryBook == null) + return null; + if (!processable.Validate(libraryBook)) + return new StatusHandler { "Validation failed" }; + + return await processBookAsync(processable, libraryBook); + } + + private static async Task processBookAsync(IProcessable processable, LibraryBook libraryBook) + { + // this should never happen. check anyway. ProcessFirstValidAsync returning null is the signal that we're done. we can't let another IProcessable accidentally send this command + var status = await processable.ProcessAsync(libraryBook); if (status == null) throw new Exception("Processable should never return a null status"); return status; } - public static LibraryBook GetNextValid(this IProcessable processable) + private static LibraryBook getNextValidBook(this IProcessable processable) { var libraryBooks = LibraryQueries.GetLibrary_Flat_NoTracking(); @@ -38,7 +62,7 @@ namespace FileLiberator return libraryBook; return null; - } + } public static async Task TryProcessAsync(this IProcessable processable, LibraryBook libraryBook) => processable.Validate(libraryBook) diff --git a/LibationWinForm/UNTESTED/BookLiberation/AutomatedBackupsForm.cs b/LibationWinForm/UNTESTED/BookLiberation/AutomatedBackupsForm.cs index 40381fcf..b632c3fe 100644 --- a/LibationWinForm/UNTESTED/BookLiberation/AutomatedBackupsForm.cs +++ b/LibationWinForm/UNTESTED/BookLiberation/AutomatedBackupsForm.cs @@ -6,7 +6,18 @@ namespace LibationWinForm.BookLiberation { public partial class AutomatedBackupsForm : Form { - public bool KeepGoingIsChecked => keepGoingCb.Checked; + public bool KeepGoingVisible + { + get => keepGoingCb.Visible; + set => keepGoingCb.Visible = value; + } + + public bool KeepGoingChecked => keepGoingCb.Checked; + + public bool KeepGoing + => keepGoingCb.Visible + && keepGoingCb.Enabled + && keepGoingCb.Checked; public AutomatedBackupsForm() { diff --git a/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.Examples.cs b/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.Examples.cs deleted file mode 100644 index 2a859227..00000000 --- a/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.Examples.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DataLayer; -using Dinah.Core.ErrorHandling; -using FileLiberator; - -namespace LibationWinForm.BookLiberation -{ - public class BookLiberatorControllerExamples - { - async Task BackupBookAsync(string productId) - { - using var context = LibationContext.Create(); - - var libraryBook = context - .Library - .GetLibrary() - .SingleOrDefault(lb => lb.Book.AudibleProductId == productId); - - if (libraryBook == null) - return; - - var backupBook = new BackupBook(); - backupBook.DownloadBook.Completed += SetBackupCountsAsync; - backupBook.DecryptBook.Completed += SetBackupCountsAsync; - await ProcessValidateLibraryBookAsync(backupBook, libraryBook); - } - - static async Task ProcessValidateLibraryBookAsync(IProcessable processable, LibraryBook libraryBook) - { - if (!processable.Validate(libraryBook)) - return new StatusHandler { "Validation failed" }; - return await processable.ProcessAsync(libraryBook); - } - - // Download First Book (Download encrypted/DRM file) - async Task DownloadFirstBookAsync() - { - var downloadBook = ProcessorAutomationController.GetWiredUpDownloadBook(); - downloadBook.Completed += SetBackupCountsAsync; - await downloadBook.ProcessFirstValidAsync(); - } - - // Decrypt First Book (Remove DRM from downloaded file) - async Task DecryptFirstBookAsync() - { - var decryptBook = ProcessorAutomationController.GetWiredUpDecryptBook(); - decryptBook.Completed += SetBackupCountsAsync; - await decryptBook.ProcessFirstValidAsync(); - } - - // Backup First Book (Decrypt a non-liberated book. Download if needed) - async Task BackupFirstBookAsync() - { - var backupBook = ProcessorAutomationController.GetWiredUpBackupBook(); - backupBook.DownloadBook.Completed += SetBackupCountsAsync; - backupBook.DecryptBook.Completed += SetBackupCountsAsync; - await backupBook.ProcessFirstValidAsync(); - } - - async void SetBackupCountsAsync(object obj, string str) => throw new NotImplementedException(); - } -} diff --git a/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.cs b/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.cs index eda781e9..763f64fb 100644 --- a/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.cs +++ b/LibationWinForm/UNTESTED/BookLiberation/ProcessorAutomationController.cs @@ -1,5 +1,7 @@ using System; using System.Threading.Tasks; +using DataLayer; +using Dinah.Core.ErrorHandling; using FileLiberator; namespace LibationWinForm.BookLiberation @@ -12,37 +14,38 @@ namespace LibationWinForm.BookLiberation // 1) we can't forget to do it // 2) we can't accidentally do it mult times becaues we lost track of complexity // - public static BackupBook GetWiredUpBackupBook() + public static BackupBook GetWiredUpBackupBook(EventHandler completedAction = null) { var backupBook = new BackupBook(); - backupBook.DownloadBook.Begin += (_, __) => wireUpDownloadable(backupBook.DownloadBook); - backupBook.DecryptBook.Begin += (_, __) => wireUpDecryptable(backupBook.DecryptBook); - backupBook.DownloadPdf.Begin += (_, __) => wireUpDecryptable(backupBook.DecryptBook); + backupBook.DownloadBook.Begin += (_, __) => wireUpEvents(backupBook.DownloadBook); + backupBook.DecryptBook.Begin += (_, __) => wireUpEvents(backupBook.DecryptBook); + backupBook.DownloadPdf.Begin += (_, __) => wireUpEvents(backupBook.DownloadPdf); - return backupBook; + if (completedAction != null) + { + backupBook.DownloadBook.Completed += completedAction; + backupBook.DecryptBook.Completed += completedAction; + backupBook.DownloadPdf.Completed += completedAction; + } + + return backupBook; } - public static DecryptBook GetWiredUpDecryptBook() - { - var decryptBook = new DecryptBook(); - decryptBook.Begin += (_, __) => wireUpDecryptable(decryptBook); - return decryptBook; - } - public static DownloadBook GetWiredUpDownloadBook() - { - var downloadBook = new DownloadBook(); - downloadBook.Begin += (_, __) => wireUpDownloadable(downloadBook); - return downloadBook; - } - public static DownloadPdf GetWiredUpDownloadPdf() + + public static DownloadPdf GetWiredUpDownloadPdf(EventHandler completedAction = null) { var downloadPdf = new DownloadPdf(); - downloadPdf.Begin += (_, __) => wireUpDownloadable(downloadPdf); + + downloadPdf.Begin += (_, __) => wireUpEvents(downloadPdf); + + if (completedAction != null) + downloadPdf.Completed += completedAction; + return downloadPdf; } // subscribed to Begin event because a new form should be created+processed+closed on each iteration - private static void wireUpDownloadable(IDownloadable downloadable) + private static void wireUpEvents(IDownloadable downloadable) { #region create form var downloadDialog = new DownloadForm(); @@ -82,7 +85,7 @@ namespace LibationWinForm.BookLiberation // unless we dispose, if the form is created but un-used/never-shown then weird UI stuff can happen // also, since event unsubscribe occurs on FormClosing and an unused form is never closed, then the events will never be unsubscribed - void dialogDispose(object _, string __) + void dialogDispose(object _, object __) { if (!downloadDialog.IsDisposed) downloadDialog.Dispose(); @@ -106,7 +109,7 @@ namespace LibationWinForm.BookLiberation } // subscribed to Begin event because a new form should be created+processed+closed on each iteration - private static void wireUpDecryptable(IDecryptable decryptBook) + private static void wireUpEvents(IDecryptable decryptBook) { #region create form var decryptDialog = new DecryptForm(); @@ -153,17 +156,23 @@ namespace LibationWinForm.BookLiberation #endregion } - public static async Task RunAutomaticDownload(IDownloadable downloadable) + public static async Task RunAutomaticDownloadAsync(IDownloadable downloadable) + { + AutomatedBackupsForm automatedBackupsForm = attachToBackupsForm(downloadable); + await runBackupLoopAsync(downloadable, automatedBackupsForm); + } + + private static AutomatedBackupsForm attachToBackupsForm(IDownloadable downloadable) { #region create form var automatedBackupsForm = new AutomatedBackupsForm(); #endregion #region define how model actions will affect form behavior - void begin(object _, string str) => automatedBackupsForm.AppendText("Begin: " + str); + void begin(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Begin: {libraryBook.Book}"); void statusUpdate(object _, string str) => automatedBackupsForm.AppendText("- " + str); // extra line after book is completely finished - void completed(object _, string str) => automatedBackupsForm.AppendText("Completed: " + str + Environment.NewLine); + void completed(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Completed: {libraryBook.Book}{Environment.NewLine}"); #endregion #region subscribe new form to model's events @@ -182,42 +191,55 @@ namespace LibationWinForm.BookLiberation }; #endregion - await runBackupLoop(downloadable, automatedBackupsForm); + return automatedBackupsForm; } - public static async Task RunAutomaticBackup(BackupBook backupBook) + public static async Task RunAutomaticBackupAsync(BackupBook backupBook) + { + var automatedBackupsForm = attachToBackupsForm(backupBook); + await runBackupLoopAsync(backupBook, automatedBackupsForm); + } + + public static async Task RunSingleBackupAsync(BackupBook backupBook, string productId) + { + var automatedBackupsForm = attachToBackupsForm(backupBook); + automatedBackupsForm.KeepGoingVisible = false; + await runSingleBackupAsync(backupBook, automatedBackupsForm, productId); + } + + private static AutomatedBackupsForm attachToBackupsForm(BackupBook backupBook) { #region create form var automatedBackupsForm = new AutomatedBackupsForm(); #endregion #region define how model actions will affect form behavior - void downloadBookBegin(object _, string str) => automatedBackupsForm.AppendText("DownloadStep_Begin: " + str); + void downloadBookBegin(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Download Step, Begin: {libraryBook.Book}"); void statusUpdate(object _, string str) => automatedBackupsForm.AppendText("- " + str); - void downloadBookCompleted(object _, string str) => automatedBackupsForm.AppendText("DownloadStep_Completed: " + str); - void decryptBookBegin(object _, string str) => automatedBackupsForm.AppendText("DecryptStep_Begin: " + str); + void downloadBookCompleted(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Download Step, Completed: {libraryBook.Book}"); + void decryptBookBegin(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Decrypt Step, Begin: {libraryBook.Book}"); // extra line after book is completely finished - void decryptBookCompleted(object _, string str) => automatedBackupsForm.AppendText("DecryptStep_Completed: " + str + Environment.NewLine); - void downloadPdfBegin(object _, string str) => automatedBackupsForm.AppendText("PdfStep_Begin: " + str); - // extra line after book is completely finished - void downloadPdfCompleted(object _, string str) => automatedBackupsForm.AppendText("PdfStep_Completed: " + str + Environment.NewLine); - #endregion + void decryptBookCompleted(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Decrypt Step, Completed: {libraryBook.Book}{Environment.NewLine}"); + void downloadPdfBegin(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"PDF Step, Begin: {libraryBook.Book}"); + // extra line after book is completely finished + void downloadPdfCompleted(object _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"PDF Step, Completed: {libraryBook.Book}{Environment.NewLine}"); + #endregion - #region subscribe new form to model's events - backupBook.DownloadBook.Begin += downloadBookBegin; + #region subscribe new form to model's events + backupBook.DownloadBook.Begin += downloadBookBegin; backupBook.DownloadBook.StatusUpdate += statusUpdate; backupBook.DownloadBook.Completed += downloadBookCompleted; backupBook.DecryptBook.Begin += decryptBookBegin; backupBook.DecryptBook.StatusUpdate += statusUpdate; backupBook.DecryptBook.Completed += decryptBookCompleted; - backupBook.DownloadPdf.Begin += downloadPdfBegin; - backupBook.DownloadPdf.StatusUpdate += statusUpdate; - backupBook.DownloadPdf.Completed += downloadPdfCompleted; - #endregion + backupBook.DownloadPdf.Begin += downloadPdfBegin; + backupBook.DownloadPdf.StatusUpdate += statusUpdate; + backupBook.DownloadPdf.Completed += downloadPdfCompleted; + #endregion - #region when form closes, unsubscribe from model's events - // unsubscribe so disposed forms aren't still trying to receive notifications - automatedBackupsForm.FormClosing += (_, __) => + #region when form closes, unsubscribe from model's events + // unsubscribe so disposed forms aren't still trying to receive notifications + automatedBackupsForm.FormClosing += (_, __) => { backupBook.DownloadBook.Begin -= downloadBookBegin; backupBook.DownloadBook.StatusUpdate -= statusUpdate; @@ -225,48 +247,29 @@ namespace LibationWinForm.BookLiberation backupBook.DecryptBook.Begin -= decryptBookBegin; backupBook.DecryptBook.StatusUpdate -= statusUpdate; backupBook.DecryptBook.Completed -= decryptBookCompleted; - backupBook.DownloadPdf.Begin -= downloadPdfBegin; - backupBook.DownloadPdf.StatusUpdate -= statusUpdate; - backupBook.DownloadPdf.Completed -= downloadPdfCompleted; - }; + backupBook.DownloadPdf.Begin -= downloadPdfBegin; + backupBook.DownloadPdf.StatusUpdate -= statusUpdate; + backupBook.DownloadPdf.Completed -= downloadPdfCompleted; + }; #endregion - await runBackupLoop(backupBook, automatedBackupsForm); + return automatedBackupsForm; } // automated backups looper feels like a composible IProcessable: logic, UI, begin + process child + end // however the process step doesn't follow the pattern: Validate(product) + Process(product) - private static async Task runBackupLoop(IProcessable processable, AutomatedBackupsForm automatedBackupsForm) + private static async Task runBackupLoopAsync(IProcessable processable, AutomatedBackupsForm automatedBackupsForm) { automatedBackupsForm.Show(); try { - do + var shouldContinue = true; + while (shouldContinue) { var statusHandler = await processable.ProcessFirstValidAsync(); - - if (statusHandler == null) - { - automatedBackupsForm.AppendText("Done. All books have been processed"); - break; - } - - if (statusHandler.HasErrors) - { - automatedBackupsForm.AppendText("ERROR. All books have not been processed. Most recent valid book: processing failed"); - foreach (var errorMessage in statusHandler.Errors) - automatedBackupsForm.AppendText(errorMessage); - break; - } - - if (!automatedBackupsForm.KeepGoingIsChecked) - { - automatedBackupsForm.AppendText("'Keep going' is unchecked"); - break; - } + shouldContinue = validateStatus(statusHandler, automatedBackupsForm); } - while (automatedBackupsForm.KeepGoingIsChecked); } catch (Exception ex) { @@ -275,5 +278,48 @@ namespace LibationWinForm.BookLiberation automatedBackupsForm.FinalizeUI(); } + + private static async Task runSingleBackupAsync(IProcessable processable, AutomatedBackupsForm automatedBackupsForm, string productId) + { + automatedBackupsForm.Show(); + + try + { + var statusHandler = await processable.ProcessSingleAsync(productId); + validateStatus(statusHandler, automatedBackupsForm); + } + catch (Exception ex) + { + automatedBackupsForm.AppendError(ex); + } + + automatedBackupsForm.FinalizeUI(); + } + + private static bool validateStatus(StatusHandler statusHandler, AutomatedBackupsForm automatedBackupsForm) + { + if (statusHandler == null) + { + automatedBackupsForm.AppendText("Done. All books have been processed"); + return false; + } + + if (statusHandler.HasErrors) + { + automatedBackupsForm.AppendText("ERROR. All books have not been processed. Most recent valid book: processing failed"); + foreach (var errorMessage in statusHandler.Errors) + automatedBackupsForm.AppendText(errorMessage); + return false; + } + + if (!automatedBackupsForm.KeepGoing) + { + if (automatedBackupsForm.KeepGoingVisible && !automatedBackupsForm.KeepGoingChecked) + automatedBackupsForm.AppendText("'Keep going' is unchecked"); + return false; + } + + return true; + } } } diff --git a/LibationWinForm/UNTESTED/Form1.cs b/LibationWinForm/UNTESTED/Form1.cs index 8cb83201..443c221d 100644 --- a/LibationWinForm/UNTESTED/Form1.cs +++ b/LibationWinForm/UNTESTED/Form1.cs @@ -59,7 +59,7 @@ namespace LibationWinForm backupsCountsLbl.Text = "[Calculating backed up book quantities]"; pdfsCountsLbl.Text = "[Calculating backed up PDFs]"; - setBackupCounts(); + setBackupCounts(null, null); } } @@ -86,24 +86,26 @@ namespace LibationWinForm { gridPanel.Controls.Remove(currProductsGrid); currProductsGrid.VisibleCountChanged -= setVisibleCount; + currProductsGrid.BackupCountsChanged -= setBackupCounts; currProductsGrid.Dispose(); } currProductsGrid = new ProductsGrid { Dock = DockStyle.Fill }; currProductsGrid.VisibleCountChanged += setVisibleCount; + currProductsGrid.BackupCountsChanged += setBackupCounts; gridPanel.Controls.Add(currProductsGrid); currProductsGrid.Display(); } ResumeLayout(); } - #endregion + #endregion #region bottom: qty books visible private void setVisibleCount(object _, int qty) => visibleCountLbl.Text = string.Format(visibleCountLbl_Format, qty); - #endregion + #endregion - #region bottom: backup counts - private void setBackupCounts() + #region bottom: backup counts + private void setBackupCounts(object _, object __) { var books = LibraryQueries.GetLibrary_Flat_NoTracking() .Select(sp => sp.Book) @@ -175,8 +177,8 @@ namespace LibationWinForm } #endregion - #region filter - private void filterHelpBtn_Click(object sender, EventArgs e) => new Dialogs.SearchSyntaxDialog().ShowDialog(); + #region filter + private void filterHelpBtn_Click(object sender, EventArgs e) => new Dialogs.SearchSyntaxDialog().ShowDialog(); private void AddFilterBtn_Click(object sender, EventArgs e) { @@ -233,33 +235,25 @@ namespace LibationWinForm MessageBox.Show($"Total processed: {totalProcessed}\r\nNew: {newAdded}"); - // update backup counts if we have new library items - if (newAdded > 0) - setBackupCounts(); - if (totalProcessed > 0) reloadGrid(); } - #endregion - - #region liberate menu - private void setBackupCounts(object _, string __) => setBackupCounts(); + #endregion + #region liberate menu private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e) { - var backupBook = BookLiberation.ProcessorAutomationController.GetWiredUpBackupBook(); - backupBook.DownloadBook.Completed += setBackupCounts; - backupBook.DecryptBook.Completed += setBackupCounts; - backupBook.DownloadPdf.Completed += setBackupCounts; - await BookLiberation.ProcessorAutomationController.RunAutomaticBackup(backupBook); + var backupBook = BookLiberation.ProcessorAutomationController.GetWiredUpBackupBook(updateGridRow); + await BookLiberation.ProcessorAutomationController.RunAutomaticBackupAsync(backupBook); } private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e) { - var downloadPdf = BookLiberation.ProcessorAutomationController.GetWiredUpDownloadPdf(); - downloadPdf.Completed += setBackupCounts; - await BookLiberation.ProcessorAutomationController.RunAutomaticDownload(downloadPdf); + var downloadPdf = BookLiberation.ProcessorAutomationController.GetWiredUpDownloadPdf(updateGridRow); + await BookLiberation.ProcessorAutomationController.RunAutomaticDownloadAsync(downloadPdf); } + + private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshRow(libraryBook.Book.AudibleProductId); #endregion #region quick filters menu diff --git a/LibationWinForm/UNTESTED/ProductsGrid.cs b/LibationWinForm/UNTESTED/ProductsGrid.cs index 56029594..510aed7b 100644 --- a/LibationWinForm/UNTESTED/ProductsGrid.cs +++ b/LibationWinForm/UNTESTED/ProductsGrid.cs @@ -25,8 +25,9 @@ namespace LibationWinForm // - click on Data Sources > ProductItem. drowdown: DataGridView // - drag/drop ProductItem on design surface public partial class ProductsGrid : UserControl - { - public event EventHandler VisibleCountChanged; + { + public event EventHandler VisibleCountChanged; + public event EventHandler BackupCountsChanged; private const string EDIT_TAGS = "Edit Tags"; private const string LIBERATE = "Liberate"; @@ -77,14 +78,19 @@ namespace LibationWinForm e.Value = value; } - private void hiddenFormatting(object _, DataGridViewCellFormattingEventArgs e) + private void hiddenFormatting(object sender, DataGridViewCellFormattingEventArgs e) { + var dgv = (DataGridView)sender; + // no action needed for buttons + if (e.RowIndex < 0 || dgv.Columns[e.ColumnIndex] is DataGridViewButtonColumn) + return; + var isHidden = GetGridEntry(e.RowIndex).TagsEnumerated.Contains("hidden"); - dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Style + dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Style = isHidden ? new DataGridViewCellStyle { ForeColor = Color.LightGray } - : dataGridView.DefaultCellStyle; + : dgv.DefaultCellStyle; } #endregion @@ -107,16 +113,30 @@ namespace LibationWinForm dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = GetGridEntry(e.RowIndex).Download_Status; } - private void liberate_Click(object sender, DataGridViewCellEventArgs e) + private async void liberate_Click(object sender, DataGridViewCellEventArgs e) { var dgv = (DataGridView)sender; if (!isColumnValid(dgv, e.RowIndex, e.ColumnIndex, LIBERATE)) return; + + var productId = GetGridEntry(e.RowIndex).GetBook().AudibleProductId; + var backupBook = BookLiberation.ProcessorAutomationController.GetWiredUpBackupBook((_, __) => RefreshRow(productId)); + await BookLiberation.ProcessorAutomationController.RunSingleBackupAsync(backupBook, productId); } #endregion + public void RefreshRow(string productId) + { + var rowId = GetRowId((ge) => ge.GetBook().AudibleProductId == productId); + + // update cells incl Liberate button text + dataGridView.InvalidateRow(rowId); + + BackupCountsChanged?.Invoke(this, EventArgs.Empty); + } + #region tag buttons private void addEditTagsButtons() { @@ -279,6 +299,8 @@ namespace LibationWinForm // FILTER // filter(); + + BackupCountsChanged?.Invoke(this, EventArgs.Empty); } #region filter diff --git a/REFERENCE.txt b/REFERENCE.txt index e9404b39..421f7754 100644 --- a/REFERENCE.txt +++ b/REFERENCE.txt @@ -1,6 +1,7 @@ -- begin VERSIONING --------------------------------------------------------------------------------------------------------------------- https://github.com/rmcrackan/Libation/releases +v3.1-beta.9 : New feature: liberate individual book v3.1-beta.8 : Bugfix: decrypt file conflict v3.1-beta.7 : Bugfix: decrypt book with no author v3.1-beta.6 : Improved logging