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 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
{
var unliberated = await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray());
if (ProcessQueue.QueueDownloadDecrypt(unliberated))
setQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up all library books");
ProcessQueue.AddDownloadDecrypt(
DbContexts
.GetLibrary_Flat_NoTracking()
.UnLiberated()
);
}
catch (Exception ex)
{
@ -33,10 +30,10 @@ namespace LibationAvalonia.ViewModels
}
}
public void BackupAllPdfs()
public async Task BackupAllPdfs()
{
if (ProcessQueue.QueueDownloadPdf(await Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking())))
setQueueCollapseState(false);
ProcessQueue.AddDownloadPdf(DbContexts.GetLibrary_Flat_NoTracking().Where(lb => lb.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated));
}
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)

View File

@ -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,36 +38,12 @@ namespace LibationAvalonia.ViewModels
{
try
{
if (libraryBooks.Length == 1)
{
var item = libraryBooks[0];
void initiateSingleDownload()
{
//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);
if (ProcessQueue.QueueDownloadDecrypt(libraryBooks))
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())
else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists())
{
// liberated: open explorer to file
var filePath = AudibleFileStorage.Audio.GetPath(item.Book.AudibleProductId);
var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId);
if (!Go.To.File(filePath?.ShortPathName))
{
var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
@ -74,20 +51,6 @@ namespace LibationAvalonia.ViewModels
}
}
}
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);
}
}
}
catch (Exception ex)
{
Serilog.Log.Logger.Error(ex, "An error occurred while handling the stop light button click for {libraryBook}", libraryBooks);
@ -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)
{

View File

@ -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
{
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)
{

View File

@ -17,7 +17,7 @@ using System.Threading.Tasks;
namespace LibationAvalonia.ViewModels
{
public class ProcessQueueViewModel : ViewModelBase, ILogForm
public class ProcessQueueViewModel : ViewModelBase, ILogForm, IProcessQueue
{
public ObservableCollection<LogEntry> LogEntries { get; } = new();
public AvaloniaList<ProcessBookViewModel> 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>() { 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)
{
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 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
{
var unliberated = await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking().UnLiberated().ToArray());
if (processBookQueue1.QueueDownloadDecrypt(unliberated))
SetQueueCollapseState(false);
Serilog.Log.Logger.Information("Begin backing up all library books");
processBookQueue1.AddDownloadDecrypt(
ApplicationServices.DbContexts
.GetLibrary_Flat_NoTracking()
.UnLiberated()
);
}
catch (Exception ex)
{
@ -33,9 +28,8 @@ namespace LibationWinForms
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (processBookQueue1.QueueDownloadPdf(await Task.Run(() => ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())))
SetQueueCollapseState(false);
await Task.Run(() => processBookQueue1.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking()
.Where(lb => lb.Book.UserDefinedItem.PdfStatus is DataLayer.LiberatedStatus.NotLiberated)));
}
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.
}
}
}

View File

@ -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,35 +29,12 @@ namespace LibationWinForms
{
try
{
if (libraryBooks.Length == 1)
{
var item = libraryBooks[0];
void initiateSingleDownload()
{
//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);
if (processBookQueue1.QueueDownloadDecrypt(libraryBooks))
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())
else if (libraryBooks.Length == 1 && libraryBooks[0].Book.Audio_Exists())
{
// liberated: open explorer to file
var filePath = AudibleFileStorage.Audio.GetPath(item.Book.AudibleProductId);
var filePath = AudibleFileStorage.Audio.GetPath(libraryBooks[0].Book.AudibleProductId);
if (!Go.To.File(filePath?.ShortPathName))
{
var suffix = string.IsNullOrWhiteSpace(filePath) ? "" : $":\r\n{filePath}";
@ -63,20 +42,6 @@ namespace LibationWinForms
}
}
}
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);
}
}
}
catch (Exception ex)
{
Serilog.Log.Logger.Error(ex, "An error occurred while handling the stop light button click for {libraryBook}", libraryBooks);
@ -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)
{

View File

@ -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
{
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)
{

View File

@ -11,7 +11,7 @@ using LibationUiBase;
namespace LibationWinForms.ProcessQueue
{
internal partial class ProcessQueueControl : UserControl, ILogForm
internal partial class ProcessQueueControl : UserControl, ILogForm, IProcessQueue
{
private TrackedQueue<ProcessBook> 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<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)
{
List<ProcessBook> procs = new();
@ -162,6 +153,9 @@ namespace LibationWinForms.ProcessQueue
}
private void AddToQueue(IEnumerable<ProcessBook> pbook)
{
if (!IsHandleCreated)
CreateControl();
BeginInvoke(() =>
{
Queue.Enqueue(pbook);