New feature: check if upgrade available on github
This commit is contained in:
parent
d8a0124b68
commit
d9e0f1aedf
35
FileLiberator/UNTESTED/DownloadFile.cs
Normal file
35
FileLiberator/UNTESTED/DownloadFile.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
|
||||||
|
namespace FileLiberator
|
||||||
|
{
|
||||||
|
// frustratingly copy pasta from DownloadableBase and DownloadPdf
|
||||||
|
public class DownloadFile : IDownloadable
|
||||||
|
{
|
||||||
|
public event EventHandler<string> DownloadBegin;
|
||||||
|
public event EventHandler<DownloadProgress> DownloadProgressChanged;
|
||||||
|
public event EventHandler<string> DownloadCompleted;
|
||||||
|
|
||||||
|
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
|
||||||
|
{
|
||||||
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
var progress = new Progress<DownloadProgress>();
|
||||||
|
progress.ProgressChanged += (_, e) => DownloadProgressChanged?.Invoke(this, e);
|
||||||
|
|
||||||
|
DownloadBegin?.Invoke(this, proposedDownloadFilePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var actualDownloadedFilePath = await client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, progress);
|
||||||
|
return actualDownloadedFilePath;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DownloadCompleted?.Invoke(this, proposedDownloadFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,9 +16,6 @@ namespace FileLiberator
|
|||||||
=> !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook))
|
=> !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook))
|
||||||
&& !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId);
|
&& !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId);
|
||||||
|
|
||||||
private static string getdownloadUrl(LibraryBook libraryBook)
|
|
||||||
=> libraryBook?.Book?.Supplements?.FirstOrDefault()?.Url;
|
|
||||||
|
|
||||||
public override async Task<StatusHandler> ProcessItemAsync(LibraryBook libraryBook)
|
public override async Task<StatusHandler> ProcessItemAsync(LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
var proposedDownloadFilePath = getProposedDownloadFilePath(libraryBook);
|
var proposedDownloadFilePath = getProposedDownloadFilePath(libraryBook);
|
||||||
@ -26,6 +23,11 @@ namespace FileLiberator
|
|||||||
return verifyDownload(libraryBook);
|
return verifyDownload(libraryBook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static StatusHandler verifyDownload(LibraryBook libraryBook)
|
||||||
|
=> !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId)
|
||||||
|
? new StatusHandler { "Downloaded PDF cannot be found" }
|
||||||
|
: new StatusHandler();
|
||||||
|
|
||||||
private static string getProposedDownloadFilePath(LibraryBook libraryBook)
|
private static string getProposedDownloadFilePath(LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
// if audio file exists, get it's dir. else return base Book dir
|
// if audio file exists, get it's dir. else return base Book dir
|
||||||
@ -39,15 +41,15 @@ namespace FileLiberator
|
|||||||
|
|
||||||
private async Task downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
|
private async Task downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
|
||||||
{
|
{
|
||||||
|
var downloadUrl = getdownloadUrl(libraryBook);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
var actualDownloadedFilePath = await PerformDownloadAsync(
|
var actualDownloadedFilePath = await PerformDownloadAsync(
|
||||||
proposedDownloadFilePath,
|
proposedDownloadFilePath,
|
||||||
(p) => client.DownloadFileAsync(getdownloadUrl(libraryBook), proposedDownloadFilePath, p));
|
(p) => client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatusHandler verifyDownload(LibraryBook libraryBook)
|
private static string getdownloadUrl(LibraryBook libraryBook)
|
||||||
=> !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId)
|
=> libraryBook?.Book?.Supplements?.FirstOrDefault()?.Url;
|
||||||
? new StatusHandler { "Downloaded PDF cannot be found" }
|
|
||||||
: new StatusHandler();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ using Dinah.Core.Net.Http;
|
|||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public abstract class DownloadableBase : IDownloadable
|
public abstract class DownloadableBase : IDownloadableProcessable
|
||||||
{
|
{
|
||||||
public event EventHandler<LibraryBook> Begin;
|
public event EventHandler<LibraryBook> Begin;
|
||||||
public event EventHandler<LibraryBook> Completed;
|
public event EventHandler<LibraryBook> Completed;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ using Dinah.Core.Net.Http;
|
|||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public interface IDownloadable : IProcessable
|
public interface IDownloadable
|
||||||
{
|
{
|
||||||
event EventHandler<string> DownloadBegin;
|
event EventHandler<string> DownloadBegin;
|
||||||
event EventHandler<DownloadProgress> DownloadProgressChanged;
|
event EventHandler<DownloadProgress> DownloadProgressChanged;
|
||||||
|
|||||||
4
FileLiberator/UNTESTED/IDownloadableProcessable.cs
Normal file
4
FileLiberator/UNTESTED/IDownloadableProcessable.cs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
namespace FileLiberator
|
||||||
|
{
|
||||||
|
public interface IDownloadableProcessable : IDownloadable, IProcessable { }
|
||||||
|
}
|
||||||
4
LibationLauncher/.msbump
Normal file
4
LibationLauncher/.msbump
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"//": "https://github.com/BalassaMarton/MSBump",
|
||||||
|
BumpRevision: true
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
@ -11,8 +12,18 @@
|
|||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
|
<Version>3.1.0.50</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MSBump" Version="2.3.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Octokit" Version="0.36.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\LibationWinForms\LibationWinForms.csproj" />
|
<ProjectReference Include="..\LibationWinForms\LibationWinForms.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dinah.Core.Logging;
|
|
||||||
using FileManager;
|
using FileManager;
|
||||||
using LibationWinForms;
|
using LibationWinForms;
|
||||||
using LibationWinForms.Dialogs;
|
using LibationWinForms.Dialogs;
|
||||||
@ -21,7 +22,12 @@ namespace LibationLauncher
|
|||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
|
||||||
createSettings();
|
createSettings();
|
||||||
initLogging();
|
|
||||||
|
ensureLoggingConfig();
|
||||||
|
ensureSerilogConfig();
|
||||||
|
configureLogging();
|
||||||
|
checkForUpdate();
|
||||||
|
logStartupState();
|
||||||
|
|
||||||
Application.Run(new Form1());
|
Application.Run(new Form1());
|
||||||
}
|
}
|
||||||
@ -71,47 +77,11 @@ namespace LibationLauncher
|
|||||||
&& !string.IsNullOrWhiteSpace(config.DownloadsInProgressEnum)
|
&& !string.IsNullOrWhiteSpace(config.DownloadsInProgressEnum)
|
||||||
&& !string.IsNullOrWhiteSpace(config.DecryptInProgressEnum);
|
&& !string.IsNullOrWhiteSpace(config.DecryptInProgressEnum);
|
||||||
|
|
||||||
private static void initLogging()
|
private static string defaultLoggingLevel { get; } = "Information";
|
||||||
|
private static void ensureLoggingConfig()
|
||||||
{
|
{
|
||||||
var config = Configuration.Instance;
|
var config = Configuration.Instance;
|
||||||
|
|
||||||
ensureLoggingConfig(config);
|
|
||||||
ensureSerilogConfig(config);
|
|
||||||
|
|
||||||
// override path. always use current libation files
|
|
||||||
var logPath = Path.Combine(Configuration.Instance.LibationFiles, "Log.log");
|
|
||||||
config.SetWithJsonPath("Serilog.WriteTo[1].Args", "path", logPath);
|
|
||||||
|
|
||||||
//// hack which achieves the same
|
|
||||||
//configuration["Serilog:WriteTo:1:Args:path"] = logPath;
|
|
||||||
|
|
||||||
// CONFIGURATION-DRIVEN (json)
|
|
||||||
var configuration = new ConfigurationBuilder()
|
|
||||||
.AddJsonFile(config.SettingsJsonPath)
|
|
||||||
.Build();
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
|
||||||
.ReadFrom.Configuration(configuration)
|
|
||||||
.CreateLogger();
|
|
||||||
|
|
||||||
//// MANUAL HARD CODED
|
|
||||||
//Log.Logger = new LoggerConfiguration()
|
|
||||||
// .Enrich.WithCaller()
|
|
||||||
// .MinimumLevel.Information()
|
|
||||||
// .WriteTo.File(logPath,
|
|
||||||
// rollingInterval: RollingInterval.Month,
|
|
||||||
// outputTemplate: code_outputTemplate)
|
|
||||||
// .CreateLogger();
|
|
||||||
|
|
||||||
Log.Logger.Information("Begin Libation");
|
|
||||||
|
|
||||||
// .Here() captures debug info via System.Runtime.CompilerServices attributes. Warning: expensive
|
|
||||||
//var withLineNumbers_outputTemplate = "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}in method {MemberName} at {FilePath}:{LineNumber}{NewLine}{Exception}{NewLine}";
|
|
||||||
//Log.Logger.Here().Debug("Begin Libation. Debug with line numbers");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string defaultLoggingLevel { get; } = "Information";
|
|
||||||
private static void ensureLoggingConfig(Configuration config)
|
|
||||||
{
|
|
||||||
if (config.GetObject("Logging") != null)
|
if (config.GetObject("Logging") != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -129,8 +99,10 @@ namespace LibationLauncher
|
|||||||
config.SetObject("Logging", loggingObj);
|
config.SetObject("Logging", loggingObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureSerilogConfig(Configuration config)
|
private static void ensureSerilogConfig()
|
||||||
{
|
{
|
||||||
|
var config = Configuration.Instance;
|
||||||
|
|
||||||
if (config.GetObject("Serilog") != null)
|
if (config.GetObject("Serilog") != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -184,5 +156,101 @@ namespace LibationLauncher
|
|||||||
};
|
};
|
||||||
config.SetObject("Serilog", serilogObj);
|
config.SetObject("Serilog", serilogObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void configureLogging()
|
||||||
|
{
|
||||||
|
var config = Configuration.Instance;
|
||||||
|
|
||||||
|
// override path. always use current libation files
|
||||||
|
var logPath = Path.Combine(Configuration.Instance.LibationFiles, "Log.log");
|
||||||
|
config.SetWithJsonPath("Serilog.WriteTo[1].Args", "path", logPath);
|
||||||
|
|
||||||
|
//// hack which achieves the same
|
||||||
|
//configuration["Serilog:WriteTo:1:Args:path"] = logPath;
|
||||||
|
|
||||||
|
// CONFIGURATION-DRIVEN (json)
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.AddJsonFile(config.SettingsJsonPath)
|
||||||
|
.Build();
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
//// MANUAL HARD CODED
|
||||||
|
//Log.Logger = new LoggerConfiguration()
|
||||||
|
// // requires: using Dinah.Core.Logging;
|
||||||
|
// .Enrich.WithCaller()
|
||||||
|
// .MinimumLevel.Information()
|
||||||
|
// .WriteTo.File(logPath,
|
||||||
|
// rollingInterval: RollingInterval.Month,
|
||||||
|
// outputTemplate: code_outputTemplate)
|
||||||
|
// .CreateLogger();
|
||||||
|
|
||||||
|
// .Here() captures debug info via System.Runtime.CompilerServices attributes. Warning: expensive
|
||||||
|
//var withLineNumbers_outputTemplate = "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}in method {MemberName} at {FilePath}:{LineNumber}{NewLine}{Exception}{NewLine}";
|
||||||
|
//Log.Logger.Here().Debug("Begin Libation. Debug with line numbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static event Action cheating;
|
||||||
|
private static void checkForUpdate()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var gitHubClient = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("Libation"));
|
||||||
|
|
||||||
|
// https://octokitnet.readthedocs.io/en/latest/releases/
|
||||||
|
var releases = gitHubClient.Repository.Release.GetAll("rmcrackan", "Libation").GetAwaiter().GetResult();
|
||||||
|
var latest = releases.First(r => !r.Draft);
|
||||||
|
|
||||||
|
var latestVersionString = latest.TagName.Trim('v');
|
||||||
|
if (!Version.TryParse(latestVersionString, out var latestRelease))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// we're up to date
|
||||||
|
if (latestRelease <= BuildVersion)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// we have an update
|
||||||
|
var zip = latest.Assets.FirstOrDefault(a => a.BrowserDownloadUrl.EndsWith(".zip"));
|
||||||
|
var zipUrl = zip?.BrowserDownloadUrl;
|
||||||
|
if (zipUrl is null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(latest.HtmlUrl, "New version available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = MessageBox.Show($"New version available @ {latest.HtmlUrl}\r\nDownload the zip file?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
|
||||||
|
if (result != DialogResult.Yes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var fileSelector = new SaveFileDialog { FileName = zip.Name, Filter = "Zip Files (*.zip)|*.zip|All files (*.*)|*.*" };
|
||||||
|
if (fileSelector.ShowDialog() != DialogResult.OK)
|
||||||
|
return;
|
||||||
|
var selectedPath = fileSelector.FileName;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LibationWinForms.BookLiberation.ProcessorAutomationController.DownloadFileAsync(zipUrl, selectedPath).GetAwaiter().GetResult();
|
||||||
|
MessageBox.Show($"File downloaded");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"ERROR: {ex.Message}\r\n{ex.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Error checking for update. ERROR: {ex.Message}\r\n{ex.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logStartupState()
|
||||||
|
{
|
||||||
|
Log.Logger.Information("Begin Libation");
|
||||||
|
|
||||||
|
Log.Logger.Information($"Version: {BuildVersion}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Version BuildVersion => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,13 +33,13 @@ namespace LibationWinForms.BookLiberation
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region timer
|
#region timer
|
||||||
Timer timer = new Timer { Interval = 1000 };
|
private Timer timer { get; } = new Timer { Interval = 1000 };
|
||||||
private void DownloadForm_Load(object sender, EventArgs e)
|
private void DownloadForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
timer.Tick += new EventHandler(timer_Tick);
|
timer.Tick += new EventHandler(timer_Tick);
|
||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
DateTime lastDownloadProgress = DateTime.Now;
|
private DateTime lastDownloadProgress = DateTime.Now;
|
||||||
private void timer_Tick(object sender, EventArgs e)
|
private void timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// if no update in the last 30 seconds, display frozen label
|
// if no update in the last 30 seconds, display frozen label
|
||||||
|
|||||||
@ -6,15 +6,28 @@ using FileLiberator;
|
|||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
// matches a file processor with a form
|
|
||||||
public static class ProcessorAutomationController
|
public static class ProcessorAutomationController
|
||||||
{
|
{
|
||||||
//
|
public static async Task BackupSingleBookAsync(string productId, EventHandler<LibraryBook> completedAction = null)
|
||||||
// these utility methods ensure proper wiring
|
{
|
||||||
// 1) we can't forget to do it
|
var backupBook = getWiredUpBackupBook(completedAction);
|
||||||
// 2) we can't accidentally do it mult times becaues we lost track of complexity
|
|
||||||
//
|
var automatedBackupsForm = attachToBackupsForm(backupBook);
|
||||||
public static BackupBook GetWiredUpBackupBook(EventHandler<LibraryBook> completedAction = null)
|
automatedBackupsForm.KeepGoingVisible = false;
|
||||||
|
|
||||||
|
await runSingleBackupAsync(backupBook, automatedBackupsForm, productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task BackupAllBooksAsync(EventHandler<LibraryBook> completedAction = null)
|
||||||
|
{
|
||||||
|
var backupBook = getWiredUpBackupBook(completedAction);
|
||||||
|
|
||||||
|
var automatedBackupsForm = attachToBackupsForm(backupBook);
|
||||||
|
|
||||||
|
await runBackupLoopAsync(backupBook, automatedBackupsForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BackupBook getWiredUpBackupBook(EventHandler<LibraryBook> completedAction)
|
||||||
{
|
{
|
||||||
var backupBook = new BackupBook();
|
var backupBook = new BackupBook();
|
||||||
|
|
||||||
@ -32,7 +45,65 @@ namespace LibationWinForms.BookLiberation
|
|||||||
return backupBook;
|
return backupBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DownloadPdf GetWiredUpDownloadPdf(EventHandler<LibraryBook> completedAction = null)
|
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 _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Download Step, Begin: {libraryBook.Book}");
|
||||||
|
void statusUpdate(object _, string str) => automatedBackupsForm.AppendText("- " + 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 _, 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;
|
||||||
|
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
|
||||||
|
|
||||||
|
#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;
|
||||||
|
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
|
||||||
|
|
||||||
|
return automatedBackupsForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task BackupAllPdfsAsync(EventHandler<LibraryBook> completedAction = null)
|
||||||
|
{
|
||||||
|
var downloadPdf = getWiredUpDownloadPdf(completedAction);
|
||||||
|
|
||||||
|
var automatedBackupsForm = attachToBackupsForm(downloadPdf);
|
||||||
|
|
||||||
|
await runBackupLoopAsync(downloadPdf, automatedBackupsForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloadPdf getWiredUpDownloadPdf(EventHandler<LibraryBook> completedAction)
|
||||||
{
|
{
|
||||||
var downloadPdf = new DownloadPdf();
|
var downloadPdf = new DownloadPdf();
|
||||||
|
|
||||||
@ -44,8 +115,25 @@ namespace LibationWinForms.BookLiberation
|
|||||||
return downloadPdf;
|
return downloadPdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task DownloadFileAsync(string url, string destination)
|
||||||
|
{
|
||||||
|
var downloadFile = new DownloadFile();
|
||||||
|
|
||||||
|
// frustratingly copy pasta from wireUpEvents(IDownloadable downloadable) due to Completed being EventHandler<LibraryBook>
|
||||||
|
var downloadDialog = new DownloadForm();
|
||||||
|
downloadFile.DownloadBegin += (_, str) =>
|
||||||
|
{
|
||||||
|
downloadDialog.UpdateFilename(str);
|
||||||
|
downloadDialog.Show();
|
||||||
|
};
|
||||||
|
downloadFile.DownloadProgressChanged += (_, progress) => downloadDialog.DownloadProgressChanged(progress.BytesReceived, progress.TotalBytesToReceive.Value);
|
||||||
|
downloadFile.DownloadCompleted += (_, __) => downloadDialog.Close();
|
||||||
|
|
||||||
|
await downloadFile.PerformDownloadFileAsync(url, destination);
|
||||||
|
}
|
||||||
|
|
||||||
// subscribed to Begin event because a new form should be created+processed+closed on each iteration
|
// subscribed to Begin event because a new form should be created+processed+closed on each iteration
|
||||||
private static void wireUpEvents(IDownloadable downloadable)
|
private static void wireUpEvents(IDownloadableProcessable downloadable)
|
||||||
{
|
{
|
||||||
#region create form
|
#region create form
|
||||||
var downloadDialog = new DownloadForm();
|
var downloadDialog = new DownloadForm();
|
||||||
@ -156,13 +244,7 @@ namespace LibationWinForms.BookLiberation
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task RunAutomaticDownloadAsync(IDownloadable downloadable)
|
private static AutomatedBackupsForm attachToBackupsForm(IDownloadableProcessable downloadable)
|
||||||
{
|
|
||||||
AutomatedBackupsForm automatedBackupsForm = attachToBackupsForm(downloadable);
|
|
||||||
await runBackupLoopAsync(downloadable, automatedBackupsForm);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AutomatedBackupsForm attachToBackupsForm(IDownloadable downloadable)
|
|
||||||
{
|
{
|
||||||
#region create form
|
#region create form
|
||||||
var automatedBackupsForm = new AutomatedBackupsForm();
|
var automatedBackupsForm = new AutomatedBackupsForm();
|
||||||
@ -194,68 +276,6 @@ namespace LibationWinForms.BookLiberation
|
|||||||
return automatedBackupsForm;
|
return automatedBackupsForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 _, LibraryBook libraryBook) => automatedBackupsForm.AppendText($"Download Step, Begin: {libraryBook.Book}");
|
|
||||||
void statusUpdate(object _, string str) => automatedBackupsForm.AppendText("- " + 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 _, 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;
|
|
||||||
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
|
|
||||||
|
|
||||||
#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;
|
|
||||||
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
|
|
||||||
|
|
||||||
return automatedBackupsForm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// automated backups looper feels like a composible IProcessable: logic, UI, begin + process child + end
|
// 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)
|
// however the process step doesn't follow the pattern: Validate(product) + Process(product)
|
||||||
private static async Task runBackupLoopAsync(IProcessable processable, AutomatedBackupsForm automatedBackupsForm)
|
private static async Task runBackupLoopAsync(IProcessable processable, AutomatedBackupsForm automatedBackupsForm)
|
||||||
|
|||||||
@ -112,7 +112,7 @@ namespace LibationWinForms
|
|||||||
enum AudioFileState { full, aax, none }
|
enum AudioFileState { full, aax, none }
|
||||||
private void setBookBackupCounts(IEnumerable<Book> books)
|
private void setBookBackupCounts(IEnumerable<Book> books)
|
||||||
{
|
{
|
||||||
AudioFileState getAudioFileState(string productId)
|
static AudioFileState getAudioFileState(string productId)
|
||||||
{
|
{
|
||||||
if (AudibleFileStorage.Audio.Exists(productId))
|
if (AudibleFileStorage.Audio.Exists(productId))
|
||||||
return AudioFileState.full;
|
return AudioFileState.full;
|
||||||
@ -237,16 +237,10 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
#region liberate menu
|
#region liberate menu
|
||||||
private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
private async void beginBookBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
=> await BookLiberation.ProcessorAutomationController.BackupAllBooksAsync(updateGridRow);
|
||||||
var backupBook = BookLiberation.ProcessorAutomationController.GetWiredUpBackupBook(updateGridRow);
|
|
||||||
await BookLiberation.ProcessorAutomationController.RunAutomaticBackupAsync(backupBook);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
private async void beginPdfBackupsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
=> await BookLiberation.ProcessorAutomationController.BackupAllPdfsAsync(updateGridRow);
|
||||||
var downloadPdf = BookLiberation.ProcessorAutomationController.GetWiredUpDownloadPdf(updateGridRow);
|
|
||||||
await BookLiberation.ProcessorAutomationController.RunAutomaticDownloadAsync(downloadPdf);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshRow(libraryBook.Book.AudibleProductId);
|
private void updateGridRow(object _, LibraryBook libraryBook) => currProductsGrid.RefreshRow(libraryBook.Book.AudibleProductId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -174,18 +174,15 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
var productId = getGridEntry(e.RowIndex).GetBook().AudibleProductId;
|
var productId = getGridEntry(e.RowIndex).GetBook().AudibleProductId;
|
||||||
|
|
||||||
// if liberated, open explorer to file
|
// not liberated: liberate
|
||||||
if (FileManager.AudibleFileStorage.Audio.Exists(productId))
|
if (!FileManager.AudibleFileStorage.Audio.Exists(productId))
|
||||||
|
await BookLiberation.ProcessorAutomationController.BackupSingleBookAsync(productId, (_, __) => RefreshRow(productId));
|
||||||
|
// liberated: open explorer to file
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var filePath = FileManager.AudibleFileStorage.Audio.GetPath(productId);
|
var filePath = FileManager.AudibleFileStorage.Audio.GetPath(productId);
|
||||||
System.Diagnostics.Process.Start("explorer.exe", $"/select, \"{filePath}\"");
|
System.Diagnostics.Process.Start("explorer.exe", $"/select, \"{filePath}\"");
|
||||||
}
|
}
|
||||||
// else liberate
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var backupBook = BookLiberation.ProcessorAutomationController.GetWiredUpBackupBook((_, __) => RefreshRow(productId));
|
|
||||||
await BookLiberation.ProcessorAutomationController.RunSingleBackupAsync(backupBook, productId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user