Consolidate queue commands into UI base

This commit is contained in:
MBucari 2025-07-15 13:27:05 -06:00
parent 3d50643ab0
commit b65b1e819b
9 changed files with 141 additions and 187 deletions

View File

@ -5,6 +5,8 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DataLayer; using DataLayer;
using LibationUiBase.Forms; using LibationUiBase.Forms;
using LibationUiBase;
using System.Collections.Generic;
#nullable enable #nullable enable
namespace LibationAvalonia.ViewModels namespace LibationAvalonia.ViewModels
@ -13,19 +15,14 @@ namespace LibationAvalonia.ViewModels
{ {
public void Configure_Liberate() { } public void Configure_Liberate() { }
public void BackupAllBooks() public async Task BackupAllBooks()
{ {
try try
{ {
setQueueCollapseState(false); var unliberated = await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray());
Serilog.Log.Logger.Information("Begin backing up all library books"); if (ProcessQueue.QueueDownloadDecrypt(unliberated))
setQueueCollapseState(false);
ProcessQueue.AddDownloadDecrypt(
DbContexts
.GetLibrary_Flat_NoTracking()
.UnLiberated()
);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -33,10 +30,10 @@ namespace LibationAvalonia.ViewModels
} }
} }
public void BackupAllPdfs() public async Task BackupAllPdfs()
{ {
setQueueCollapseState(false); if (ProcessQueue.QueueDownloadPdf(await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking())))
ProcessQueue.AddDownloadPdf(DbContexts.GetLibrary_Flat_NoTracking().Where(lb => lb.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated)); setQueueCollapseState(false);
} }
public async Task ConvertAllToMp3Async() public async Task ConvertAllToMp3Async()
@ -49,12 +46,8 @@ namespace LibationAvalonia.ViewModels
"Convert all M4b => Mp3?", "Convert all M4b => Mp3?",
MessageBoxButtons.YesNo, MessageBoxButtons.YesNo,
MessageBoxIcon.Warning); MessageBoxIcon.Warning);
if (result == DialogResult.Yes) if (result == DialogResult.Yes && ProcessQueue.QueueConvertToMp3(await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking())))
{
setQueueCollapseState(false); 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) private void setQueueCollapseState(bool collapsed)

View File

@ -1,10 +1,11 @@
using LibationFileManager; using DataLayer;
using System;
using System.Linq;
using DataLayer;
using Dinah.Core; using Dinah.Core;
using LibationFileManager;
using LibationUiBase;
using LibationUiBase.GridView; using LibationUiBase.GridView;
using ReactiveUI; using ReactiveUI;
using System;
using System.Linq;
#nullable enable #nullable enable
namespace LibationAvalonia.ViewModels namespace LibationAvalonia.ViewModels
@ -37,54 +38,16 @@ namespace LibationAvalonia.ViewModels
{ {
try 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]; // liberated: open explorer to file
var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId);
void initiateSingleDownload() if (!Go.To.File(filePath?.ShortPathName))
{ {
//Remove this item from the queue if it's already present and completed. var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
//Only do this when adding a single book at a time to prevent accidental await MessageBox.Show($"File not found" + suffix);
//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);
} }
} }
} }
@ -98,11 +61,10 @@ namespace LibationAvalonia.ViewModels
{ {
try try
{ {
setQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up all {series} episodes", series.LibraryBook); 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) catch (Exception ex)
{ {
@ -114,13 +76,8 @@ namespace LibationAvalonia.ViewModels
{ {
try try
{ {
var preLiberated = libraryBooks.Where(lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated).ToArray(); if (ProcessQueue.QueueConvertToMp3(libraryBooks))
if (preLiberated.Length > 0)
{
Serilog.Log.Logger.Information("Begin convert {count} books to mp3", preLiberated.Length);
setQueueCollapseState(false); setQueueCollapseState(false);
ProcessQueue.AddConvertMp3(preLiberated);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -6,6 +6,8 @@ using Avalonia.Threading;
using LibationAvalonia.Dialogs; using LibationAvalonia.Dialogs;
using ReactiveUI; using ReactiveUI;
using LibationUiBase.Forms; using LibationUiBase.Forms;
using System.Linq;
using LibationUiBase;
#nullable enable #nullable enable
namespace LibationAvalonia.ViewModels namespace LibationAvalonia.ViewModels
@ -72,15 +74,8 @@ namespace LibationAvalonia.ViewModels
{ {
try try
{ {
setQueueCollapseState(false); if (ProcessQueue.QueueDownloadDecrypt(ProductsDisplay.GetVisibleBookEntries().UnLiberated().ToArray()))
setQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up visible library books");
ProcessQueue.AddDownloadDecrypt(
ProductsDisplay
.GetVisibleBookEntries()
.UnLiberated()
);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -17,7 +17,7 @@ using System.Threading.Tasks;
namespace LibationAvalonia.ViewModels namespace LibationAvalonia.ViewModels
{ {
public class ProcessQueueViewModel : ViewModelBase, ILogForm public class ProcessQueueViewModel : ViewModelBase, ILogForm, IProcessQueue
{ {
public ObservableCollection<LogEntry> LogEntries { get; } = new(); public ObservableCollection<LogEntry> LogEntries { get; } = new();
public AvaloniaList<ProcessBookViewModel> Items { get; } = new(); public AvaloniaList<ProcessBookViewModel> Items { get; } = new();
@ -136,15 +136,6 @@ namespace LibationAvalonia.ViewModels
&& entry.Status is ProcessBookStatus.Completed && entry.Status is ProcessBookStatus.Completed
&& Queue.RemoveCompleted(entry); && Queue.RemoveCompleted(entry);
public void AddDownloadPdf(LibraryBook libraryBook)
=> AddDownloadPdf(new List<LibraryBook>() { libraryBook });
public void AddDownloadDecrypt(LibraryBook libraryBook)
=> AddDownloadDecrypt(new List<LibraryBook>() { libraryBook });
public void AddConvertMp3(LibraryBook libraryBook)
=> AddConvertMp3(new List<LibraryBook>() { libraryBook });
public void AddDownloadPdf(IEnumerable<LibraryBook> entries) public void AddDownloadPdf(IEnumerable<LibraryBook> entries)
{ {
List<ProcessBookViewModel> procs = new(); List<ProcessBookViewModel> procs = new();

View File

@ -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<LibraryBook> entries);
void AddConvertMp3(IEnumerable<LibraryBook> entries);
void AddDownloadDecrypt(IEnumerable<LibraryBook> entries);
}
public static class ProcessQueueExtensions
{
public static bool QueueDownloadPdf(this IProcessQueue queue, IList<LibraryBook> 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<LibraryBook> 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<LibraryBook> 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;
}
}

View File

@ -1,4 +1,5 @@
using DataLayer; using DataLayer;
using LibationUiBase;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -11,19 +12,13 @@ namespace LibationWinForms
private void Configure_Liberate() { } private void Configure_Liberate() { }
//GetLibrary_Flat_NoTracking() may take a long time on a hugh library. so run in new thread //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 try
{ {
SetQueueCollapseState(false); var unliberated = await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray());
if (processBookQueue1.QueueDownloadDecrypt(unliberated))
Serilog.Log.Logger.Information("Begin backing up all library books"); SetQueueCollapseState(false);
processBookQueue1.AddDownloadDecrypt(
ApplicationServices.DbContexts
.GetLibrary_Flat_NoTracking()
.UnLiberated()
);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -33,9 +28,8 @@ namespace LibationWinForms
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e) private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
{ {
SetQueueCollapseState(false); if (processBookQueue1.QueueDownloadPdf(await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())))
await Task.Run(() => processBookQueue1.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() SetQueueCollapseState(false);
.Where(lb => lb.Book.UserDefinedItem.PdfStatus is DataLayer.LiberatedStatus.NotLiberated)));
} }
private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e) private async void convertAllM4bToMp3ToolStripMenuItem_Click(object sender, EventArgs e)
@ -48,13 +42,8 @@ namespace LibationWinForms
"Convert all M4b => Mp3?", "Convert all M4b => Mp3?",
MessageBoxButtons.YesNo, MessageBoxButtons.YesNo,
MessageBoxIcon.Warning); MessageBoxIcon.Warning);
if (result == DialogResult.Yes) if (result == DialogResult.Yes && processBookQueue1.QueueConvertToMp3(await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())))
{
SetQueueCollapseState(false); 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.
} }
} }
} }

View File

@ -1,6 +1,8 @@
using DataLayer; using DataLayer;
using Dinah.Core; using Dinah.Core;
using LibationFileManager; using LibationFileManager;
using LibationUiBase;
using LibationUiBase.Forms;
using LibationUiBase.GridView; using LibationUiBase.GridView;
using LibationWinForms.ProcessQueue; using LibationWinForms.ProcessQueue;
using System; using System;
@ -27,53 +29,16 @@ namespace LibationWinForms
{ {
try 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]; // liberated: open explorer to file
var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId);
void initiateSingleDownload() if (!Go.To.File(filePath?.ShortPathName))
{ {
//Remove this item from the queue if it's already present and completed. var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
//Only do this when adding a single book at a time to prevent accidental MessageBox.Show($"File not found" + suffix);
//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);
} }
} }
} }
@ -87,11 +52,10 @@ namespace LibationWinForms
{ {
try try
{ {
SetQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up all {series} episodes", series.LibraryBook); 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) catch (Exception ex)
{ {
@ -103,13 +67,8 @@ namespace LibationWinForms
{ {
try try
{ {
var preLiberated = libraryBooks.Where(lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated).ToArray(); if (processBookQueue1.QueueConvertToMp3(libraryBooks))
if (preLiberated.Length > 0)
{
Serilog.Log.Logger.Information("Begin convert {count} books to mp3", preLiberated.Length);
SetQueueCollapseState(false); SetQueueCollapseState(false);
processBookQueue1.AddConvertMp3(preLiberated);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -5,6 +5,7 @@ using System.Windows.Forms;
using ApplicationServices; using ApplicationServices;
using DataLayer; using DataLayer;
using Dinah.Core.Threading; using Dinah.Core.Threading;
using LibationUiBase;
using LibationWinForms.Dialogs; using LibationWinForms.Dialogs;
namespace LibationWinForms namespace LibationWinForms
@ -58,15 +59,8 @@ namespace LibationWinForms
{ {
try try
{ {
SetQueueCollapseState(false); if (processBookQueue1.QueueDownloadDecrypt(productsDisplay.GetVisible().UnLiberated().ToArray()))
SetQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up visible library books");
processBookQueue1.AddDownloadDecrypt(
productsDisplay
.GetVisible()
.UnLiberated()
);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -11,7 +11,7 @@ using LibationUiBase;
namespace LibationWinForms.ProcessQueue namespace LibationWinForms.ProcessQueue
{ {
internal partial class ProcessQueueControl : UserControl, ILogForm internal partial class ProcessQueueControl : UserControl, ILogForm, IProcessQueue
{ {
private TrackedQueue<ProcessBook> Queue = new(); private TrackedQueue<ProcessBook> Queue = new();
private readonly LogMe Logger; private readonly LogMe Logger;
@ -97,15 +97,6 @@ namespace LibationWinForms.ProcessQueue
&& entry.Status is ProcessBookStatus.Completed && entry.Status is ProcessBookStatus.Completed
&& Queue.RemoveCompleted(entry); && Queue.RemoveCompleted(entry);
public void AddDownloadPdf(DataLayer.LibraryBook libraryBook)
=> AddDownloadPdf(new List<DataLayer.LibraryBook>() { libraryBook });
public void AddDownloadDecrypt(DataLayer.LibraryBook libraryBook)
=> AddDownloadDecrypt(new List<DataLayer.LibraryBook>() { libraryBook });
public void AddConvertMp3(DataLayer.LibraryBook libraryBook)
=> AddConvertMp3(new List<DataLayer.LibraryBook>() { libraryBook });
public void AddDownloadPdf(IEnumerable<DataLayer.LibraryBook> entries) public void AddDownloadPdf(IEnumerable<DataLayer.LibraryBook> entries)
{ {
List<ProcessBook> procs = new(); List<ProcessBook> procs = new();
@ -162,6 +153,9 @@ namespace LibationWinForms.ProcessQueue
} }
private void AddToQueue(IEnumerable<ProcessBook> pbook) private void AddToQueue(IEnumerable<ProcessBook> pbook)
{ {
if (!IsHandleCreated)
CreateControl();
BeginInvoke(() => BeginInvoke(() =>
{ {
Queue.Enqueue(pbook); Queue.Enqueue(pbook);