New feature #241 : Auto download episodes after scanning. Setting is on Import Library tab

This commit is contained in:
Robert McRackan 2022-05-25 15:21:28 -04:00
parent 99527453a7
commit f7a482659c
11 changed files with 1101 additions and 1054 deletions

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<Version>7.8.1.1</Version> <Version>7.9.0.1</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -138,6 +138,9 @@ namespace AppScaffolding
if (!config.Exists(nameof(config.DownloadCoverArt))) if (!config.Exists(nameof(config.DownloadCoverArt)))
config.DownloadCoverArt = true; config.DownloadCoverArt = true;
if (!config.Exists(nameof(config.AutoDownloadEpisodes)))
config.AutoDownloadEpisodes = false;
} }
/// <summary>Initialize logging. Wire-up events. Run after migration</summary> /// <summary>Initialize logging. Wire-up events. Run after migration</summary>

View File

@ -341,7 +341,14 @@ namespace ApplicationServices
// below are queries, not commands. maybe I should make a LibraryQueries. except there's already one of those... // below are queries, not commands. maybe I should make a LibraryQueries. except there's already one of those...
public record LibraryStats(int booksFullyBackedUp, int booksDownloadedOnly, int booksNoProgress, int booksError, int pdfsDownloaded, int pdfsNotDownloaded) { } public record LibraryStats(int booksFullyBackedUp, int booksDownloadedOnly, int booksNoProgress, int booksError, int pdfsDownloaded, int pdfsNotDownloaded)
{
public int PendingBooks => booksNoProgress + booksDownloadedOnly;
public bool HasPendingBooks => PendingBooks > 0;
public bool HasBookResults => 0 < (booksFullyBackedUp + booksDownloadedOnly + booksNoProgress + booksError);
public bool HasPdfResults => 0 < (pdfsNotDownloaded + pdfsDownloaded);
}
public static LibraryStats GetCounts() public static LibraryStats GetCounts()
{ {
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking(); var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();

View File

@ -268,6 +268,13 @@ namespace LibationFileManager
} }
} }
[Description("Auto download episodes? Efter scan, download new books in 'checked' accounts.")]
public bool AutoDownloadEpisodes
{
get => persistentDictionary.GetNonString<bool>(nameof(AutoDownloadEpisodes));
set => persistentDictionary.SetNonString(nameof(AutoDownloadEpisodes), value);
}
#region templates: custom file naming #region templates: custom file naming
[Description("How to format the folders in which files will be saved")] [Description("How to format the folders in which files will be saved")]

View File

@ -53,6 +53,7 @@
this.tab1ImportantSettings = new System.Windows.Forms.TabPage(); this.tab1ImportantSettings = new System.Windows.Forms.TabPage();
this.booksGb = new System.Windows.Forms.GroupBox(); this.booksGb = new System.Windows.Forms.GroupBox();
this.tab2ImportLibrary = new System.Windows.Forms.TabPage(); this.tab2ImportLibrary = new System.Windows.Forms.TabPage();
this.autoDownloadEpisodesCb = new System.Windows.Forms.CheckBox();
this.autoScanCb = new System.Windows.Forms.CheckBox(); this.autoScanCb = new System.Windows.Forms.CheckBox();
this.showImportedStatsCb = new System.Windows.Forms.CheckBox(); this.showImportedStatsCb = new System.Windows.Forms.CheckBox();
this.tab3DownloadDecrypt = new System.Windows.Forms.TabPage(); this.tab3DownloadDecrypt = new System.Windows.Forms.TabPage();
@ -100,8 +101,8 @@
this.lameTargetBitrateRb = new System.Windows.Forms.RadioButton(); this.lameTargetBitrateRb = new System.Windows.Forms.RadioButton();
this.stripUnabridgedCbox = new System.Windows.Forms.CheckBox(); this.stripUnabridgedCbox = new System.Windows.Forms.CheckBox();
this.retainAaxFileCbox = new System.Windows.Forms.CheckBox(); this.retainAaxFileCbox = new System.Windows.Forms.CheckBox();
this.createCueSheetCbox = new System.Windows.Forms.CheckBox();
this.downloadCoverArtCbox = new System.Windows.Forms.CheckBox(); this.downloadCoverArtCbox = new System.Windows.Forms.CheckBox();
this.createCueSheetCbox = new System.Windows.Forms.CheckBox();
this.badBookGb.SuspendLayout(); this.badBookGb.SuspendLayout();
this.tabControl.SuspendLayout(); this.tabControl.SuspendLayout();
this.tab1ImportantSettings.SuspendLayout(); this.tab1ImportantSettings.SuspendLayout();
@ -390,6 +391,7 @@
// //
// tab2ImportLibrary // tab2ImportLibrary
// //
this.tab2ImportLibrary.Controls.Add(this.autoDownloadEpisodesCb);
this.tab2ImportLibrary.Controls.Add(this.autoScanCb); this.tab2ImportLibrary.Controls.Add(this.autoScanCb);
this.tab2ImportLibrary.Controls.Add(this.showImportedStatsCb); this.tab2ImportLibrary.Controls.Add(this.showImportedStatsCb);
this.tab2ImportLibrary.Controls.Add(this.importEpisodesCb); this.tab2ImportLibrary.Controls.Add(this.importEpisodesCb);
@ -402,6 +404,16 @@
this.tab2ImportLibrary.Text = "Import library"; this.tab2ImportLibrary.Text = "Import library";
this.tab2ImportLibrary.UseVisualStyleBackColor = true; this.tab2ImportLibrary.UseVisualStyleBackColor = true;
// //
// autoDownloadEpisodesCb
//
this.autoDownloadEpisodesCb.AutoSize = true;
this.autoDownloadEpisodesCb.Location = new System.Drawing.Point(6, 106);
this.autoDownloadEpisodesCb.Name = "autoDownloadEpisodesCb";
this.autoDownloadEpisodesCb.Size = new System.Drawing.Size(190, 19);
this.autoDownloadEpisodesCb.TabIndex = 5;
this.autoDownloadEpisodesCb.Text = "[auto download episodes desc]";
this.autoDownloadEpisodesCb.UseVisualStyleBackColor = true;
//
// autoScanCb // autoScanCb
// //
this.autoScanCb.AutoSize = true; this.autoScanCb.AutoSize = true;
@ -923,19 +935,6 @@
this.retainAaxFileCbox.UseVisualStyleBackColor = true; this.retainAaxFileCbox.UseVisualStyleBackColor = true;
this.retainAaxFileCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged); this.retainAaxFileCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged);
// //
// createCueSheetCbox
//
this.createCueSheetCbox.AutoSize = true;
this.createCueSheetCbox.Checked = true;
this.createCueSheetCbox.CheckState = System.Windows.Forms.CheckState.Checked;
this.createCueSheetCbox.Location = new System.Drawing.Point(19, 43);
this.createCueSheetCbox.Name = "createCueSheetCbox";
this.createCueSheetCbox.Size = new System.Drawing.Size(145, 19);
this.createCueSheetCbox.TabIndex = 10;
this.createCueSheetCbox.Text = "[CreateCueSheet desc]";
this.createCueSheetCbox.UseVisualStyleBackColor = true;
this.createCueSheetCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged);
//
// downloadCoverArtCbox // downloadCoverArtCbox
// //
this.downloadCoverArtCbox.AutoSize = true; this.downloadCoverArtCbox.AutoSize = true;
@ -949,6 +948,19 @@
this.downloadCoverArtCbox.UseVisualStyleBackColor = true; this.downloadCoverArtCbox.UseVisualStyleBackColor = true;
this.downloadCoverArtCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged); this.downloadCoverArtCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged);
// //
// createCueSheetCbox
//
this.createCueSheetCbox.AutoSize = true;
this.createCueSheetCbox.Checked = true;
this.createCueSheetCbox.CheckState = System.Windows.Forms.CheckState.Checked;
this.createCueSheetCbox.Location = new System.Drawing.Point(19, 43);
this.createCueSheetCbox.Name = "createCueSheetCbox";
this.createCueSheetCbox.Size = new System.Drawing.Size(145, 19);
this.createCueSheetCbox.TabIndex = 10;
this.createCueSheetCbox.Text = "[CreateCueSheet desc]";
this.createCueSheetCbox.UseVisualStyleBackColor = true;
this.createCueSheetCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged);
//
// SettingsDialog // SettingsDialog
// //
this.AcceptButton = this.saveBtn; this.AcceptButton = this.saveBtn;
@ -1072,5 +1084,6 @@
private System.Windows.Forms.CheckBox createCueSheetCbox; private System.Windows.Forms.CheckBox createCueSheetCbox;
private System.Windows.Forms.CheckBox autoScanCb; private System.Windows.Forms.CheckBox autoScanCb;
private System.Windows.Forms.CheckBox downloadCoverArtCbox; private System.Windows.Forms.CheckBox downloadCoverArtCbox;
private System.Windows.Forms.CheckBox autoDownloadEpisodesCb;
} }
} }

View File

@ -35,6 +35,7 @@ namespace LibationWinForms.Dialogs
this.showImportedStatsCb.Text = desc(nameof(config.ShowImportedStats)); this.showImportedStatsCb.Text = desc(nameof(config.ShowImportedStats));
this.importEpisodesCb.Text = desc(nameof(config.ImportEpisodes)); this.importEpisodesCb.Text = desc(nameof(config.ImportEpisodes));
this.downloadEpisodesCb.Text = desc(nameof(config.DownloadEpisodes)); this.downloadEpisodesCb.Text = desc(nameof(config.DownloadEpisodes));
this.autoDownloadEpisodesCb.Text = desc(nameof(config.AutoDownloadEpisodes));
this.booksLocationDescLbl.Text = desc(nameof(config.Books)); this.booksLocationDescLbl.Text = desc(nameof(config.Books));
this.inProgressDescLbl.Text = desc(nameof(config.InProgress)); this.inProgressDescLbl.Text = desc(nameof(config.InProgress));
@ -80,6 +81,7 @@ namespace LibationWinForms.Dialogs
showImportedStatsCb.Checked = config.ShowImportedStats; showImportedStatsCb.Checked = config.ShowImportedStats;
importEpisodesCb.Checked = config.ImportEpisodes; importEpisodesCb.Checked = config.ImportEpisodes;
downloadEpisodesCb.Checked = config.DownloadEpisodes; downloadEpisodesCb.Checked = config.DownloadEpisodes;
autoDownloadEpisodesCb.Checked = config.AutoDownloadEpisodes;
lameTargetRb_CheckedChanged(this, e); lameTargetRb_CheckedChanged(this, e);
LameMatchSourceBRCbox_CheckedChanged(this, e); LameMatchSourceBRCbox_CheckedChanged(this, e);
@ -204,6 +206,7 @@ namespace LibationWinForms.Dialogs
config.ShowImportedStats = showImportedStatsCb.Checked; config.ShowImportedStats = showImportedStatsCb.Checked;
config.ImportEpisodes = importEpisodesCb.Checked; config.ImportEpisodes = importEpisodesCb.Checked;
config.DownloadEpisodes = downloadEpisodesCb.Checked; config.DownloadEpisodes = downloadEpisodesCb.Checked;
config.AutoDownloadEpisodes = autoDownloadEpisodesCb.Checked;
config.InProgress = inProgressSelectControl.SelectedDirectory; config.InProgress = inProgressSelectControl.SelectedDirectory;

View File

@ -6,6 +6,8 @@ namespace LibationWinForms
{ {
public partial class Form1 public partial class Form1
{ {
private System.ComponentModel.BackgroundWorker updateCountsBw = new();
protected void Configure_BackupCounts() protected void Configure_BackupCounts()
{ {
// init formattable // init formattable
@ -16,21 +18,22 @@ namespace LibationWinForms
Load += setBackupCounts; Load += setBackupCounts;
LibraryCommands.LibrarySizeChanged += setBackupCounts; LibraryCommands.LibrarySizeChanged += setBackupCounts;
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts; LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
updateCountsBw.DoWork += UpdateCountsBw_DoWork;
updateCountsBw.RunWorkerCompleted += exportMenuEnable;
updateCountsBw.RunWorkerCompleted += updateBottomBookNumbers;
updateCountsBw.RunWorkerCompleted += update_BeginBookBackups_menuItem;
updateCountsBw.RunWorkerCompleted += updateBottomPdfNumbers;
updateCountsBw.RunWorkerCompleted += udpate_BeginPdfOnlyBackups_menuItem;
} }
private System.ComponentModel.BackgroundWorker updateCountsBw;
private bool runBackupCountsAgain; private bool runBackupCountsAgain;
private void setBackupCounts(object _, object __) private void setBackupCounts(object _, object __)
{ {
runBackupCountsAgain = true; runBackupCountsAgain = true;
if (updateCountsBw is not null) if (!updateCountsBw.IsBusy)
return;
updateCountsBw = new System.ComponentModel.BackgroundWorker();
updateCountsBw.DoWork += UpdateCountsBw_DoWork;
updateCountsBw.RunWorkerCompleted += UpdateCountsBw_RunWorkerCompleted;
updateCountsBw.RunWorkerAsync(); updateCountsBw.RunWorkerAsync();
} }
@ -39,40 +42,27 @@ namespace LibationWinForms
while (runBackupCountsAgain) while (runBackupCountsAgain)
{ {
runBackupCountsAgain = false; runBackupCountsAgain = false;
e.Result = LibraryCommands.GetCounts();
var libraryStats = LibraryCommands.GetCounts();
e.Result = libraryStats;
} }
updateCountsBw = null;
} }
private void UpdateCountsBw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) private void exportMenuEnable(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
{ {
var libraryStats = e.Result as LibraryCommands.LibraryStats; var libraryStats = e.Result as LibraryCommands.LibraryStats;
exportLibraryToolStripMenuItem.Enabled = libraryStats.HasBookResults;
setBookBackupCounts(libraryStats);
setPdfBackupCounts(libraryStats);
} }
// this cannot be cleanly be FormattableToolStripMenuItem because of the optional "Errors" text // this cannot be cleanly be FormattableToolStripMenuItem because of the optional "Errors" text
private const string backupsCountsLbl_Format = "BACKUPS: No progress: {0} In process: {1} Fully backed up: {2}"; private const string backupsCountsLbl_Format = "BACKUPS: No progress: {0} In process: {1} Fully backed up: {2}";
private void setBookBackupCounts(LibraryCommands.LibraryStats libraryStats) private void updateBottomBookNumbers(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
{ {
var pending = libraryStats.booksNoProgress + libraryStats.booksDownloadedOnly; var libraryStats = e.Result as LibraryCommands.LibraryStats;
var hasResults = 0 < (libraryStats.booksFullyBackedUp + libraryStats.booksDownloadedOnly + libraryStats.booksNoProgress + libraryStats.booksError);
// enable/disable export
{
exportLibraryToolStripMenuItem.Enabled = hasResults;
}
// update bottom numbers
{
var formatString var formatString
= !hasResults ? "No books. Begin by importing your library" = !libraryStats.HasBookResults ? "No books. Begin by importing your library"
: libraryStats.booksError > 0 ? backupsCountsLbl_Format + " Errors: {3}" : libraryStats.booksError > 0 ? backupsCountsLbl_Format + " Errors: {3}"
: pending > 0 ? backupsCountsLbl_Format : libraryStats.HasPendingBooks ? backupsCountsLbl_Format
: $"All {"book".PluralizeWithCount(libraryStats.booksFullyBackedUp)} backed up"; : $"All {"book".PluralizeWithCount(libraryStats.booksFullyBackedUp)} backed up";
var statusStripText = string.Format(formatString, var statusStripText = string.Format(formatString,
libraryStats.booksNoProgress, libraryStats.booksNoProgress,
@ -83,33 +73,38 @@ namespace LibationWinForms
} }
// update 'begin book backups' menu item // update 'begin book backups' menu item
private void update_BeginBookBackups_menuItem(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
{ {
var libraryStats = e.Result as LibraryCommands.LibraryStats;
var menuItemText var menuItemText
= pending > 0 = libraryStats.HasPendingBooks
? $"{pending} remaining" ? $"{libraryStats.PendingBooks} remaining"
: "All books have been liberated"; : "All books have been liberated";
menuStrip1.UIThreadAsync(() => menuStrip1.UIThreadAsync(() =>
{ {
beginBookBackupsToolStripMenuItem.Format(menuItemText); beginBookBackupsToolStripMenuItem.Format(menuItemText);
beginBookBackupsToolStripMenuItem.Enabled = pending > 0; beginBookBackupsToolStripMenuItem.Enabled = libraryStats.HasPendingBooks;
}); });
} }
}
private void setPdfBackupCounts(LibraryCommands.LibraryStats libraryStats) private void updateBottomPdfNumbers(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
{ {
// update bottom numbers var libraryStats = e.Result as LibraryCommands.LibraryStats;
{
var hasResults = 0 < (libraryStats.pdfsNotDownloaded + libraryStats.pdfsDownloaded);
// don't need to assign the output of Format(). It just makes this logic cleaner // don't need to assign the output of Format(). It just makes this logic cleaner
var statusStripText var statusStripText
= !hasResults ? "" = !libraryStats.HasPdfResults ? ""
: libraryStats.pdfsNotDownloaded > 0 ? pdfsCountsLbl.Format(libraryStats.pdfsNotDownloaded, libraryStats.pdfsDownloaded) : libraryStats.pdfsNotDownloaded > 0 ? pdfsCountsLbl.Format(libraryStats.pdfsNotDownloaded, libraryStats.pdfsDownloaded)
: $"| All {libraryStats.pdfsDownloaded} PDFs downloaded"; : $"| All {libraryStats.pdfsDownloaded} PDFs downloaded";
statusStrip1.UIThreadAsync(() => pdfsCountsLbl.Text = statusStripText); statusStrip1.UIThreadAsync(() => pdfsCountsLbl.Text = statusStripText);
} }
// update 'begin pdf only backups' menu item // update 'begin pdf only backups' menu item
private void udpate_BeginPdfOnlyBackups_menuItem(object _, System.ComponentModel.RunWorkerCompletedEventArgs e)
{ {
var libraryStats = e.Result as LibraryCommands.LibraryStats;
var menuItemText var menuItemText
= libraryStats.pdfsNotDownloaded > 0 = libraryStats.pdfsNotDownloaded > 0
? $"{libraryStats.pdfsNotDownloaded} remaining" ? $"{libraryStats.pdfsNotDownloaded} remaining"
@ -121,5 +116,4 @@ namespace LibationWinForms
}); });
} }
} }
}
} }

View File

@ -10,7 +10,7 @@ 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 async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e) private async void beginBookBackupsToolStripMenuItem_Click(object _ = null, EventArgs __ = null)
{ {
SetQueueCollapseState(false); SetQueueCollapseState(false);
await Task.Run(() => processBookQueue1.AddDownloadDecrypt(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() await Task.Run(() => processBookQueue1.AddDownloadDecrypt(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking()

View File

@ -1,18 +0,0 @@
using Dinah.Core.Drawing;
using LibationFileManager;
namespace LibationWinForms
{
public partial class Form1
{
private void Configure_PictureStorage()
{
// init default/placeholder cover art
var format = System.Drawing.Imaging.ImageFormat.Jpeg;
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize._500x500, Properties.Resources.default_cover_500x500.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize.Native, Properties.Resources.default_cover_500x500.ToBytes(format));
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ApplicationServices;
using Dinah.Core.Drawing;
using LibationFileManager;
namespace LibationWinForms
{
public partial class Form1
{
private void Configure_NonUI()
{
// init default/placeholder cover art
var format = System.Drawing.Imaging.ImageFormat.Jpeg;
PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize._300x300, Properties.Resources.default_cover_300x300.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize._500x500, Properties.Resources.default_cover_500x500.ToBytes(format));
PictureStorage.SetDefaultImage(PictureSize.Native, Properties.Resources.default_cover_500x500.ToBytes(format));
// wire-up event to automatically download after scan.
// winforms only. this should NOT be allowed in cli
updateCountsBw.RunWorkerCompleted += (object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) =>
{
if (!Configuration.Instance.AutoDownloadEpisodes)
return;
var libraryStats = e.Result as LibraryCommands.LibraryStats;
if ((libraryStats.booksNoProgress + libraryStats.pdfsNotDownloaded) > 0)
beginBookBackupsToolStripMenuItem_Click();
};
}
}
}

View File

@ -38,7 +38,6 @@ namespace LibationWinForms
// these should do nothing interesting yet (storing simple var, subscribe to events) and should never rely on each other for order. // these should do nothing interesting yet (storing simple var, subscribe to events) and should never rely on each other for order.
// otherwise, order could be an issue. // otherwise, order could be an issue.
// eg: if one of these init'd productsGrid, then another can't reliably subscribe to it // eg: if one of these init'd productsGrid, then another can't reliably subscribe to it
Configure_PictureStorage();
Configure_BackupCounts(); Configure_BackupCounts();
Configure_ScanAuto(); Configure_ScanAuto();
Configure_ScanNotification(); Configure_ScanNotification();
@ -50,6 +49,8 @@ namespace LibationWinForms
Configure_Settings(); Configure_Settings();
Configure_ProcessQueue(); Configure_ProcessQueue();
Configure_Filter(); Configure_Filter();
// misc which belongs in winforms app but doesn't have a UI element
Configure_NonUI();
// Configure_Grid(); // since it's just this, can keep here. If it needs more, then give grid it's own 'partial class Form1' // Configure_Grid(); // since it's just this, can keep here. If it needs more, then give grid it's own 'partial class Form1'
{ {