Redesign DookLiberation control flow.
This commit is contained in:
parent
963d632208
commit
0045cf05ef
@ -1,6 +1,7 @@
|
|||||||
using AAXClean;
|
using AAXClean;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.IO;
|
using Dinah.Core.IO;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
using Dinah.Core.StepRunner;
|
using Dinah.Core.StepRunner;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -12,8 +13,9 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
public event EventHandler<AppleTags> RetrievedTags;
|
public event EventHandler<AppleTags> RetrievedTags;
|
||||||
public event EventHandler<byte[]> RetrievedCoverArt;
|
public event EventHandler<byte[]> RetrievedCoverArt;
|
||||||
public event EventHandler<int> DecryptProgressUpdate;
|
public event EventHandler<DownloadProgress> DecryptProgressUpdate;
|
||||||
public event EventHandler<TimeSpan> DecryptTimeRemaining;
|
public event EventHandler<TimeSpan> DecryptTimeRemaining;
|
||||||
|
|
||||||
public string AppName { get; set; } = nameof(AaxcDownloadConverter);
|
public string AppName { get; set; } = nameof(AaxcDownloadConverter);
|
||||||
|
|
||||||
private string outputFileName { get; }
|
private string outputFileName { get; }
|
||||||
@ -132,7 +134,14 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
public bool Step2_DownloadAndCombine()
|
public bool Step2_DownloadAndCombine()
|
||||||
{
|
{
|
||||||
DecryptProgressUpdate?.Invoke(this, 0);
|
var zeroProgress = new DownloadProgress
|
||||||
|
{
|
||||||
|
BytesReceived = 0,
|
||||||
|
ProgressPercentage = 0,
|
||||||
|
TotalBytesToReceive = nfsPersister.NetworkFileStream.Length
|
||||||
|
};
|
||||||
|
|
||||||
|
DecryptProgressUpdate?.Invoke(this, zeroProgress);
|
||||||
|
|
||||||
if (File.Exists(outputFileName))
|
if (File.Exists(outputFileName))
|
||||||
FileExt.SafeDelete(outputFileName);
|
FileExt.SafeDelete(outputFileName);
|
||||||
@ -151,7 +160,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
nfsPersister.Dispose();
|
nfsPersister.Dispose();
|
||||||
|
|
||||||
DecryptProgressUpdate?.Invoke(this, 0);
|
DecryptProgressUpdate?.Invoke(this, zeroProgress);
|
||||||
|
|
||||||
return decryptionResult == ConversionResult.NoErrorsDetected && !isCanceled;
|
return decryptionResult == ConversionResult.NoErrorsDetected && !isCanceled;
|
||||||
}
|
}
|
||||||
@ -167,7 +176,13 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
|
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
|
||||||
|
|
||||||
DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
|
DecryptProgressUpdate?.Invoke(this,
|
||||||
|
new DownloadProgress
|
||||||
|
{
|
||||||
|
ProgressPercentage = progressPercent,
|
||||||
|
BytesReceived = (long)(nfsPersister.NetworkFileStream.Length * progressPercent),
|
||||||
|
TotalBytesToReceive = nfsPersister.NetworkFileStream.Length
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Step3_CreateCue()
|
public bool Step3_CreateCue()
|
||||||
@ -209,6 +224,7 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
isCanceled = true;
|
isCanceled = true;
|
||||||
aaxFile?.Cancel();
|
aaxFile?.Cancel();
|
||||||
|
aaxFile?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core.ErrorHandling;
|
using Dinah.Core.ErrorHandling;
|
||||||
using FileManager;
|
|
||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
@ -20,8 +19,14 @@ namespace FileLiberator
|
|||||||
public event EventHandler<string> StatusUpdate;
|
public event EventHandler<string> StatusUpdate;
|
||||||
public event EventHandler<LibraryBook> Completed;
|
public event EventHandler<LibraryBook> Completed;
|
||||||
|
|
||||||
public DownloadDecryptBook DownloadDecryptBook { get; } = new DownloadDecryptBook();
|
public DownloadDecryptBook DownloadDecryptBook { get; }
|
||||||
public DownloadPdf DownloadPdf { get; } = new DownloadPdf();
|
public DownloadPdf DownloadPdf { get; }
|
||||||
|
|
||||||
|
public BackupBook(DownloadDecryptBook downloadDecryptBook, DownloadPdf downloadPdf)
|
||||||
|
{
|
||||||
|
DownloadDecryptBook = downloadDecryptBook;
|
||||||
|
DownloadPdf = downloadPdf;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Validate(LibraryBook libraryBook)
|
public bool Validate(LibraryBook libraryBook)
|
||||||
=> !ApplicationServices.TransitionalFileLocator.Audio_Exists(libraryBook.Book);
|
=> !ApplicationServices.TransitionalFileLocator.Audio_Exists(libraryBook.Book);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using DataLayer;
|
|||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.ErrorHandling;
|
using Dinah.Core.ErrorHandling;
|
||||||
using Dinah.Core.IO;
|
using Dinah.Core.IO;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -11,24 +12,25 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public class ConvertToMp3 : IDecryptable
|
public class ConvertToMp3 : IAudioDecodable
|
||||||
{
|
{
|
||||||
public event EventHandler<string> DecryptBegin;
|
|
||||||
|
private Mp4File m4bBook;
|
||||||
|
|
||||||
|
public event EventHandler<TimeSpan> StreamingTimeRemaining;
|
||||||
|
public event EventHandler<Action<byte[]>> RequestCoverArt;
|
||||||
public event EventHandler<string> TitleDiscovered;
|
public event EventHandler<string> TitleDiscovered;
|
||||||
public event EventHandler<string> AuthorsDiscovered;
|
public event EventHandler<string> AuthorsDiscovered;
|
||||||
public event EventHandler<string> NarratorsDiscovered;
|
public event EventHandler<string> NarratorsDiscovered;
|
||||||
public event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
public event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
||||||
public event EventHandler<int> UpdateProgress;
|
public event EventHandler<string> StreamingBegin;
|
||||||
public event EventHandler<TimeSpan> UpdateRemainingTime;
|
public event EventHandler<DownloadProgress> StreamingProgressChanged;
|
||||||
public event EventHandler<string> DecryptCompleted;
|
public event EventHandler<string> StreamingCompleted;
|
||||||
public event EventHandler<LibraryBook> Begin;
|
public event EventHandler<LibraryBook> Begin;
|
||||||
|
public event EventHandler<string> StatusUpdate;
|
||||||
public event EventHandler<LibraryBook> Completed;
|
public event EventHandler<LibraryBook> Completed;
|
||||||
|
|
||||||
public event EventHandler<string> StatusUpdate;
|
private long fileSize;
|
||||||
public event EventHandler<Action<byte[]>> RequestCoverArt;
|
|
||||||
|
|
||||||
private Mp4File m4bBook;
|
|
||||||
|
|
||||||
private string Mp3FileName(string m4bPath) => m4bPath is null ? string.Empty : PathLib.ReplaceExtension(m4bPath, ".mp3");
|
private string Mp3FileName(string m4bPath) => m4bPath is null ? string.Empty : PathLib.ReplaceExtension(m4bPath, ".mp3");
|
||||||
|
|
||||||
public void Cancel() => m4bBook?.Cancel();
|
public void Cancel() => m4bBook?.Cancel();
|
||||||
@ -43,15 +45,16 @@ namespace FileLiberator
|
|||||||
{
|
{
|
||||||
Begin?.Invoke(this, libraryBook);
|
Begin?.Invoke(this, libraryBook);
|
||||||
|
|
||||||
DecryptBegin?.Invoke(this, $"Begin converting {libraryBook} to mp3");
|
StreamingBegin?.Invoke(this, $"Begin converting {libraryBook} to mp3");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var m4bPath = ApplicationServices.TransitionalFileLocator.Audio_GetPath(libraryBook.Book);
|
var m4bPath = ApplicationServices.TransitionalFileLocator.Audio_GetPath(libraryBook.Book);
|
||||||
|
|
||||||
m4bBook = new Mp4File(m4bPath, FileAccess.Read);
|
m4bBook = new Mp4File(m4bPath, FileAccess.Read);
|
||||||
m4bBook.ConversionProgressUpdate += M4bBook_ConversionProgressUpdate;
|
m4bBook.ConversionProgressUpdate += M4bBook_ConversionProgressUpdate;
|
||||||
|
|
||||||
|
fileSize = m4bBook.InputStream.Length;
|
||||||
|
|
||||||
TitleDiscovered?.Invoke(this, m4bBook.AppleTags.Title);
|
TitleDiscovered?.Invoke(this, m4bBook.AppleTags.Title);
|
||||||
AuthorsDiscovered?.Invoke(this, m4bBook.AppleTags.FirstAuthor);
|
AuthorsDiscovered?.Invoke(this, m4bBook.AppleTags.FirstAuthor);
|
||||||
NarratorsDiscovered?.Invoke(this, m4bBook.AppleTags.Narrator);
|
NarratorsDiscovered?.Invoke(this, m4bBook.AppleTags.Narrator);
|
||||||
@ -76,7 +79,7 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
DecryptCompleted?.Invoke(this, $"Completed converting to mp3: {libraryBook.Book.Title}");
|
StreamingCompleted?.Invoke(this, $"Completed converting to mp3: {libraryBook.Book.Title}");
|
||||||
Completed?.Invoke(this, libraryBook);
|
Completed?.Invoke(this, libraryBook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,11 +91,17 @@ namespace FileLiberator
|
|||||||
double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed;
|
double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed;
|
||||||
|
|
||||||
if (double.IsNormal(estTimeRemaining))
|
if (double.IsNormal(estTimeRemaining))
|
||||||
UpdateRemainingTime?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining));
|
StreamingTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining));
|
||||||
|
|
||||||
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
|
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
|
||||||
|
|
||||||
UpdateProgress?.Invoke(this, (int)progressPercent);
|
StreamingProgressChanged?.Invoke(this,
|
||||||
|
new DownloadProgress
|
||||||
|
{
|
||||||
|
ProgressPercentage = progressPercent,
|
||||||
|
BytesReceived = (long)(fileSize * progressPercent),
|
||||||
|
TotalBytesToReceive = fileSize
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,26 +8,29 @@ using AudibleApi;
|
|||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.ErrorHandling;
|
using Dinah.Core.ErrorHandling;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public class DownloadDecryptBook : IDecryptable
|
public class DownloadDecryptBook : IAudioDecodable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private AaxcDownloadConverter aaxcDownloader;
|
||||||
|
|
||||||
|
public event EventHandler<TimeSpan> StreamingTimeRemaining;
|
||||||
public event EventHandler<Action<byte[]>> RequestCoverArt;
|
public event EventHandler<Action<byte[]>> RequestCoverArt;
|
||||||
public event EventHandler<LibraryBook> Begin;
|
|
||||||
public event EventHandler<string> DecryptBegin;
|
|
||||||
public event EventHandler<string> TitleDiscovered;
|
public event EventHandler<string> TitleDiscovered;
|
||||||
public event EventHandler<string> AuthorsDiscovered;
|
public event EventHandler<string> AuthorsDiscovered;
|
||||||
public event EventHandler<string> NarratorsDiscovered;
|
public event EventHandler<string> NarratorsDiscovered;
|
||||||
public event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
public event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
||||||
public event EventHandler<int> UpdateProgress;
|
public event EventHandler<string> StreamingBegin;
|
||||||
public event EventHandler<TimeSpan> UpdateRemainingTime;
|
public event EventHandler<DownloadProgress> StreamingProgressChanged;
|
||||||
public event EventHandler<string> DecryptCompleted;
|
public event EventHandler<string> StreamingCompleted;
|
||||||
public event EventHandler<LibraryBook> Completed;
|
public event EventHandler<LibraryBook> Begin;
|
||||||
public event EventHandler<string> StatusUpdate;
|
public event EventHandler<string> StatusUpdate;
|
||||||
|
public event EventHandler<LibraryBook> Completed;
|
||||||
|
|
||||||
private AaxcDownloadConverter aaxcDownloader;
|
|
||||||
public async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
|
public async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
Begin?.Invoke(this, libraryBook);
|
Begin?.Invoke(this, libraryBook);
|
||||||
@ -63,7 +66,7 @@ namespace FileLiberator
|
|||||||
|
|
||||||
private async Task<string> aaxToM4bConverterDecryptAsync(string cacheDir, string destinationDir, LibraryBook libraryBook)
|
private async Task<string> aaxToM4bConverterDecryptAsync(string cacheDir, string destinationDir, LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
DecryptBegin?.Invoke(this, $"Begin decrypting {libraryBook}");
|
StreamingBegin?.Invoke(this, $"Begin decrypting {libraryBook}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -103,8 +106,8 @@ namespace FileLiberator
|
|||||||
|
|
||||||
|
|
||||||
aaxcDownloader = new AaxcDownloadConverter(outFileName, cacheDir, aaxcDecryptDlLic, format) { AppName = "Libation" };
|
aaxcDownloader = new AaxcDownloadConverter(outFileName, cacheDir, aaxcDecryptDlLic, format) { AppName = "Libation" };
|
||||||
aaxcDownloader.DecryptProgressUpdate += (s, progress) => UpdateProgress?.Invoke(this, progress);
|
aaxcDownloader.DecryptProgressUpdate += (s, progress) => StreamingProgressChanged?.Invoke(this, progress);
|
||||||
aaxcDownloader.DecryptTimeRemaining += (s, remaining) => UpdateRemainingTime?.Invoke(this, remaining);
|
aaxcDownloader.DecryptTimeRemaining += (s, remaining) => StreamingTimeRemaining?.Invoke(this, remaining);
|
||||||
aaxcDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
|
aaxcDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
|
||||||
aaxcDownloader.RetrievedTags += aaxcDownloader_RetrievedTags;
|
aaxcDownloader.RetrievedTags += aaxcDownloader_RetrievedTags;
|
||||||
|
|
||||||
@ -119,10 +122,11 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
DecryptCompleted?.Invoke(this, $"Completed downloading and decrypting {libraryBook.Book.Title}");
|
StreamingCompleted?.Invoke(this, $"Completed downloading and decrypting {libraryBook.Book.Title}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void AaxcDownloader_RetrievedCoverArt(object sender, byte[] e)
|
private void AaxcDownloader_RetrievedCoverArt(object sender, byte[] e)
|
||||||
{
|
{
|
||||||
if (e is null && Configuration.Instance.AllowLibationFixup)
|
if (e is null && Configuration.Instance.AllowLibationFixup)
|
||||||
|
|||||||
@ -6,20 +6,21 @@ using Dinah.Core.Net.Http;
|
|||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
// currently only used to download the .zip flies for upgrade
|
// currently only used to download the .zip flies for upgrade
|
||||||
public class DownloadFile : IDownloadable
|
public class DownloadFile : IStreamable
|
||||||
{
|
{
|
||||||
public event EventHandler<string> DownloadBegin;
|
public event EventHandler<string> StreamingBegin;
|
||||||
public event EventHandler<DownloadProgress> DownloadProgressChanged;
|
public event EventHandler<DownloadProgress> StreamingProgressChanged;
|
||||||
public event EventHandler<string> DownloadCompleted;
|
public event EventHandler<string> StreamingCompleted;
|
||||||
|
public event EventHandler<TimeSpan> StreamingTimeRemaining;
|
||||||
|
|
||||||
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
|
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
|
||||||
{
|
{
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
var progress = new Progress<DownloadProgress>();
|
var progress = new Progress<DownloadProgress>();
|
||||||
progress.ProgressChanged += (_, e) => DownloadProgressChanged?.Invoke(this, e);
|
progress.ProgressChanged += OnProgressChanged;
|
||||||
|
|
||||||
DownloadBegin?.Invoke(this, proposedDownloadFilePath);
|
StreamingBegin?.Invoke(this, proposedDownloadFilePath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -28,8 +29,12 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
DownloadCompleted?.Invoke(this, proposedDownloadFilePath);
|
StreamingCompleted?.Invoke(this, proposedDownloadFilePath);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
private void OnProgressChanged(object sender, DownloadProgress e)
|
||||||
|
{
|
||||||
|
StreamingProgressChanged?.Invoke(this, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,18 @@ using Dinah.Core.Net.Http;
|
|||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public abstract class DownloadableBase : IDownloadableProcessable
|
public abstract class DownloadableBase : IStreamProcessable
|
||||||
{
|
{
|
||||||
public event EventHandler<LibraryBook> Begin;
|
public event EventHandler<LibraryBook> Begin;
|
||||||
public event EventHandler<LibraryBook> Completed;
|
public event EventHandler<LibraryBook> Completed;
|
||||||
|
|
||||||
public event EventHandler<string> DownloadBegin;
|
public event EventHandler<string> StreamingBegin;
|
||||||
public event EventHandler<DownloadProgress> DownloadProgressChanged;
|
public event EventHandler<DownloadProgress> StreamingProgressChanged;
|
||||||
public event EventHandler<string> DownloadCompleted;
|
public event EventHandler<string> StreamingCompleted;
|
||||||
|
|
||||||
public event EventHandler<string> StatusUpdate;
|
public event EventHandler<string> StatusUpdate;
|
||||||
|
public event EventHandler<TimeSpan> StreamingTimeRemaining;
|
||||||
|
|
||||||
protected void Invoke_StatusUpdate(string message) => StatusUpdate?.Invoke(this, message);
|
protected void Invoke_StatusUpdate(string message) => StatusUpdate?.Invoke(this, message);
|
||||||
|
|
||||||
public abstract bool Validate(LibraryBook libraryBook);
|
public abstract bool Validate(LibraryBook libraryBook);
|
||||||
@ -44,9 +46,9 @@ namespace FileLiberator
|
|||||||
protected async Task<string> PerformDownloadAsync(string proposedDownloadFilePath, Func<Progress<DownloadProgress>, Task<string>> func)
|
protected async Task<string> PerformDownloadAsync(string proposedDownloadFilePath, Func<Progress<DownloadProgress>, Task<string>> func)
|
||||||
{
|
{
|
||||||
var progress = new Progress<DownloadProgress>();
|
var progress = new Progress<DownloadProgress>();
|
||||||
progress.ProgressChanged += (_, e) => DownloadProgressChanged?.Invoke(this, e);
|
progress.ProgressChanged += (_, e) => StreamingProgressChanged?.Invoke(this, e);
|
||||||
|
|
||||||
DownloadBegin?.Invoke(this, proposedDownloadFilePath);
|
StreamingBegin?.Invoke(this, proposedDownloadFilePath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -57,7 +59,7 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
DownloadCompleted?.Invoke(this, proposedDownloadFilePath);
|
StreamingCompleted?.Invoke(this, proposedDownloadFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,17 @@
|
|||||||
using System;
|
using Dinah.Core.Net.Http;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
public interface IDecryptable : IProcessable
|
public interface IAudioDecodable : IStreamProcessable
|
||||||
{
|
{
|
||||||
event EventHandler<string> DecryptBegin;
|
|
||||||
|
|
||||||
event EventHandler<Action<byte[]>> RequestCoverArt;
|
event EventHandler<Action<byte[]>> RequestCoverArt;
|
||||||
event EventHandler<string> TitleDiscovered;
|
event EventHandler<string> TitleDiscovered;
|
||||||
event EventHandler<string> AuthorsDiscovered;
|
event EventHandler<string> AuthorsDiscovered;
|
||||||
event EventHandler<string> NarratorsDiscovered;
|
event EventHandler<string> NarratorsDiscovered;
|
||||||
event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
event EventHandler<byte[]> CoverImageFilepathDiscovered;
|
||||||
event EventHandler<int> UpdateProgress;
|
|
||||||
event EventHandler<TimeSpan> UpdateRemainingTime;
|
|
||||||
|
|
||||||
event EventHandler<string> DecryptCompleted;
|
|
||||||
void Cancel();
|
void Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Dinah.Core.Net.Http;
|
|
||||||
|
|
||||||
namespace FileLiberator
|
|
||||||
{
|
|
||||||
public interface IDownloadable
|
|
||||||
{
|
|
||||||
event EventHandler<string> DownloadBegin;
|
|
||||||
event EventHandler<DownloadProgress> DownloadProgressChanged;
|
|
||||||
event EventHandler<string> DownloadCompleted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
namespace FileLiberator
|
|
||||||
{
|
|
||||||
public interface IDownloadableProcessable : IDownloadable, IProcessable { }
|
|
||||||
}
|
|
||||||
5
FileLiberator/IStreamProcessable.cs
Normal file
5
FileLiberator/IStreamProcessable.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
namespace FileLiberator
|
||||||
|
{
|
||||||
|
public interface IStreamProcessable : IStreamable, IProcessable { }
|
||||||
|
}
|
||||||
13
FileLiberator/IStreamable.cs
Normal file
13
FileLiberator/IStreamable.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
|
||||||
|
namespace FileLiberator
|
||||||
|
{
|
||||||
|
public interface IStreamable
|
||||||
|
{
|
||||||
|
event EventHandler<string> StreamingBegin;
|
||||||
|
event EventHandler<DownloadProgress> StreamingProgressChanged;
|
||||||
|
event EventHandler<TimeSpan> StreamingTimeRemaining;
|
||||||
|
event EventHandler<string> StreamingCompleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -125,7 +125,7 @@ namespace FileManager
|
|||||||
private static HttpClient imageDownloadClient { get; } = new HttpClient();
|
private static HttpClient imageDownloadClient { get; } = new HttpClient();
|
||||||
private static byte[] downloadBytes(PictureDefinition def)
|
private static byte[] downloadBytes(PictureDefinition def)
|
||||||
{
|
{
|
||||||
var sz = ((int)def.Size).ToString();
|
var sz = (int)def.Size;
|
||||||
return imageDownloadClient.GetByteArrayAsync("ht" + $"tps://images-na.ssl-images-amazon.com/images/I/{def.PictureId}._SL{sz}_.jpg").Result;
|
return imageDownloadClient.GetByteArrayAsync("ht" + $"tps://images-na.ssl-images-amazon.com/images/I/{def.PictureId}._SL{sz}_.jpg").Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
<Version>5.4.9.158</Version>
|
<Version>5.4.9.200</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|||||||
@ -63,6 +63,9 @@ namespace LibationLauncher
|
|||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
checkForUpdate(config);
|
checkForUpdate(config);
|
||||||
#endif
|
#endif
|
||||||
|
LibationWinForms.BookLiberation.ProcessorAutomationController.DownloadFile(
|
||||||
|
"https://github.com/rmcrackan/Libation/releases/download/v5.4.9/Libation.5.4.9.zip",
|
||||||
|
@"C:\Users\mbuca\Downloads\libation test dl.zip");
|
||||||
|
|
||||||
Application.Run(new Form1());
|
Application.Run(new Form1());
|
||||||
}
|
}
|
||||||
|
|||||||
28
LibationWinForms/BookLiberation/AudioConvertForm.cs
Normal file
28
LibationWinForms/BookLiberation/AudioConvertForm.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
class AudioConvertForm : AudioDecodeBaseForm
|
||||||
|
{
|
||||||
|
#region AudioDecodeBaseForm overrides
|
||||||
|
public override string DecodeActionName => "Converting";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IProcessable event handler overrides
|
||||||
|
public override void OnBegin(object sender, LibraryBook libraryBook)
|
||||||
|
{
|
||||||
|
InfoLogAction($"Convert Step, Begin: {libraryBook.Book}");
|
||||||
|
|
||||||
|
base.OnBegin(sender, libraryBook);
|
||||||
|
}
|
||||||
|
public override void OnCompleted(object sender, LibraryBook libraryBook)
|
||||||
|
=> InfoLogAction($"Convert Step, Completed: {libraryBook.Book}{Environment.NewLine}");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
partial class DecryptForm
|
partial class AudioDecodeBaseForm
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
129
LibationWinForms/BookLiberation/AudioDecodeBaseForm.cs
Normal file
129
LibationWinForms/BookLiberation/AudioDecodeBaseForm.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
using Dinah.Core.Windows.Forms;
|
||||||
|
using FileLiberator;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
public partial class AudioDecodeBaseForm : ProcessBaseForm
|
||||||
|
{
|
||||||
|
public virtual string DecodeActionName { get; } = "Decoding";
|
||||||
|
public AudioDecodeBaseForm() => InitializeComponent();
|
||||||
|
|
||||||
|
private Func<byte[]> GetCoverArtDelegate;
|
||||||
|
|
||||||
|
// book info
|
||||||
|
private string title;
|
||||||
|
private string authorNames;
|
||||||
|
private string narratorNames;
|
||||||
|
|
||||||
|
public override void SetProcessable(IStreamable streamProcessable, Action<string> infoLog)
|
||||||
|
{
|
||||||
|
base.SetProcessable(streamProcessable, infoLog);
|
||||||
|
|
||||||
|
if (Streamable is not null && Streamable is IAudioDecodable audioDecodable)
|
||||||
|
{
|
||||||
|
OnUnsubscribeAll(this, EventArgs.Empty);
|
||||||
|
|
||||||
|
audioDecodable.RequestCoverArt += OnRequestCoverArt;
|
||||||
|
audioDecodable.TitleDiscovered += OnTitleDiscovered;
|
||||||
|
audioDecodable.AuthorsDiscovered += OnAuthorsDiscovered;
|
||||||
|
audioDecodable.NarratorsDiscovered += OnNarratorsDiscovered;
|
||||||
|
audioDecodable.CoverImageFilepathDiscovered += OnCoverImageFilepathDiscovered;
|
||||||
|
|
||||||
|
Disposed += OnUnsubscribeAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void OnUnsubscribeAll(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Disposed -= OnUnsubscribeAll;
|
||||||
|
if (Streamable is not null && Streamable is IAudioDecodable audioDecodable)
|
||||||
|
{
|
||||||
|
audioDecodable.RequestCoverArt -= OnRequestCoverArt;
|
||||||
|
audioDecodable.TitleDiscovered -= OnTitleDiscovered;
|
||||||
|
audioDecodable.AuthorsDiscovered -= OnAuthorsDiscovered;
|
||||||
|
audioDecodable.NarratorsDiscovered -= OnNarratorsDiscovered;
|
||||||
|
audioDecodable.CoverImageFilepathDiscovered -= OnCoverImageFilepathDiscovered;
|
||||||
|
|
||||||
|
audioDecodable.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IProcessable event handler overrides
|
||||||
|
public override void OnBegin(object sender, LibraryBook libraryBook)
|
||||||
|
{
|
||||||
|
GetCoverArtDelegate = () => FileManager.PictureStorage.GetPictureSynchronously(
|
||||||
|
new FileManager.PictureDefinition(
|
||||||
|
libraryBook.Book.PictureId,
|
||||||
|
FileManager.PictureSize._500x500));
|
||||||
|
|
||||||
|
//Set default values from library
|
||||||
|
OnTitleDiscovered(null, libraryBook.Book.Title);
|
||||||
|
OnAuthorsDiscovered(null, string.Join(", ", libraryBook.Book.Authors));
|
||||||
|
OnNarratorsDiscovered(null, string.Join(", ", libraryBook.Book.NarratorNames));
|
||||||
|
OnCoverImageFilepathDiscovered(null,
|
||||||
|
FileManager.PictureStorage.GetPictureSynchronously(
|
||||||
|
new FileManager.PictureDefinition(
|
||||||
|
libraryBook.Book.PictureId,
|
||||||
|
FileManager.PictureSize._80x80)));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IStreamable event handler overrides
|
||||||
|
|
||||||
|
public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress)
|
||||||
|
{
|
||||||
|
if (!downloadProgress.ProgressPercentage.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (downloadProgress.ProgressPercentage == 0)
|
||||||
|
updateRemainingTime(0);
|
||||||
|
else
|
||||||
|
progressBar1.UIThread(() => progressBar1.Value = (int)downloadProgress.ProgressPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining)
|
||||||
|
=> updateRemainingTime((int)timeRemaining.TotalSeconds);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IAudioDecodable event handlers
|
||||||
|
|
||||||
|
public virtual void OnRequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
|
||||||
|
=> setCoverArtDelegate(GetCoverArtDelegate?.Invoke());
|
||||||
|
|
||||||
|
public virtual void OnTitleDiscovered(object sender, string title)
|
||||||
|
{
|
||||||
|
this.UIThread(() => this.Text = DecodeActionName + " " + title);
|
||||||
|
this.title = title;
|
||||||
|
updateBookInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnAuthorsDiscovered(object sender, string authors)
|
||||||
|
{
|
||||||
|
authorNames = authors;
|
||||||
|
updateBookInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnNarratorsDiscovered(object sender, string narrators)
|
||||||
|
{
|
||||||
|
narratorNames = narrators;
|
||||||
|
updateBookInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnCoverImageFilepathDiscovered(object sender, byte[] coverArt)
|
||||||
|
=> pictureBox1.UIThread(() => pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(coverArt));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
// thread-safe UI updates
|
||||||
|
private void updateBookInfo()
|
||||||
|
=> bookInfoLbl.UIThread(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}");
|
||||||
|
|
||||||
|
private void updateRemainingTime(int remaining)
|
||||||
|
=> remainingTimeLbl.UIThread(() => remainingTimeLbl.Text = $"ETA:\r\n{remaining} sec");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
24
LibationWinForms/BookLiberation/AudioDecryptForm.cs
Normal file
24
LibationWinForms/BookLiberation/AudioDecryptForm.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
class AudioDecryptForm : AudioDecodeBaseForm
|
||||||
|
{
|
||||||
|
#region AudioDecodeBaseForm overrides
|
||||||
|
public override string DecodeActionName => "Decrypting";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IProcessable event handler overrides
|
||||||
|
public override void OnBegin(object sender, LibraryBook libraryBook)
|
||||||
|
{
|
||||||
|
InfoLogAction($"Download & Decrypt Step, Begin: {libraryBook.Book}");
|
||||||
|
|
||||||
|
base.OnBegin(sender, libraryBook);
|
||||||
|
}
|
||||||
|
public override void OnCompleted(object sender, LibraryBook libraryBook)
|
||||||
|
=> InfoLogAction($"Download & Decrypt Step, Completed: {libraryBook.Book}{Environment.NewLine}");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,55 +0,0 @@
|
|||||||
using Dinah.Core.Windows.Forms;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
|
||||||
{
|
|
||||||
public partial class DecryptForm : Form
|
|
||||||
{
|
|
||||||
public DecryptForm() => InitializeComponent();
|
|
||||||
|
|
||||||
// book info
|
|
||||||
private string title;
|
|
||||||
private string authorNames;
|
|
||||||
private string narratorNames;
|
|
||||||
|
|
||||||
public void SetTitle(string actionName, string title)
|
|
||||||
{
|
|
||||||
this.UIThread(() => this.Text = actionName + " " + title);
|
|
||||||
this.title = title;
|
|
||||||
updateBookInfo();
|
|
||||||
}
|
|
||||||
public void SetAuthorNames(string authorNames)
|
|
||||||
{
|
|
||||||
this.authorNames = authorNames;
|
|
||||||
updateBookInfo();
|
|
||||||
}
|
|
||||||
public void SetNarratorNames(string narratorNames)
|
|
||||||
{
|
|
||||||
this.narratorNames = narratorNames;
|
|
||||||
updateBookInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
// thread-safe UI updates
|
|
||||||
private void updateBookInfo()
|
|
||||||
=> bookInfoLbl.UIThread(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}");
|
|
||||||
|
|
||||||
public void SetCoverImage(System.Drawing.Image coverImage)
|
|
||||||
=> pictureBox1.UIThread(() => pictureBox1.Image = coverImage);
|
|
||||||
|
|
||||||
public void UpdateProgress(int percentage)
|
|
||||||
{
|
|
||||||
if (percentage == 0)
|
|
||||||
updateRemainingTime(0);
|
|
||||||
else
|
|
||||||
progressBar1.UIThread(() => progressBar1.Value = percentage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateRemainingTime(TimeSpan remaining)
|
|
||||||
=> updateRemainingTime((int)remaining.TotalSeconds);
|
|
||||||
|
|
||||||
private void updateRemainingTime(int remaining)
|
|
||||||
=> remainingTimeLbl.UIThread(() => remainingTimeLbl.Text = $"ETA:\r\n{remaining} sec");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,13 @@
|
|||||||
using Dinah.Core.Windows.Forms;
|
using DataLayer;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
using Dinah.Core.Windows.Forms;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace LibationWinForms.BookLiberation
|
namespace LibationWinForms.BookLiberation
|
||||||
{
|
{
|
||||||
public partial class DownloadForm : Form
|
public partial class DownloadForm : ProcessBaseForm
|
||||||
{
|
{
|
||||||
public DownloadForm()
|
public DownloadForm()
|
||||||
{
|
{
|
||||||
@ -15,23 +17,27 @@ namespace LibationWinForms.BookLiberation
|
|||||||
filenameLbl.Text = "";
|
filenameLbl.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread-safe UI updates
|
#region IStreamable event handler overrides
|
||||||
public void UpdateFilename(string title) => filenameLbl.UIThread(() => filenameLbl.Text = title);
|
public override void OnStreamingBegin(object sender, string beginString)
|
||||||
|
{
|
||||||
public void DownloadProgressChanged(long BytesReceived, long? TotalBytesToReceive)
|
filenameLbl.UIThread(() => filenameLbl.Text = beginString);
|
||||||
|
base.OnStreamingBegin(sender, beginString);
|
||||||
|
}
|
||||||
|
public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress)
|
||||||
{
|
{
|
||||||
// this won't happen with download file. it will happen with download string
|
// this won't happen with download file. it will happen with download string
|
||||||
if (!TotalBytesToReceive.HasValue || TotalBytesToReceive.Value <= 0)
|
if (!downloadProgress.TotalBytesToReceive.HasValue || downloadProgress.TotalBytesToReceive.Value <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
progressLbl.UIThread(() => progressLbl.Text = $"{BytesReceived:#,##0} of {TotalBytesToReceive.Value:#,##0}");
|
progressLbl.UIThread(() => progressLbl.Text = $"{downloadProgress.BytesReceived:#,##0} of {downloadProgress.TotalBytesToReceive.Value:#,##0}");
|
||||||
|
|
||||||
var d = double.Parse(BytesReceived.ToString()) / double.Parse(TotalBytesToReceive.Value.ToString()) * 100.0;
|
var d = double.Parse(downloadProgress.BytesReceived.ToString()) / double.Parse(downloadProgress.TotalBytesToReceive.Value.ToString()) * 100.0;
|
||||||
var i = int.Parse(Math.Truncate(d).ToString());
|
var i = int.Parse(Math.Truncate(d).ToString());
|
||||||
progressBar1.UIThread(() => progressBar1.Value = i);
|
progressBar1.UIThread(() => progressBar1.Value = i);
|
||||||
|
|
||||||
lastDownloadProgress = DateTime.Now;
|
lastDownloadProgress = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region timer
|
#region timer
|
||||||
private Timer timer { get; } = new Timer { Interval = 1000 };
|
private Timer timer { get; } = new Timer { Interval = 1000 };
|
||||||
|
|||||||
16
LibationWinForms/BookLiberation/PdfDownloadForm.cs
Normal file
16
LibationWinForms/BookLiberation/PdfDownloadForm.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
internal class PdfDownloadForm : DownloadForm
|
||||||
|
{
|
||||||
|
public override void OnBegin(object sender, LibraryBook libraryBook) => InfoLogAction($"PDF Step, Begin: {libraryBook.Book}");
|
||||||
|
public override void OnCompleted(object sender, LibraryBook libraryBook) => InfoLogAction($"PDF Step, Completed: {libraryBook.Book}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
45
LibationWinForms/BookLiberation/ProcessBaseForm.cs
Normal file
45
LibationWinForms/BookLiberation/ProcessBaseForm.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using DataLayer;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
using FileLiberator;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
public class ProcessBaseForm : StreamBaseForm
|
||||||
|
{
|
||||||
|
protected Action<string> InfoLogAction { get; private set; }
|
||||||
|
public virtual void SetProcessable(IStreamable streamable, Action<string> infoLog)
|
||||||
|
{
|
||||||
|
InfoLogAction = infoLog;
|
||||||
|
SetStreamable(streamable);
|
||||||
|
|
||||||
|
if (Streamable is not null && Streamable is IProcessable processable)
|
||||||
|
{
|
||||||
|
OnUnsubscribeAll(this, EventArgs.Empty);
|
||||||
|
|
||||||
|
processable.Begin += OnBegin;
|
||||||
|
processable.Completed += OnCompleted;
|
||||||
|
processable.StatusUpdate += OnStatusUpdate;
|
||||||
|
Disposed += OnUnsubscribeAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnsubscribeAll(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Disposed -= OnUnsubscribeAll;
|
||||||
|
if (Streamable is not null && Streamable is IProcessable processable)
|
||||||
|
{
|
||||||
|
processable.Begin -= OnBegin;
|
||||||
|
processable.Completed -= OnCompleted;
|
||||||
|
processable.StatusUpdate -= OnStatusUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IProcessable event handlers
|
||||||
|
public virtual void OnBegin(object sender, LibraryBook libraryBook) => InfoLogAction($"Begin: {libraryBook.Book}");
|
||||||
|
public virtual void OnStatusUpdate(object sender, string statusUpdate) => InfoLogAction("- " + statusUpdate);
|
||||||
|
public virtual void OnCompleted(object sender, LibraryBook libraryBook) => InfoLogAction($"Completed: {libraryBook.Book}{Environment.NewLine}");
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -55,153 +55,65 @@ namespace LibationWinForms.BookLiberation
|
|||||||
{
|
{
|
||||||
Serilog.Log.Logger.Information("Begin backup single {@DebugInfo}", new { libraryBook?.Book?.AudibleProductId });
|
Serilog.Log.Logger.Information("Begin backup single {@DebugInfo}", new { libraryBook?.Book?.AudibleProductId });
|
||||||
|
|
||||||
var backupBook = getWiredUpBackupBook(completedAction);
|
LogMe logMe = LogMe.RegisterForm();
|
||||||
|
var backupBook = CreateBackupBook(completedAction, logMe);
|
||||||
(Action unsubscribeEvents, LogMe logMe) = attachToBackupsForm(backupBook);
|
|
||||||
|
|
||||||
// continue even if libraryBook is null. we'll display even that in the processing box
|
// continue even if libraryBook is null. we'll display even that in the processing box
|
||||||
await new BackupSingle(logMe, backupBook, libraryBook).RunBackupAsync();
|
await new BackupSingle(logMe, backupBook, libraryBook).RunBackupAsync();
|
||||||
|
|
||||||
unsubscribeEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task BackupAllBooksAsync(EventHandler<LibraryBook> completedAction = null)
|
public static async Task BackupAllBooksAsync(EventHandler<LibraryBook> completedAction = null)
|
||||||
{
|
{
|
||||||
Serilog.Log.Logger.Information("Begin " + nameof(BackupAllBooksAsync));
|
Serilog.Log.Logger.Information("Begin " + nameof(BackupAllBooksAsync));
|
||||||
|
|
||||||
var backupBook = getWiredUpBackupBook(completedAction);
|
|
||||||
var automatedBackupsForm = new AutomatedBackupsForm();
|
var automatedBackupsForm = new AutomatedBackupsForm();
|
||||||
|
LogMe logMe = LogMe.RegisterForm(automatedBackupsForm);
|
||||||
|
|
||||||
(Action unsubscribeEvents, LogMe logMe) = attachToBackupsForm(backupBook, automatedBackupsForm);
|
var backupBook = CreateBackupBook(completedAction, logMe);
|
||||||
|
|
||||||
await new BackupLoop(logMe, backupBook, automatedBackupsForm).RunBackupAsync();
|
await new BackupLoop(logMe, backupBook, automatedBackupsForm).RunBackupAsync();
|
||||||
|
|
||||||
unsubscribeEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ConvertAllBooksAsync()
|
public static async Task ConvertAllBooksAsync()
|
||||||
{
|
{
|
||||||
Serilog.Log.Logger.Information("Begin " + nameof(ConvertAllBooksAsync));
|
Serilog.Log.Logger.Information("Begin " + nameof(ConvertAllBooksAsync));
|
||||||
|
|
||||||
var convertBook = new ConvertToMp3();
|
|
||||||
convertBook.Begin += (_, l) => wireUpEvents(convertBook, l, "Converting");
|
|
||||||
|
|
||||||
var automatedBackupsForm = new AutomatedBackupsForm();
|
var automatedBackupsForm = new AutomatedBackupsForm();
|
||||||
|
LogMe logMe = LogMe.RegisterForm(automatedBackupsForm);
|
||||||
|
|
||||||
var logMe = LogMe.RegisterForm(automatedBackupsForm);
|
var convertBook = CreateStreamableProcessable<ConvertToMp3, AudioConvertForm>(null, logMe);
|
||||||
|
|
||||||
void statusUpdate(object _, string str) => logMe.Info("- " + str);
|
|
||||||
void convertBookBegin(object _, LibraryBook libraryBook) => logMe.Info($"Convert Step, Begin: {libraryBook.Book}");
|
|
||||||
void convertBookCompleted(object _, LibraryBook libraryBook) => logMe.Info($"Convert Step, Completed: {libraryBook.Book}{Environment.NewLine}");
|
|
||||||
convertBook.Begin += convertBookBegin;
|
|
||||||
convertBook.StatusUpdate += statusUpdate;
|
|
||||||
convertBook.Completed += convertBookCompleted;
|
|
||||||
|
|
||||||
await new BackupLoop(logMe, convertBook, automatedBackupsForm).RunBackupAsync();
|
await new BackupLoop(logMe, convertBook, automatedBackupsForm).RunBackupAsync();
|
||||||
|
|
||||||
convertBook.Begin -= convertBookBegin;
|
|
||||||
convertBook.StatusUpdate -= statusUpdate;
|
|
||||||
convertBook.Completed -= convertBookCompleted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BackupBook getWiredUpBackupBook(EventHandler<LibraryBook> completedAction)
|
private static BackupBook CreateBackupBook(EventHandler<LibraryBook> completedAction, LogMe logMe)
|
||||||
{
|
{
|
||||||
var backupBook = new BackupBook();
|
var downloadPdf = CreateStreamableProcessable<DownloadPdf, DownloadForm>(completedAction, logMe);
|
||||||
|
var downloadDecryptBook = CreateStreamableProcessable<DownloadDecryptBook, AudioDecryptForm>(completedAction, logMe);
|
||||||
backupBook.DownloadDecryptBook.Begin += (_, l) => wireUpEvents(backupBook.DownloadDecryptBook, l);
|
return new BackupBook(downloadDecryptBook, downloadPdf);
|
||||||
backupBook.DownloadPdf.Begin += (_, __) => wireUpEvents(backupBook.DownloadPdf);
|
|
||||||
|
|
||||||
if (completedAction != null)
|
|
||||||
{
|
|
||||||
backupBook.DownloadDecryptBook.Completed += completedAction;
|
|
||||||
backupBook.DownloadPdf.Completed += completedAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
return backupBook;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (Action unsubscribeEvents, LogMe) attachToBackupsForm(BackupBook backupBook, AutomatedBackupsForm automatedBackupsForm = null)
|
|
||||||
{
|
|
||||||
#region create logger
|
|
||||||
var logMe = LogMe.RegisterForm(automatedBackupsForm);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region define how model actions will affect form behavior
|
|
||||||
void statusUpdate(object _, string str) => logMe.Info("- " + str);
|
|
||||||
void decryptBookBegin(object _, LibraryBook libraryBook) => logMe.Info($"Decrypt Step, Begin: {libraryBook.Book}");
|
|
||||||
// extra line after book is completely finished
|
|
||||||
void decryptBookCompleted(object _, LibraryBook libraryBook) => logMe.Info($"Decrypt Step, Completed: {libraryBook.Book}{Environment.NewLine}");
|
|
||||||
void downloadPdfBegin(object _, LibraryBook libraryBook) => logMe.Info($"PDF Step, Begin: {libraryBook.Book}");
|
|
||||||
// extra line after book is completely finished
|
|
||||||
void downloadPdfCompleted(object _, LibraryBook libraryBook) => logMe.Info($"PDF Step, Completed: {libraryBook.Book}{Environment.NewLine}");
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region subscribe new form to model's events
|
|
||||||
backupBook.DownloadDecryptBook.Begin += decryptBookBegin;
|
|
||||||
backupBook.DownloadDecryptBook.StatusUpdate += statusUpdate;
|
|
||||||
backupBook.DownloadDecryptBook.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
|
|
||||||
Action unsubscribe = () =>
|
|
||||||
{
|
|
||||||
backupBook.DownloadDecryptBook.Begin -= decryptBookBegin;
|
|
||||||
backupBook.DownloadDecryptBook.StatusUpdate -= statusUpdate;
|
|
||||||
backupBook.DownloadDecryptBook.Completed -= decryptBookCompleted;
|
|
||||||
backupBook.DownloadPdf.Begin -= downloadPdfBegin;
|
|
||||||
backupBook.DownloadPdf.StatusUpdate -= statusUpdate;
|
|
||||||
backupBook.DownloadPdf.Completed -= downloadPdfCompleted;
|
|
||||||
};
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
return (unsubscribe, logMe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task BackupAllPdfsAsync(EventHandler<LibraryBook> completedAction = null)
|
public static async Task BackupAllPdfsAsync(EventHandler<LibraryBook> completedAction = null)
|
||||||
{
|
{
|
||||||
Serilog.Log.Logger.Information("Begin " + nameof(BackupAllPdfsAsync));
|
Serilog.Log.Logger.Information("Begin " + nameof(BackupAllPdfsAsync));
|
||||||
|
|
||||||
var downloadPdf = getWiredUpDownloadPdf(completedAction);
|
var automatedBackupsForm = new AutomatedBackupsForm();
|
||||||
|
LogMe logMe = LogMe.RegisterForm(automatedBackupsForm);
|
||||||
|
|
||||||
|
var downloadPdf = CreateStreamableProcessable<DownloadPdf, DownloadForm>(completedAction, logMe);
|
||||||
|
|
||||||
(AutomatedBackupsForm automatedBackupsForm, LogMe logMe) = attachToBackupsForm(downloadPdf);
|
|
||||||
await new BackupLoop(logMe, downloadPdf, automatedBackupsForm).RunBackupAsync();
|
await new BackupLoop(logMe, downloadPdf, automatedBackupsForm).RunBackupAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DownloadPdf getWiredUpDownloadPdf(EventHandler<LibraryBook> completedAction)
|
|
||||||
{
|
|
||||||
var downloadPdf = new DownloadPdf();
|
|
||||||
|
|
||||||
downloadPdf.Begin += (_, __) => wireUpEvents(downloadPdf);
|
|
||||||
|
|
||||||
if (completedAction != null)
|
|
||||||
downloadPdf.Completed += completedAction;
|
|
||||||
|
|
||||||
return downloadPdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DownloadFile(string url, string destination, bool showDownloadCompletedDialog = false)
|
public static void DownloadFile(string url, string destination, bool showDownloadCompletedDialog = false)
|
||||||
{
|
{
|
||||||
var downloadDialog = new DownloadForm();
|
|
||||||
downloadDialog.UpdateFilename(destination);
|
|
||||||
downloadDialog.Show();
|
|
||||||
|
|
||||||
new System.Threading.Thread(() =>
|
new System.Threading.Thread(() =>
|
||||||
{
|
{
|
||||||
var downloadFile = new DownloadFile();
|
(DownloadFile downloadFile, DownloadForm downloadForm) = CreateStreamable<DownloadFile, DownloadForm>();
|
||||||
|
|
||||||
downloadFile.DownloadProgressChanged += (_, progress) => downloadDialog.UIThread(() =>
|
|
||||||
downloadDialog.DownloadProgressChanged(progress.BytesReceived, progress.TotalBytesToReceive)
|
|
||||||
);
|
|
||||||
downloadFile.DownloadCompleted += (_, __) => downloadDialog.UIThread(() =>
|
|
||||||
{
|
|
||||||
downloadDialog.Close();
|
|
||||||
if (showDownloadCompletedDialog)
|
if (showDownloadCompletedDialog)
|
||||||
MessageBox.Show("File downloaded");
|
downloadFile.StreamingCompleted += (_, __) => MessageBox.Show("File downloaded");
|
||||||
});
|
|
||||||
|
|
||||||
downloadFile.PerformDownloadFileAsync(url, destination).GetAwaiter().GetResult();
|
downloadFile.PerformDownloadFileAsync(url, destination).GetAwaiter().GetResult();
|
||||||
})
|
})
|
||||||
@ -209,171 +121,41 @@ namespace LibationWinForms.BookLiberation
|
|||||||
.Start();
|
.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribed to Begin event because a new form should be created+processed+closed on each iteration
|
/// <summary>
|
||||||
private static void wireUpEvents(IDownloadableProcessable downloadable)
|
/// Create a new <see cref="IStreamProcessable"/> and which creates a new <see cref="ProcessBaseForm"/> on IProcessable.Begin.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TStrProc">The <see cref="IStreamProcessable"/> derrived type to create.</typeparam>
|
||||||
|
/// <typeparam name="TForm">The <see cref="ProcessBaseForm"/> derrived form to create on Begin</typeparam>
|
||||||
|
/// <param name="completedAction">An additional event handler to handle <typeparamref name="TStrProc"/>.Completed</param>
|
||||||
|
/// <returns>A new <see cref="IStreamProcessable"/> of type <typeparamref name="TStrProc"/></returns>
|
||||||
|
private static TStrProc CreateStreamableProcessable<TStrProc, TForm>(EventHandler<LibraryBook> completedAction = null, LogMe logMe = null)
|
||||||
|
where TForm : ProcessBaseForm, new()
|
||||||
|
where TStrProc : IStreamProcessable, new()
|
||||||
{
|
{
|
||||||
#region create form
|
var strProc = new TStrProc();
|
||||||
var downloadDialog = new DownloadForm();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// extra complexity for wiring up download form:
|
strProc.Begin += (sender, libraryBook) =>
|
||||||
// case 1: download is needed
|
|
||||||
// dialog created. subscribe to events
|
|
||||||
// downloadable.DownloadBegin fires. shows dialog
|
|
||||||
// downloadable.DownloadCompleted fires. closes dialog. which fires FormClosing, FormClosed, Disposed
|
|
||||||
// Disposed unsubscribe from events
|
|
||||||
// case 2: download is not needed
|
|
||||||
// dialog created. subscribe to events
|
|
||||||
// dialog is never shown nor closed
|
|
||||||
// downloadable.Completed fires. disposes dialog and unsubscribes from events
|
|
||||||
|
|
||||||
#region define how model actions will affect form behavior
|
|
||||||
void downloadBegin(object _, string str)
|
|
||||||
{
|
{
|
||||||
downloadDialog.UpdateFilename(str);
|
var processForm = new TForm();
|
||||||
downloadDialog.Show();
|
processForm.SetProcessable(strProc, logMe.Info);
|
||||||
}
|
processForm.OnBegin(sender, libraryBook);
|
||||||
|
|
||||||
// close form on DOWNLOAD completed, not final Completed. Else for BackupBook this form won't close until DECRYPT is also complete
|
|
||||||
void fileDownloadCompleted(object _, string __) => downloadDialog.Close();
|
|
||||||
|
|
||||||
void downloadProgressChanged(object _, Dinah.Core.Net.Http.DownloadProgress progress)
|
|
||||||
=> downloadDialog.DownloadProgressChanged(progress.BytesReceived, progress.TotalBytesToReceive);
|
|
||||||
|
|
||||||
void unsubscribe(object _ = null, EventArgs __ = null)
|
|
||||||
{
|
|
||||||
downloadable.DownloadBegin -= downloadBegin;
|
|
||||||
downloadable.DownloadCompleted -= fileDownloadCompleted;
|
|
||||||
downloadable.DownloadProgressChanged -= downloadProgressChanged;
|
|
||||||
downloadable.Completed -= dialogDispose;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unless we dispose, if the form is created but un-used/never-shown then weird UI stuff can happen
|
|
||||||
// also, since event unsubscribe occurs on FormClosing and an unused form is never closed, then the events will never be unsubscribed
|
|
||||||
void dialogDispose(object _, object __)
|
|
||||||
{
|
|
||||||
if (!downloadDialog.IsDisposed)
|
|
||||||
downloadDialog.Dispose();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region subscribe new form to model's events
|
|
||||||
downloadable.DownloadBegin += downloadBegin;
|
|
||||||
downloadable.DownloadCompleted += fileDownloadCompleted;
|
|
||||||
downloadable.DownloadProgressChanged += downloadProgressChanged;
|
|
||||||
downloadable.Completed += dialogDispose;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region when form closes, unsubscribe from model's events
|
|
||||||
// unsubscribe so disposed forms aren't still trying to receive notifications
|
|
||||||
// FormClosing is more UI safe but won't fire unless the form is shown and closed
|
|
||||||
// if form was shown, Disposed will fire for FormClosing, FormClosed, and Disposed
|
|
||||||
// if not shown, it will still fire for Disposed
|
|
||||||
downloadDialog.Disposed += unsubscribe;
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
// subscribed to Begin event because a new form should be created+processed+closed on each iteration
|
|
||||||
private static void wireUpEvents(IDecryptable decryptBook, LibraryBook libraryBook, string actionName = "Decrypting")
|
|
||||||
{
|
|
||||||
#region create form
|
|
||||||
var decryptDialog = new DecryptForm();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Set initially displayed book properties from library info.
|
|
||||||
decryptDialog.SetTitle(actionName, libraryBook.Book.Title);
|
|
||||||
decryptDialog.SetAuthorNames(string.Join(", ", libraryBook.Book.Authors));
|
|
||||||
decryptDialog.SetNarratorNames(string.Join(", ", libraryBook.Book.NarratorNames));
|
|
||||||
decryptDialog.SetCoverImage(
|
|
||||||
Dinah.Core.Drawing.ImageReader.ToImage(
|
|
||||||
FileManager.PictureStorage.GetPictureSynchronously(
|
|
||||||
new FileManager.PictureDefinition(
|
|
||||||
libraryBook.Book.PictureId,
|
|
||||||
FileManager.PictureSize._80x80))));
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region define how model actions will affect form behavior
|
|
||||||
void decryptBegin(object _, string __) => decryptDialog.Show();
|
|
||||||
void titleDiscovered(object _, string title) => decryptDialog.SetTitle(actionName, title);
|
|
||||||
void authorsDiscovered(object _, string authors) => decryptDialog.SetAuthorNames(authors);
|
|
||||||
void narratorsDiscovered(object _, string narrators) => decryptDialog.SetNarratorNames(narrators);
|
|
||||||
void coverImageFilepathDiscovered(object _, byte[] coverBytes) => decryptDialog.SetCoverImage(Dinah.Core.Drawing.ImageReader.ToImage(coverBytes));
|
|
||||||
void updateProgress(object _, int percentage) => decryptDialog.UpdateProgress(percentage);
|
|
||||||
void updateRemainingTime(object _, TimeSpan remaining) => decryptDialog.UpdateRemainingTime(remaining);
|
|
||||||
void decryptCompleted(object _, string __) => decryptDialog.Close();
|
|
||||||
void requestCoverArt(object _, Action<byte[]> setCoverArtDelegate)
|
|
||||||
=> setCoverArtDelegate(
|
|
||||||
FileManager.PictureStorage.GetPictureSynchronously(
|
|
||||||
new FileManager.PictureDefinition(
|
|
||||||
libraryBook.Book.PictureId,
|
|
||||||
FileManager.PictureSize._500x500)));
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region subscribe new form to model's events
|
|
||||||
decryptBook.DecryptBegin += decryptBegin;
|
|
||||||
|
|
||||||
decryptBook.TitleDiscovered += titleDiscovered;
|
|
||||||
decryptBook.AuthorsDiscovered += authorsDiscovered;
|
|
||||||
decryptBook.NarratorsDiscovered += narratorsDiscovered;
|
|
||||||
decryptBook.CoverImageFilepathDiscovered += coverImageFilepathDiscovered;
|
|
||||||
decryptBook.UpdateProgress += updateProgress;
|
|
||||||
decryptBook.UpdateRemainingTime += updateRemainingTime;
|
|
||||||
decryptBook.RequestCoverArt += requestCoverArt;
|
|
||||||
|
|
||||||
decryptBook.DecryptCompleted += decryptCompleted;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region when form closes, unsubscribe from model's events
|
|
||||||
// unsubscribe so disposed forms aren't still trying to receive notifications
|
|
||||||
decryptDialog.FormClosing += (_, __) =>
|
|
||||||
{
|
|
||||||
decryptBook.DecryptBegin -= decryptBegin;
|
|
||||||
|
|
||||||
decryptBook.TitleDiscovered -= titleDiscovered;
|
|
||||||
decryptBook.AuthorsDiscovered -= authorsDiscovered;
|
|
||||||
decryptBook.NarratorsDiscovered -= narratorsDiscovered;
|
|
||||||
decryptBook.CoverImageFilepathDiscovered -= coverImageFilepathDiscovered;
|
|
||||||
decryptBook.UpdateProgress -= updateProgress;
|
|
||||||
decryptBook.UpdateRemainingTime -= updateRemainingTime;
|
|
||||||
decryptBook.RequestCoverArt -= requestCoverArt;
|
|
||||||
|
|
||||||
decryptBook.DecryptCompleted -= decryptCompleted;
|
|
||||||
decryptBook.Cancel();
|
|
||||||
};
|
};
|
||||||
#endregion
|
|
||||||
|
if (completedAction != null)
|
||||||
|
strProc.Completed += completedAction;
|
||||||
|
|
||||||
|
return strProc;
|
||||||
}
|
}
|
||||||
|
private static (TStrProc, TForm) CreateStreamable<TStrProc, TForm>(EventHandler<LibraryBook> completedAction = null)
|
||||||
private static (AutomatedBackupsForm, LogMe) attachToBackupsForm(IDownloadableProcessable downloadable)
|
where TForm : StreamBaseForm, new()
|
||||||
|
where TStrProc : IStreamable, new()
|
||||||
{
|
{
|
||||||
#region create form and logger
|
var strProc = new TStrProc();
|
||||||
var automatedBackupsForm = new AutomatedBackupsForm();
|
|
||||||
var logMe = LogMe.RegisterForm(automatedBackupsForm);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region define how model actions will affect form behavior
|
var streamForm = new TForm();
|
||||||
void begin(object _, LibraryBook libraryBook) => logMe.Info($"Begin: {libraryBook.Book}");
|
streamForm.SetStreamable(strProc);
|
||||||
void statusUpdate(object _, string str) => logMe.Info("- " + str);
|
|
||||||
// extra line after book is completely finished
|
|
||||||
void completed(object _, LibraryBook libraryBook) => logMe.Info($"Completed: {libraryBook.Book}{Environment.NewLine}");
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region subscribe new form to model's events
|
return (strProc, streamForm);
|
||||||
downloadable.Begin += begin;
|
|
||||||
downloadable.StatusUpdate += statusUpdate;
|
|
||||||
downloadable.Completed += completed;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region when form closes, unsubscribe from model's events
|
|
||||||
// unsubscribe so disposed forms aren't still trying to receive notifications
|
|
||||||
automatedBackupsForm.FormClosing += (_, __) =>
|
|
||||||
{
|
|
||||||
downloadable.Begin -= begin;
|
|
||||||
downloadable.StatusUpdate -= statusUpdate;
|
|
||||||
downloadable.Completed -= completed;
|
|
||||||
};
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
return (automatedBackupsForm, logMe);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
LibationWinForms/BookLiberation/StreamBaseForm.cs
Normal file
52
LibationWinForms/BookLiberation/StreamBaseForm.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
using FileLiberator;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace LibationWinForms.BookLiberation
|
||||||
|
{
|
||||||
|
public class StreamBaseForm : Form
|
||||||
|
{
|
||||||
|
protected IStreamable Streamable { get; private set; }
|
||||||
|
public void SetStreamable(IStreamable streamable)
|
||||||
|
{
|
||||||
|
Streamable = streamable;
|
||||||
|
|
||||||
|
if (Streamable is null) return;
|
||||||
|
|
||||||
|
OnUnsubscribeAll(this, EventArgs.Empty);
|
||||||
|
|
||||||
|
Streamable.StreamingBegin += OnStreamingBegin;
|
||||||
|
Streamable.StreamingCompleted += OnStreamingCompleted;
|
||||||
|
Streamable.StreamingProgressChanged += OnStreamingProgressChanged;
|
||||||
|
Streamable.StreamingTimeRemaining += OnStreamingTimeRemaining;
|
||||||
|
|
||||||
|
Disposed += OnUnsubscribeAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnsubscribeAll(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Disposed -= OnUnsubscribeAll;
|
||||||
|
|
||||||
|
Streamable.StreamingBegin -= OnStreamingBegin;
|
||||||
|
Streamable.StreamingCompleted -= OnStreamingCompleted;
|
||||||
|
Streamable.StreamingProgressChanged -= OnStreamingProgressChanged;
|
||||||
|
Streamable.StreamingTimeRemaining -= OnStreamingTimeRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IStreamable event handlers
|
||||||
|
public virtual void OnStreamingBegin(object sender, string beginString) => Show();
|
||||||
|
public virtual void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress) { }
|
||||||
|
public virtual void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining) { }
|
||||||
|
public virtual void OnStreamingCompleted(object sender, string completedString)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
17
LibationWinForms/Form1.Designer.cs
generated
17
LibationWinForms/Form1.Designer.cs
generated
@ -61,6 +61,7 @@
|
|||||||
this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
this.backupsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.pdfsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
this.pdfsCountsLbl = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.addFilterBtn = new System.Windows.Forms.Button();
|
this.addFilterBtn = new System.Windows.Forms.Button();
|
||||||
|
this.button1 = new System.Windows.Forms.Button();
|
||||||
this.menuStrip1.SuspendLayout();
|
this.menuStrip1.SuspendLayout();
|
||||||
this.statusStrip1.SuspendLayout();
|
this.statusStrip1.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
@ -177,14 +178,14 @@
|
|||||||
// removeAllAccountsToolStripMenuItem
|
// removeAllAccountsToolStripMenuItem
|
||||||
//
|
//
|
||||||
this.removeAllAccountsToolStripMenuItem.Name = "removeAllAccountsToolStripMenuItem";
|
this.removeAllAccountsToolStripMenuItem.Name = "removeAllAccountsToolStripMenuItem";
|
||||||
this.removeAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
this.removeAllAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||||
this.removeAllAccountsToolStripMenuItem.Text = "All Accounts";
|
this.removeAllAccountsToolStripMenuItem.Text = "All Accounts";
|
||||||
this.removeAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeAllAccountsToolStripMenuItem_Click);
|
this.removeAllAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeAllAccountsToolStripMenuItem_Click);
|
||||||
//
|
//
|
||||||
// removeSomeAccountsToolStripMenuItem
|
// removeSomeAccountsToolStripMenuItem
|
||||||
//
|
//
|
||||||
this.removeSomeAccountsToolStripMenuItem.Name = "removeSomeAccountsToolStripMenuItem";
|
this.removeSomeAccountsToolStripMenuItem.Name = "removeSomeAccountsToolStripMenuItem";
|
||||||
this.removeSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
this.removeSomeAccountsToolStripMenuItem.Size = new System.Drawing.Size(157, 22);
|
||||||
this.removeSomeAccountsToolStripMenuItem.Text = "Some Accounts";
|
this.removeSomeAccountsToolStripMenuItem.Text = "Some Accounts";
|
||||||
this.removeSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeSomeAccountsToolStripMenuItem_Click);
|
this.removeSomeAccountsToolStripMenuItem.Click += new System.EventHandler(this.removeSomeAccountsToolStripMenuItem_Click);
|
||||||
//
|
//
|
||||||
@ -336,11 +337,22 @@
|
|||||||
this.addFilterBtn.UseVisualStyleBackColor = true;
|
this.addFilterBtn.UseVisualStyleBackColor = true;
|
||||||
this.addFilterBtn.Click += new System.EventHandler(this.AddFilterBtn_Click);
|
this.addFilterBtn.Click += new System.EventHandler(this.AddFilterBtn_Click);
|
||||||
//
|
//
|
||||||
|
// button1
|
||||||
|
//
|
||||||
|
this.button1.Location = new System.Drawing.Point(648, 0);
|
||||||
|
this.button1.Name = "button1";
|
||||||
|
this.button1.Size = new System.Drawing.Size(123, 70);
|
||||||
|
this.button1.TabIndex = 0;
|
||||||
|
this.button1.Text = "button1";
|
||||||
|
this.button1.UseVisualStyleBackColor = true;
|
||||||
|
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||||
|
//
|
||||||
// Form1
|
// Form1
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(1007, 539);
|
this.ClientSize = new System.Drawing.Size(1007, 539);
|
||||||
|
this.Controls.Add(this.button1);
|
||||||
this.Controls.Add(this.filterBtn);
|
this.Controls.Add(this.filterBtn);
|
||||||
this.Controls.Add(this.addFilterBtn);
|
this.Controls.Add(this.addFilterBtn);
|
||||||
this.Controls.Add(this.filterSearchTb);
|
this.Controls.Add(this.filterSearchTb);
|
||||||
@ -398,5 +410,6 @@
|
|||||||
private System.Windows.Forms.ToolStripMenuItem removeLibraryBooksToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem removeLibraryBooksToolStripMenuItem;
|
||||||
private System.Windows.Forms.ToolStripMenuItem removeAllAccountsToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem removeAllAccountsToolStripMenuItem;
|
||||||
private System.Windows.Forms.ToolStripMenuItem removeSomeAccountsToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem removeSomeAccountsToolStripMenuItem;
|
||||||
|
private System.Windows.Forms.Button button1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,7 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
// also applies filter. ONLY call AFTER loading grid
|
// also applies filter. ONLY call AFTER loading grid
|
||||||
loadInitialQuickFilterState();
|
loadInitialQuickFilterState();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
@ -494,5 +495,13 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
private void basicSettingsToolStripMenuItem_Click(object sender, EventArgs e) => new SettingsDialog().ShowDialog();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void button1_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
BookLiberation.ProcessorAutomationController.DownloadFile(
|
||||||
|
"https://github.com/rmcrackan/Libation/releases/download/v5.4.9/Libation.5.4.9.zip",
|
||||||
|
@"C:\Users\mbuca\Downloads\libation test dl.zip");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<root>
|
||||||
<root>
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user