From 73a5d76503e4a181daefa7a308029e92ad75c668 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 14 May 2022 14:39:46 -0600 Subject: [PATCH] Make thread safe and integrate with Libation UI --- Source/LibationWinForms/Form1.Designer.cs | 5 +- Source/LibationWinForms/Form1.Liberate.cs | 12 ++-- Source/LibationWinForms/Form1.ProcessQueue.cs | 10 +--- .../ProcessQueue/ProcessQueueControl.cs | 56 ++++++++++++++++--- Source/LibationWinForms/grid/ProductsGrid.cs | 9 +-- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/Source/LibationWinForms/Form1.Designer.cs b/Source/LibationWinForms/Form1.Designer.cs index cabc4447..2687df4d 100644 --- a/Source/LibationWinForms/Form1.Designer.cs +++ b/Source/LibationWinForms/Form1.Designer.cs @@ -74,7 +74,7 @@ this.splitContainer1 = new System.Windows.Forms.SplitContainer(); this.button1 = new System.Windows.Forms.Button(); this.panel1 = new System.Windows.Forms.Panel(); - this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessBookQueue(); + this.processBookQueue1 = new LibationWinForms.ProcessQueue.ProcessQueueControl(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); @@ -470,7 +470,6 @@ this.button1.TabIndex = 8; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); // // panel1 // @@ -565,7 +564,7 @@ private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem liberateVisible2ToolStripMenuItem; private System.Windows.Forms.SplitContainer splitContainer1; - private LibationWinForms.ProcessQueue.ProcessBookQueue processBookQueue1; + private LibationWinForms.ProcessQueue.ProcessQueueControl processBookQueue1; private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Button button1; } diff --git a/Source/LibationWinForms/Form1.Liberate.cs b/Source/LibationWinForms/Form1.Liberate.cs index 43f91546..b954e5d6 100644 --- a/Source/LibationWinForms/Form1.Liberate.cs +++ b/Source/LibationWinForms/Form1.Liberate.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using System.Windows.Forms; namespace LibationWinForms @@ -7,11 +8,12 @@ namespace LibationWinForms { private void Configure_Liberate() { } - private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e) - => await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync(); + //GetLibrary_Flat_NoTracking() may take a long time on a hugh library. so run in new thread + private void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e) + => Task.Run(()=>processBookQueue1.AddDownloadDecrypt(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())); - private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e) - => await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync(); + private void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e) + => Task.Run(() => processBookQueue1.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())); private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e) { @@ -24,7 +26,7 @@ namespace LibationWinForms MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) - await BookLiberation.ProcessorAutomationController.ConvertAllBooksAsync(); + await Task.Run(() => processBookQueue1.AddConvertMp3(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())); } } } diff --git a/Source/LibationWinForms/Form1.ProcessQueue.cs b/Source/LibationWinForms/Form1.ProcessQueue.cs index 54218c78..f2379cd5 100644 --- a/Source/LibationWinForms/Form1.ProcessQueue.cs +++ b/Source/LibationWinForms/Form1.ProcessQueue.cs @@ -1,4 +1,5 @@ -using LibationFileManager; +using ApplicationServices; +using LibationFileManager; using LibationWinForms.ProcessQueue; using System; using System.Windows.Forms; @@ -9,7 +10,7 @@ namespace LibationWinForms { private void Configure_ProcessQueue() { - //splitContainer1.Panel2Collapsed = true; + productsGrid.LiberateClicked += (_, lb) => processBookQueue1.AddDownloadDecrypt(lb); processBookQueue1.popoutBtn.Click += ProcessBookQueue1_PopOut; } @@ -39,10 +40,5 @@ namespace LibationWinForms this.Focus(); } } - - private void button1_Click(object sender, EventArgs e) - { - processBookQueue1.AddDownloadDecrypt(productsGrid.List); - } } } diff --git a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs index 2df35ef8..8c35ca70 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessQueueControl.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; @@ -12,7 +13,7 @@ namespace LibationWinForms.ProcessQueue { private TrackedQueue Queue = new(); private readonly LogMe Logger; - + private SynchronizationContext SyncContext { get; } = SynchronizationContext.Current; private int QueuedCount { set @@ -70,16 +71,48 @@ namespace LibationWinForms.ProcessQueue CompletedCount = 0; } + public void AddDownloadPdf(IEnumerable entries) + { + Action> makeAll = (lb) => + { + foreach (var entry in entries) + AddDownloadPdf(entry); + }; + //IEnumerable are run on non-ui thread, so send collection to UI first + PassToUIThread(entries, makeAll); + } + public void AddDownloadDecrypt(IEnumerable entries) { - foreach (var entry in entries) - AddDownloadDecrypt(entry); + Action> makeAll = (lb) => + { + foreach (var entry in entries) + AddDownloadDecrypt(entry); + }; + //IEnumerable are run on non-ui thread, so send collection to UI first + PassToUIThread(entries, makeAll); } public void AddConvertMp3(IEnumerable entries) { - foreach (var entry in entries) - AddConvertMp3(entry); + Action> makeAll = (lb) => + { + foreach (var entry in entries) + AddConvertMp3(entry); + }; + //IEnumerable are run on non-ui thread, so send collection to UI first + PassToUIThread(entries, makeAll); + } + + public void AddDownloadPdf(DataLayer.LibraryBook libraryBook) + { + if (Queue.Any(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId)) + return; + + ProcessBook pbook = new(libraryBook, Logger); + pbook.PropertyChanged += Pbook_DataAvailable; + pbook.AddDownloadPdf(); + AddToQueue(pbook); } public void AddDownloadDecrypt(DataLayer.LibraryBook libraryBook) @@ -105,6 +138,15 @@ namespace LibationWinForms.ProcessQueue AddToQueue(pbook); } + private void PassToUIThread(IEnumerable libraryBooks, Action> onComplete) + { + void OnSendOrPostCallback(object asyncArgs) + { + onComplete((IEnumerable)asyncArgs); + } + SyncContext.Send(OnSendOrPostCallback, libraryBooks); + } + private void AddToQueue(ProcessBook pbook) { Queue.Enqueue(pbook); @@ -164,8 +206,8 @@ namespace LibationWinForms.ProcessQueue } private void UpdateProgressBar() { - toolStripProgressBar1.Maximum = Queue.Count; - toolStripProgressBar1.Value = Queue.Completed.Count; + toolStripProgressBar1.Maximum = Queue.Count; + toolStripProgressBar1.Value = Queue.Completed.Count; } private void cancelAllBtn_Click(object sender, EventArgs e) diff --git a/Source/LibationWinForms/grid/ProductsGrid.cs b/Source/LibationWinForms/grid/ProductsGrid.cs index 93caca4d..b088262e 100644 --- a/Source/LibationWinForms/grid/ProductsGrid.cs +++ b/Source/LibationWinForms/grid/ProductsGrid.cs @@ -36,8 +36,10 @@ namespace LibationWinForms // VS has improved since then with .net6+ but I haven't checked again #endregion + public partial class ProductsGrid : UserControl { + public event EventHandler LiberateClicked; /// Number of visible rows has changed public event EventHandler VisibleCountChanged; @@ -76,7 +78,7 @@ namespace LibationWinForms return; if (e.ColumnIndex == liberateGVColumn.Index) - await Liberate_Click(getGridEntry(e.RowIndex)); + Liberate_Click(getGridEntry(e.RowIndex)); else if (e.ColumnIndex == tagAndDetailsGVColumn.Index) Details_Click(getGridEntry(e.RowIndex)); else if (e.ColumnIndex == descriptionGVColumn.Index) @@ -128,7 +130,7 @@ namespace LibationWinForms displayWindow.Show(this); } - private static async Task Liberate_Click(GridEntry liveGridEntry) + private void Liberate_Click(GridEntry liveGridEntry) { var libraryBook = liveGridEntry.LibraryBook; @@ -144,8 +146,7 @@ namespace LibationWinForms return; } - // else: liberate - await liveGridEntry.DownloadBook(); + LiberateClicked?.Invoke(this, liveGridEntry.LibraryBook); } private static void Details_Click(GridEntry liveGridEntry)