Merge pull request #132 from Mbucari/master

Convert IProcessable to abstract class Processable.
This commit is contained in:
rmcrackan 2021-10-06 11:06:25 -04:00 committed by GitHub
commit 40520b89d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 319 additions and 308 deletions

View File

@ -0,0 +1,44 @@
using System;
namespace FileLiberator
{
public abstract class AudioDecodable : Processable
{
public event EventHandler<Action<byte[]>> RequestCoverArt;
public event EventHandler<string> TitleDiscovered;
public event EventHandler<string> AuthorsDiscovered;
public event EventHandler<string> NarratorsDiscovered;
public event EventHandler<byte[]> CoverImageDiscovered;
public abstract void Cancel();
protected void OnRequestCoverArt(Action<byte[]> setCoverArtDel)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(RequestCoverArt) });
RequestCoverArt?.Invoke(this, setCoverArtDel);
}
protected void OnTitleDiscovered(string title)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(TitleDiscovered), Title = title });
TitleDiscovered?.Invoke(this, title);
}
protected void OnAuthorsDiscovered(string authors)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(AuthorsDiscovered), Authors = authors });
AuthorsDiscovered?.Invoke(this, authors);
}
protected void OnNarratorsDiscovered(string narrators)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(NarratorsDiscovered), Narrators = narrators });
NarratorsDiscovered?.Invoke(this, narrators);
}
protected void OnCoverImageDiscovered(byte[] coverImage)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(CoverImageDiscovered), CoverImageBytes = coverImage?.Length });
CoverImageDiscovered?.Invoke(this, coverImage);
}
}
}

View File

@ -12,39 +12,26 @@ using System.Threading.Tasks;
namespace FileLiberator
{
public class ConvertToMp3 : IAudioDecodable
public class ConvertToMp3 : AudioDecodable
{
private Mp4File m4bBook;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public event EventHandler<Action<byte[]>> RequestCoverArt;
public event EventHandler<string> TitleDiscovered;
public event EventHandler<string> AuthorsDiscovered;
public event EventHandler<string> NarratorsDiscovered;
public event EventHandler<byte[]> CoverImageDiscovered;
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<string> StreamingCompleted;
public event EventHandler<LibraryBook> Begin;
public event EventHandler<string> StatusUpdate;
public event EventHandler<LibraryBook> Completed;
private long fileSize;
private string Mp3FileName(string m4bPath) => m4bPath is null ? string.Empty : PathLib.ReplaceExtension(m4bPath, ".mp3");
public void Cancel() => m4bBook?.Cancel();
public override void Cancel() => m4bBook?.Cancel();
public bool Validate(LibraryBook libraryBook)
public override bool Validate(LibraryBook libraryBook)
{
var path = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId);
return path?.ToLower()?.EndsWith(".m4b") == true && !File.Exists(Mp3FileName(path));
}
public async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
public override async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
{
Begin?.Invoke(this, libraryBook);
OnBegin(libraryBook);
StreamingBegin?.Invoke(this, $"Begin converting {libraryBook} to mp3");
OnStreamingBegin($"Begin converting {libraryBook} to mp3");
try
{
@ -54,10 +41,10 @@ namespace FileLiberator
fileSize = m4bBook.InputStream.Length;
TitleDiscovered?.Invoke(this, m4bBook.AppleTags.Title);
AuthorsDiscovered?.Invoke(this, m4bBook.AppleTags.FirstAuthor);
NarratorsDiscovered?.Invoke(this, m4bBook.AppleTags.Narrator);
CoverImageDiscovered?.Invoke(this, m4bBook.AppleTags.Cover);
OnTitleDiscovered(m4bBook.AppleTags.Title);
OnAuthorsDiscovered(m4bBook.AppleTags.FirstAuthor);
OnNarratorsDiscovered(m4bBook.AppleTags.Narrator);
OnCoverImageDiscovered(m4bBook.AppleTags.Cover);
using var mp3File = File.OpenWrite(Path.GetTempFileName());
@ -78,8 +65,8 @@ namespace FileLiberator
}
finally
{
StreamingCompleted?.Invoke(this, $"Completed converting to mp3: {libraryBook.Book.Title}");
Completed?.Invoke(this, libraryBook);
OnStreamingCompleted($"Completed converting to mp3: {libraryBook.Book.Title}");
OnCompleted(libraryBook);
}
}
@ -90,11 +77,11 @@ namespace FileLiberator
double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed;
if (double.IsNormal(estTimeRemaining))
StreamingTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining));
OnStreamingTimeRemaining(TimeSpan.FromSeconds(estTimeRemaining));
double progressPercent = 100 * e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
StreamingProgressChanged?.Invoke(this,
OnStreamingProgressChanged(
new DownloadProgress
{
ProgressPercentage = progressPercent,

View File

@ -8,31 +8,17 @@ using AudibleApi;
using DataLayer;
using Dinah.Core;
using Dinah.Core.ErrorHandling;
using Dinah.Core.Net.Http;
using FileManager;
namespace FileLiberator
{
public class DownloadDecryptBook : IAudioDecodable
public class DownloadDecryptBook : AudioDecodable
{
private AudiobookDownloadBase aaxcDownloader;
private AudiobookDownloadBase abDownloader;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public event EventHandler<Action<byte[]>> RequestCoverArt;
public event EventHandler<string> TitleDiscovered;
public event EventHandler<string> AuthorsDiscovered;
public event EventHandler<string> NarratorsDiscovered;
public event EventHandler<byte[]> CoverImageDiscovered;
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<string> StreamingCompleted;
public event EventHandler<LibraryBook> Begin;
public event EventHandler<string> StatusUpdate;
public event EventHandler<LibraryBook> Completed;
public async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
public override async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
{
Begin?.Invoke(this, libraryBook);
OnBegin(libraryBook);
try
{
@ -57,13 +43,13 @@ namespace FileLiberator
}
finally
{
Completed?.Invoke(this, libraryBook);
OnCompleted(libraryBook);
}
}
private async Task<string> downloadAudiobookAsync(string cacheDir, string destinationDir, LibraryBook libraryBook)
{
StreamingBegin?.Invoke(this, $"Begin decrypting {libraryBook}");
OnStreamingBegin($"Begin decrypting {libraryBook}");
try
{
@ -98,18 +84,19 @@ namespace FileLiberator
var outFileName = Path.Combine(destinationDir, $"{PathLib.ToPathSafeString(libraryBook.Book.Title)} [{libraryBook.Book.AudibleProductId}].{outputFormat.ToString().ToLower()}");
aaxcDownloader = contentLic.DrmType == AudibleApi.Common.DrmType.Adrm
? new AaxcDownloadConverter(outFileName, cacheDir, audiobookDlLic, outputFormat, Configuration.Instance.SplitFilesByChapter) { AppName = "Libation" }
abDownloader = contentLic.DrmType == AudibleApi.Common.DrmType.Adrm
? new AaxcDownloadConverter(outFileName, cacheDir, audiobookDlLic, outputFormat, Configuration.Instance.SplitFilesByChapter)
: new UnencryptedAudiobookDownloader(outFileName, cacheDir, audiobookDlLic);
aaxcDownloader.DecryptProgressUpdate += (s, progress) => StreamingProgressChanged?.Invoke(this, progress);
aaxcDownloader.DecryptTimeRemaining += (s, remaining) => StreamingTimeRemaining?.Invoke(this, remaining);
aaxcDownloader.RetrievedTitle += (s, title) => TitleDiscovered?.Invoke(this, title);
aaxcDownloader.RetrievedAuthors += (s, authors) => AuthorsDiscovered?.Invoke(this, authors);
aaxcDownloader.RetrievedNarrators += (s, narrators) => NarratorsDiscovered?.Invoke(this, narrators);
aaxcDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
abDownloader.AppName = "Libation";
abDownloader.DecryptProgressUpdate += (_, progress) => OnStreamingProgressChanged(progress);
abDownloader.DecryptTimeRemaining += (_, remaining) => OnStreamingTimeRemaining(remaining);
abDownloader.RetrievedTitle += (_, title) => OnTitleDiscovered(title);
abDownloader.RetrievedAuthors += (_, authors) => OnAuthorsDiscovered(authors);
abDownloader.RetrievedNarrators += (_, narrators) => OnNarratorsDiscovered(narrators);
abDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
// REAL WORK DONE HERE
var success = await Task.Run(() => aaxcDownloader.Run());
var success = await Task.Run(abDownloader.Run);
// decrypt failed
if (!success)
@ -119,7 +106,7 @@ namespace FileLiberator
}
finally
{
StreamingCompleted?.Invoke(this, $"Completed downloading and decrypting {libraryBook.Book.Title}");
OnStreamingCompleted($"Completed downloading and decrypting {libraryBook.Book.Title}");
}
}
@ -127,12 +114,12 @@ namespace FileLiberator
{
if (e is null && Configuration.Instance.AllowLibationFixup)
{
RequestCoverArt?.Invoke(this, aaxcDownloader.SetCoverArt);
OnRequestCoverArt(abDownloader.SetCoverArt);
}
if (e is not null)
{
CoverImageDiscovered?.Invoke(this, e);
OnCoverImageDiscovered(e);
}
}
@ -214,11 +201,11 @@ namespace FileLiberator
throw new Exception(errorString("Locale"));
}
public bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists;
public override bool Validate(LibraryBook libraryBook) => !libraryBook.Book.Audio_Exists;
public void Cancel()
public override void Cancel()
{
aaxcDownloader?.Cancel();
abDownloader?.Cancel();
}
}
}

View File

@ -6,21 +6,16 @@ using Dinah.Core.Net.Http;
namespace FileLiberator
{
// currently only used to download the .zip flies for upgrade
public class DownloadFile : IStreamable
public class DownloadFile : Streamable
{
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<string> StreamingCompleted;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
{
var client = new HttpClient();
var progress = new Progress<DownloadProgress>();
progress.ProgressChanged += (_, e) => StreamingProgressChanged?.Invoke(this, e);
progress.ProgressChanged += (_, e) => OnStreamingProgressChanged(e);
StreamingBegin?.Invoke(this, proposedDownloadFilePath);
OnStreamingBegin(proposedDownloadFilePath);
try
{
@ -29,7 +24,7 @@ namespace FileLiberator
}
finally
{
StreamingCompleted?.Invoke(this, proposedDownloadFilePath);
OnStreamingCompleted(proposedDownloadFilePath);
}
}
}

View File

@ -11,25 +11,15 @@ using FileManager;
namespace FileLiberator
{
public class DownloadPdf : IProcessable
public class DownloadPdf : Processable
{
public event EventHandler<LibraryBook> Begin;
public event EventHandler<LibraryBook> Completed;
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<string> StreamingCompleted;
public event EventHandler<string> StatusUpdate;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public bool Validate(LibraryBook libraryBook)
public override bool Validate(LibraryBook libraryBook)
=> !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook))
&& !libraryBook.Book.PDF_Exists;
public async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
public override async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
{
Begin?.Invoke(this, libraryBook);
OnBegin(libraryBook);
try
{
@ -43,7 +33,7 @@ namespace FileLiberator
}
finally
{
Completed?.Invoke(this, libraryBook);
OnCompleted(libraryBook);
}
}
@ -69,7 +59,7 @@ namespace FileLiberator
private async Task<string> downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
{
StreamingBegin?.Invoke(this, proposedDownloadFilePath);
OnStreamingBegin(proposedDownloadFilePath);
try
{
@ -77,17 +67,17 @@ namespace FileLiberator
var downloadUrl = await api.GetPdfDownloadLinkAsync(libraryBook.Book.AudibleProductId);
var progress = new Progress<DownloadProgress>();
progress.ProgressChanged += (_, e) => StreamingProgressChanged?.Invoke(this, e);
progress.ProgressChanged += (_, e) => OnStreamingProgressChanged(e);
var client = new HttpClient();
var actualDownloadedFilePath = await client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, progress);
StatusUpdate?.Invoke(this, actualDownloadedFilePath);
OnStatusUpdate(actualDownloadedFilePath);
return actualDownloadedFilePath;
}
finally
{
StreamingCompleted?.Invoke(this, proposedDownloadFilePath);
OnStreamingCompleted(proposedDownloadFilePath);
}
}

View File

@ -1,14 +0,0 @@
using System;
namespace FileLiberator
{
public interface IAudioDecodable : IProcessable
{
event EventHandler<Action<byte[]>> RequestCoverArt;
event EventHandler<string> TitleDiscovered;
event EventHandler<string> AuthorsDiscovered;
event EventHandler<string> NarratorsDiscovered;
event EventHandler<byte[]> CoverImageDiscovered;
void Cancel();
}
}

View File

@ -1,23 +0,0 @@
using System;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core.ErrorHandling;
namespace FileLiberator
{
public interface IProcessable : IStreamable
{
event EventHandler<LibraryBook> Begin;
/// <summary>General string message to display. DON'T rely on this for success, failure, or control logic</summary>
event EventHandler<string> StatusUpdate;
event EventHandler<LibraryBook> Completed;
/// <returns>True == Valid</returns>
bool Validate(LibraryBook libraryBook);
/// <returns>True == success</returns>
Task<StatusHandler> ProcessAsync(LibraryBook libraryBook);
}
}

View File

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core;
using Dinah.Core.ErrorHandling;
namespace FileLiberator
{
public static class IProcessableExt
{
// when used in foreach: stateful. deferred execution
public static IEnumerable<LibraryBook> GetValidLibraryBooks(this IProcessable processable, IEnumerable<LibraryBook> library)
=> library.Where(libraryBook =>
processable.Validate(libraryBook)
&& (libraryBook.Book.ContentType != ContentType.Episode || FileManager.Configuration.Instance.DownloadEpisodes)
);
public static async Task<StatusHandler> ProcessSingleAsync(this IProcessable processable, LibraryBook libraryBook, bool validate)
{
if (validate && !processable.Validate(libraryBook))
return new StatusHandler { "Validation failed" };
Serilog.Log.Logger.Information("Begin " + nameof(ProcessSingleAsync) + " {@DebugInfo}", new
{
libraryBook.Book.Title,
libraryBook.Book.AudibleProductId,
libraryBook.Book.Locale,
Account = libraryBook.Account?.ToMask() ?? "[empty]"
});
var status
= (await processable.ProcessAsync(libraryBook))
?? new StatusHandler { "Processable should never return a null status" };
return status;
}
public static async Task<StatusHandler> TryProcessAsync(this IProcessable processable, LibraryBook libraryBook)
=> processable.Validate(libraryBook)
? await processable.ProcessAsync(libraryBook)
: new StatusHandler();
}
}

View File

@ -1,13 +0,0 @@
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;
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core;
using Dinah.Core.ErrorHandling;
namespace FileLiberator
{
public abstract class Processable : Streamable
{
public event EventHandler<LibraryBook> Begin;
/// <summary>General string message to display. DON'T rely on this for success, failure, or control logic</summary>
public event EventHandler<string> StatusUpdate;
public event EventHandler<LibraryBook> Completed;
/// <returns>True == Valid</returns>
public abstract bool Validate(LibraryBook libraryBook);
/// <returns>True == success</returns>
public abstract Task<StatusHandler> ProcessAsync(LibraryBook libraryBook);
// when used in foreach: stateful. deferred execution
protected IEnumerable<LibraryBook> GetValidLibraryBooks(IEnumerable<LibraryBook> library)
=> library.Where(libraryBook =>
Validate(libraryBook)
&& (libraryBook.Book.ContentType != ContentType.Episode || FileManager.Configuration.Instance.DownloadEpisodes)
);
protected async Task<StatusHandler> ProcessSingleAsync(LibraryBook libraryBook, bool validate)
{
if (validate && !Validate(libraryBook))
return new StatusHandler { "Validation failed" };
Serilog.Log.Logger.Information("Begin " + nameof(ProcessSingleAsync) + " {@DebugInfo}", new
{
libraryBook.Book.Title,
libraryBook.Book.AudibleProductId,
libraryBook.Book.Locale,
Account = libraryBook.Account?.ToMask() ?? "[empty]"
});
var status
= (await ProcessAsync(libraryBook))
?? new StatusHandler { "Processable should never return a null status" };
return status;
}
protected async Task<StatusHandler> TryProcessAsync(LibraryBook libraryBook)
=> Validate(libraryBook)
? await ProcessAsync(libraryBook)
: new StatusHandler();
protected void OnBegin(LibraryBook libraryBook)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(Begin), Book = libraryBook.LogFriendly() });
Begin?.Invoke(this, libraryBook);
}
protected void OnStatusUpdate(string statusUpdate)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(StatusUpdate), Status = statusUpdate });
StatusUpdate?.Invoke(this, statusUpdate);
}
protected void OnCompleted(LibraryBook libraryBook)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(Completed), Book = libraryBook.LogFriendly() });
Completed?.Invoke(this, libraryBook);
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using Dinah.Core.Net.Http;
namespace FileLiberator
{
public abstract class Streamable
{
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public event EventHandler<string> StreamingCompleted;
protected void OnStreamingBegin(string filePath)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(StreamingBegin), Message = filePath });
StreamingBegin?.Invoke(this, filePath);
}
protected void OnStreamingProgressChanged(DownloadProgress progress)
{
StreamingProgressChanged?.Invoke(this, progress);
}
protected void OnStreamingTimeRemaining(TimeSpan timeRemaining)
{
StreamingTimeRemaining?.Invoke(this, timeRemaining);
}
protected void OnStreamingCompleted(string filePath)
{
Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(StreamingCompleted), Message = filePath });
StreamingCompleted?.Invoke(this, filePath);
//TODO: Update file cache
}
}
}

View File

@ -20,7 +20,7 @@ namespace LibationCli
? RunAsync(CreateProcessable<DownloadPdf>())
: RunAsync(CreateBackupBook());
private static IProcessable CreateBackupBook()
private static Processable CreateBackupBook()
{
var downloadPdf = CreateProcessable<DownloadPdf>();

View File

@ -13,7 +13,7 @@ namespace LibationCli
public abstract class ProcessableOptionsBase : OptionsBase
{
protected static TProcessable CreateProcessable<TProcessable>(EventHandler<LibraryBook> completedAction = null)
where TProcessable : IProcessable, new()
where TProcessable : Processable, new()
{
var strProc = new TProcessable();
@ -25,7 +25,7 @@ namespace LibationCli
return strProc;
}
protected static async Task RunAsync(IProcessable Processable)
protected static async Task RunAsync(Processable Processable)
{
foreach (var libraryBook in Processable.GetValidLibraryBooks(DbContexts.GetLibrary_Flat_NoTracking()))
await ProcessOneAsync(Processable, libraryBook, false);
@ -35,7 +35,7 @@ namespace LibationCli
Serilog.Log.Logger.Information(done);
}
private static async Task ProcessOneAsync(IProcessable Processable, LibraryBook libraryBook, bool validate)
private static async Task ProcessOneAsync(Processable Processable, LibraryBook libraryBook, bool validate)
{
try
{

View File

@ -16,16 +16,16 @@ namespace LibationWinForms.BookLiberation
public override string DecodeActionName => "Converting";
#endregion
#region IProcessable event handler overrides
public override void OnBegin(object sender, LibraryBook libraryBook)
#region Processable event handler overrides
public override void Processable_Begin(object sender, LibraryBook libraryBook)
{
LogMe.Info($"Convert Step, Begin: {libraryBook.Book}");
base.OnBegin(sender, libraryBook);
base.Processable_Begin(sender, libraryBook);
}
public override void OnCompleted(object sender, LibraryBook libraryBook)
public override void Processable_Completed(object sender, LibraryBook libraryBook)
{
base.OnCompleted(sender, libraryBook);
base.Processable_Completed(sender, libraryBook);
LogMe.Info($"Convert Step, Completed: {libraryBook.Book}{Environment.NewLine}");
}

View File

@ -18,10 +18,10 @@ namespace LibationWinForms.BookLiberation
private string authorNames;
private string narratorNames;
#region IProcessable event handler overrides
public override void OnBegin(object sender, LibraryBook libraryBook)
#region Processable event handler overrides
public override void Processable_Begin(object sender, LibraryBook libraryBook)
{
base.OnBegin(sender, libraryBook);
base.Processable_Begin(sender, libraryBook);
GetCoverArtDelegate = () => FileManager.PictureStorage.GetPictureSynchronously(
new FileManager.PictureDefinition(
@ -29,10 +29,10 @@ namespace LibationWinForms.BookLiberation
FileManager.PictureSize._500x500));
//Set default values from library
OnTitleDiscovered(sender, libraryBook.Book.Title);
OnAuthorsDiscovered(sender, string.Join(", ", libraryBook.Book.Authors));
OnNarratorsDiscovered(sender, string.Join(", ", libraryBook.Book.NarratorNames));
OnCoverImageDiscovered(sender,
AudioDecodable_TitleDiscovered(sender, libraryBook.Book.Title);
AudioDecodable_AuthorsDiscovered(sender, string.Join(", ", libraryBook.Book.Authors));
AudioDecodable_NarratorsDiscovered(sender, string.Join(", ", libraryBook.Book.NarratorNames));
AudioDecodable_CoverImageDiscovered(sender,
FileManager.PictureStorage.GetPicture(
new FileManager.PictureDefinition(
libraryBook.Book.PictureId,
@ -40,10 +40,10 @@ namespace LibationWinForms.BookLiberation
}
#endregion
#region IStreamable event handler overrides
public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress)
#region Streamable event handler overrides
public override void Streamable_StreamingProgressChanged(object sender, DownloadProgress downloadProgress)
{
base.OnStreamingProgressChanged(sender, downloadProgress);
base.Streamable_StreamingProgressChanged(sender, downloadProgress);
if (!downloadProgress.ProgressPercentage.HasValue)
return;
@ -53,46 +53,46 @@ namespace LibationWinForms.BookLiberation
progressBar1.UIThreadAsync(() => progressBar1.Value = (int)downloadProgress.ProgressPercentage);
}
public override void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining)
public override void Streamable_StreamingTimeRemaining(object sender, TimeSpan timeRemaining)
{
base.OnStreamingTimeRemaining(sender, timeRemaining);
base.Streamable_StreamingTimeRemaining(sender, timeRemaining);
updateRemainingTime((int)timeRemaining.TotalSeconds);
}
#endregion
#region IAudioDecodable event handlers
public override void OnRequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
#region AudioDecodable event handlers
public override void AudioDecodable_RequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
{
base.OnRequestCoverArt(sender, setCoverArtDelegate);
base.AudioDecodable_RequestCoverArt(sender, setCoverArtDelegate);
setCoverArtDelegate(GetCoverArtDelegate?.Invoke());
}
public override void OnTitleDiscovered(object sender, string title)
public override void AudioDecodable_TitleDiscovered(object sender, string title)
{
base.OnTitleDiscovered(sender, title);
base.AudioDecodable_TitleDiscovered(sender, title);
this.UIThreadAsync(() => this.Text = DecodeActionName + " " + title);
this.title = title;
updateBookInfo();
}
public override void OnAuthorsDiscovered(object sender, string authors)
public override void AudioDecodable_AuthorsDiscovered(object sender, string authors)
{
base.OnAuthorsDiscovered(sender, authors);
base.AudioDecodable_AuthorsDiscovered(sender, authors);
authorNames = authors;
updateBookInfo();
}
public override void OnNarratorsDiscovered(object sender, string narrators)
public override void AudioDecodable_NarratorsDiscovered(object sender, string narrators)
{
base.OnNarratorsDiscovered(sender, narrators);
base.AudioDecodable_NarratorsDiscovered(sender, narrators);
narratorNames = narrators;
updateBookInfo();
}
public override void OnCoverImageDiscovered(object sender, byte[] coverArt)
public override void AudioDecodable_CoverImageDiscovered(object sender, byte[] coverArt)
{
base.OnCoverImageDiscovered(sender, coverArt);
base.AudioDecodable_CoverImageDiscovered(sender, coverArt);
pictureBox1.UIThreadAsync(() => pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(coverArt));
}
#endregion

View File

@ -16,16 +16,16 @@ namespace LibationWinForms.BookLiberation
public override string DecodeActionName => "Decrypting";
#endregion
#region IProcessable event handler overrides
public override void OnBegin(object sender, LibraryBook libraryBook)
#region Processable event handler overrides
public override void Processable_Begin(object sender, LibraryBook libraryBook)
{
LogMe.Info($"Download & Decrypt Step, Begin: {libraryBook.Book}");
base.OnBegin(sender, libraryBook);
base.Processable_Begin(sender, libraryBook);
}
public override void OnCompleted(object sender, LibraryBook libraryBook)
public override void Processable_Completed(object sender, LibraryBook libraryBook)
{
base.OnCompleted(sender, libraryBook);
base.Processable_Completed(sender, libraryBook);
LogMe.Info($"Download & Decrypt Step, Completed: {libraryBook.Book}{Environment.NewLine}");
}

View File

@ -9,7 +9,7 @@ namespace LibationWinForms.BookLiberation.BaseForms
{
public class LiberationBaseForm : Form
{
protected IStreamable Streamable { get; private set; }
protected Streamable Streamable { get; private set; }
protected LogMe LogMe { get; private set; }
private SynchronizeInvoker Invoker { get; init; }
@ -21,7 +21,7 @@ namespace LibationWinForms.BookLiberation.BaseForms
Invoker = new SynchronizeInvoker();
}
public void RegisterFileLiberator(IStreamable streamable, LogMe logMe = null)
public void RegisterFileLiberator(Streamable streamable, LogMe logMe = null)
{
if (streamable is null) return;
@ -30,52 +30,52 @@ namespace LibationWinForms.BookLiberation.BaseForms
Subscribe(streamable);
if (Streamable is IProcessable processable)
if (Streamable is Processable processable)
Subscribe(processable);
if (Streamable is IAudioDecodable audioDecodable)
if (Streamable is AudioDecodable audioDecodable)
Subscribe(audioDecodable);
}
#region Event Subscribers and Unsubscribers
private void Subscribe(IStreamable streamable)
private void Subscribe(Streamable streamable)
{
UnsubscribeStreamable(this, EventArgs.Empty);
streamable.StreamingBegin += OnStreamingBeginShow;
streamable.StreamingBegin += OnStreamingBegin;
streamable.StreamingProgressChanged += OnStreamingProgressChanged;
streamable.StreamingTimeRemaining += OnStreamingTimeRemaining;
streamable.StreamingCompleted += OnStreamingCompleted;
streamable.StreamingBegin += Streamable_StreamingBegin;
streamable.StreamingProgressChanged += Streamable_StreamingProgressChanged;
streamable.StreamingTimeRemaining += Streamable_StreamingTimeRemaining;
streamable.StreamingCompleted += Streamable_StreamingCompleted;
streamable.StreamingCompleted += OnStreamingCompletedClose;
Disposed += UnsubscribeStreamable;
}
private void Subscribe(IProcessable processable)
private void Subscribe(Processable processable)
{
UnsubscribeProcessable(this, null);
processable.Begin += OnBegin;
processable.StatusUpdate += OnStatusUpdate;
processable.Completed += OnCompleted;
processable.Begin += Processable_Begin;
processable.StatusUpdate += Processable_StatusUpdate;
processable.Completed += Processable_Completed;
//The form is created on IProcessable.Begin and we
//dispose of it on IProcessable.Completed
//The form is created on Processable.Begin and we
//dispose of it on Processable.Completed
processable.Completed += OnCompletedDispose;
//Don't unsubscribe from Dispose because it fires when
//IStreamable.StreamingCompleted closes the form, and
//the IProcessable events need to live past that event.
//Streamable.StreamingCompleted closes the form, and
//the Processable events need to live past that event.
processable.Completed += UnsubscribeProcessable;
}
private void Subscribe(IAudioDecodable audioDecodable)
private void Subscribe(AudioDecodable audioDecodable)
{
UnsubscribeAudioDecodable(this, EventArgs.Empty);
audioDecodable.RequestCoverArt += OnRequestCoverArt;
audioDecodable.TitleDiscovered += OnTitleDiscovered;
audioDecodable.AuthorsDiscovered += OnAuthorsDiscovered;
audioDecodable.NarratorsDiscovered += OnNarratorsDiscovered;
audioDecodable.CoverImageDiscovered += OnCoverImageDiscovered;
audioDecodable.RequestCoverArt += AudioDecodable_RequestCoverArt;
audioDecodable.TitleDiscovered += AudioDecodable_TitleDiscovered;
audioDecodable.AuthorsDiscovered += AudioDecodable_AuthorsDiscovered;
audioDecodable.NarratorsDiscovered += AudioDecodable_NarratorsDiscovered;
audioDecodable.CoverImageDiscovered += AudioDecodable_CoverImageDiscovered;
Disposed += UnsubscribeAudioDecodable;
}
@ -84,34 +84,34 @@ namespace LibationWinForms.BookLiberation.BaseForms
Disposed -= UnsubscribeStreamable;
Streamable.StreamingBegin -= OnStreamingBeginShow;
Streamable.StreamingBegin -= OnStreamingBegin;
Streamable.StreamingProgressChanged -= OnStreamingProgressChanged;
Streamable.StreamingTimeRemaining -= OnStreamingTimeRemaining;
Streamable.StreamingCompleted -= OnStreamingCompleted;
Streamable.StreamingBegin -= Streamable_StreamingBegin;
Streamable.StreamingProgressChanged -= Streamable_StreamingProgressChanged;
Streamable.StreamingTimeRemaining -= Streamable_StreamingTimeRemaining;
Streamable.StreamingCompleted -= Streamable_StreamingCompleted;
Streamable.StreamingCompleted -= OnStreamingCompletedClose;
}
private void UnsubscribeProcessable(object sender, LibraryBook e)
{
if (Streamable is not IProcessable processable)
if (Streamable is not Processable processable)
return;
processable.Completed -= UnsubscribeProcessable;
processable.Completed -= OnCompletedDispose;
processable.Completed -= OnCompleted;
processable.StatusUpdate -= OnStatusUpdate;
processable.Begin -= OnBegin;
processable.Completed -= Processable_Completed;
processable.StatusUpdate -= Processable_StatusUpdate;
processable.Begin -= Processable_Begin;
}
private void UnsubscribeAudioDecodable(object sender, EventArgs e)
{
if (Streamable is not IAudioDecodable audioDecodable)
if (Streamable is not AudioDecodable audioDecodable)
return;
Disposed -= UnsubscribeAudioDecodable;
audioDecodable.RequestCoverArt -= OnRequestCoverArt;
audioDecodable.TitleDiscovered -= OnTitleDiscovered;
audioDecodable.AuthorsDiscovered -= OnAuthorsDiscovered;
audioDecodable.NarratorsDiscovered -= OnNarratorsDiscovered;
audioDecodable.CoverImageDiscovered -= OnCoverImageDiscovered;
audioDecodable.RequestCoverArt -= AudioDecodable_RequestCoverArt;
audioDecodable.TitleDiscovered -= AudioDecodable_TitleDiscovered;
audioDecodable.AuthorsDiscovered -= AudioDecodable_AuthorsDiscovered;
audioDecodable.NarratorsDiscovered -= AudioDecodable_NarratorsDiscovered;
audioDecodable.CoverImageDiscovered -= AudioDecodable_CoverImageDiscovered;
audioDecodable.Cancel();
}
@ -133,40 +133,30 @@ namespace LibationWinForms.BookLiberation.BaseForms
/// (ie. shown) because Control doesn't get a window handle until it is Shown.
/// </summary>
private void OnStreamingBeginShow(object sender, string beginString) => Invoker.UIThreadAsync(Show);
#endregion
#region IStreamable event handlers
public virtual void OnStreamingBegin(object sender, string beginString)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IStreamable.StreamingBegin), Message = beginString });
public virtual void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress) { }
public virtual void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining) { }
public virtual void OnStreamingCompleted(object sender, string completedString)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IStreamable.StreamingCompleted), Message = completedString });
#region Streamable event handlers
public virtual void Streamable_StreamingBegin(object sender, string beginString) { }
public virtual void Streamable_StreamingProgressChanged(object sender, DownloadProgress downloadProgress) { }
public virtual void Streamable_StreamingTimeRemaining(object sender, TimeSpan timeRemaining) { }
public virtual void Streamable_StreamingCompleted(object sender, string completedString) { }
#endregion
#region IProcessable event handlers
public virtual void OnBegin(object sender, LibraryBook libraryBook)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IProcessable.Begin), Book = libraryBook.LogFriendly() });
public virtual void OnStatusUpdate(object sender, string statusUpdate)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IProcessable.StatusUpdate), Status = statusUpdate });
public virtual void OnCompleted(object sender, LibraryBook libraryBook)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IProcessable.Completed), Book = libraryBook.LogFriendly() });
#region Processable event handlers
public virtual void Processable_Begin(object sender, LibraryBook libraryBook) { }
public virtual void Processable_StatusUpdate(object sender, string statusUpdate) { }
public virtual void Processable_Completed(object sender, LibraryBook libraryBook) { }
#endregion
#region IAudioDecodable event handlers
public virtual void OnRequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IAudioDecodable.RequestCoverArt) });
public virtual void OnTitleDiscovered(object sender, string title)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IAudioDecodable.TitleDiscovered), Title = title });
public virtual void OnAuthorsDiscovered(object sender, string authors)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IAudioDecodable.AuthorsDiscovered), Authors = authors });
public virtual void OnNarratorsDiscovered(object sender, string narrators)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IAudioDecodable.NarratorsDiscovered), Narrators = narrators });
public virtual void OnCoverImageDiscovered(object sender, byte[] coverArt)
=> Serilog.Log.Logger.Debug("Event fired {@DebugInfo}", new { Name = nameof(IAudioDecodable.CoverImageDiscovered), CoverImageBytes = coverArt?.Length });
#region AudioDecodable event handlers
public virtual void AudioDecodable_RequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate) { }
public virtual void AudioDecodable_TitleDiscovered(object sender, string title) { }
public virtual void AudioDecodable_AuthorsDiscovered(object sender, string authors) { }
public virtual void AudioDecodable_NarratorsDiscovered(object sender, string narrators) { }
public virtual void AudioDecodable_CoverImageDiscovered(object sender, byte[] coverArt) { }
#endregion
}
}

View File

@ -17,15 +17,15 @@ namespace LibationWinForms.BookLiberation
}
#region IStreamable event handler overrides
public override void OnStreamingBegin(object sender, string beginString)
#region Streamable event handler overrides
public override void Streamable_StreamingBegin(object sender, string beginString)
{
base.OnStreamingBegin(sender, beginString);
base.Streamable_StreamingBegin(sender, beginString);
filenameLbl.UIThreadAsync(() => filenameLbl.Text = beginString);
}
public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress)
public override void Streamable_StreamingProgressChanged(object sender, DownloadProgress downloadProgress)
{
base.OnStreamingProgressChanged(sender, downloadProgress);
base.Streamable_StreamingProgressChanged(sender, downloadProgress);
// this won't happen with download file. it will happen with download string
if (!downloadProgress.TotalBytesToReceive.HasValue || downloadProgress.TotalBytesToReceive.Value <= 0)
return;

View File

@ -4,14 +4,14 @@ namespace LibationWinForms.BookLiberation
{
internal class PdfDownloadForm : DownloadForm
{
public override void OnBegin(object sender, LibraryBook libraryBook)
public override void Processable_Begin(object sender, LibraryBook libraryBook)
{
base.OnBegin(sender, libraryBook);
base.Processable_Begin(sender, libraryBook);
LogMe.Info($"PDF Step, Begin: {libraryBook.Book}");
}
public override void OnCompleted(object sender, LibraryBook libraryBook)
public override void Processable_Completed(object sender, LibraryBook libraryBook)
{
base.OnCompleted(sender, libraryBook);
base.Processable_Completed(sender, libraryBook);
LogMe.Info($"PDF Step, Completed: {libraryBook.Book}");
}
}

View File

@ -96,7 +96,7 @@ namespace LibationWinForms.BookLiberation
await new BackupLoop(logMe, downloadPdf, automatedBackupsForm).RunBackupAsync();
}
private static IProcessable CreateBackupBook(LogMe logMe)
private static Processable CreateBackupBook(LogMe logMe)
{
var downloadPdf = CreateProcessable<DownloadPdf, PdfDownloadForm>(logMe);
@ -132,16 +132,16 @@ namespace LibationWinForms.BookLiberation
}
/// <summary>
/// Create a new <see cref="IProcessable"/> and links it to a new <see cref="LiberationBaseForm"/>.
/// Create a new <see cref="Processable"/> and links it to a new <see cref="LiberationBaseForm"/>.
/// </summary>
/// <typeparam name="TProcessable">The <see cref="IProcessable"/> derived type to create.</typeparam>
/// <typeparam name="TForm">The <see cref="LiberationBaseForm"/> derived Form to create on <see cref="IProcessable.Begin"/>, Show on <see cref="IStreamable.StreamingBegin"/>, Close on <see cref="IStreamable.StreamingCompleted"/>, and Dispose on <see cref="IProcessable.Completed"/> </typeparam>
/// <typeparam name="TProcessable">The <see cref="Processable"/> derived type to create.</typeparam>
/// <typeparam name="TForm">The <see cref="LiberationBaseForm"/> derived Form to create on <see cref="Processable.Begin"/>, Show on <see cref="Streamable.StreamingBegin"/>, Close on <see cref="Streamable.StreamingCompleted"/>, and Dispose on <see cref="Processable.Completed"/> </typeparam>
/// <param name="logMe">The logger</param>
/// <param name="completedAction">An additional event handler to handle <see cref="IProcessable.Completed"/></param>
/// <returns>A new <see cref="IProcessable"/> of type <typeparamref name="TProcessable"/></returns>
/// <param name="completedAction">An additional event handler to handle <see cref="Processable.Completed"/></param>
/// <returns>A new <see cref="Processable"/> of type <typeparamref name="TProcessable"/></returns>
private static TProcessable CreateProcessable<TProcessable, TForm>(LogMe logMe, EventHandler<LibraryBook> completedAction = null)
where TForm : LiberationBaseForm, new()
where TProcessable : IProcessable, new()
where TProcessable : Processable, new()
{
var strProc = new TProcessable();
@ -149,7 +149,7 @@ namespace LibationWinForms.BookLiberation
{
var processForm = new TForm();
processForm.RegisterFileLiberator(strProc, logMe);
processForm.OnBegin(sender, libraryBook);
processForm.Processable_Begin(sender, libraryBook);
};
strProc.Completed += completedAction;
@ -161,10 +161,10 @@ namespace LibationWinForms.BookLiberation
internal abstract class BackupRunner
{
protected LogMe LogMe { get; }
protected IProcessable Processable { get; }
protected Processable Processable { get; }
protected AutomatedBackupsForm AutomatedBackupsForm { get; }
protected BackupRunner(LogMe logMe, IProcessable processable, AutomatedBackupsForm automatedBackupsForm = null)
protected BackupRunner(LogMe logMe, Processable processable, AutomatedBackupsForm automatedBackupsForm = null)
{
LogMe = logMe;
Processable = processable;
@ -278,7 +278,7 @@ An error occurred while trying to process this book. Skip this book permanently?
protected override MessageBoxDefaultButton SkipDialogDefaultButton => MessageBoxDefaultButton.Button2;
protected override DialogResult SkipResult => DialogResult.Yes;
public BackupSingle(LogMe logMe, IProcessable processable, LibraryBook libraryBook)
public BackupSingle(LogMe logMe, Processable processable, LibraryBook libraryBook)
: base(logMe, processable)
{
_libraryBook = libraryBook;
@ -307,7 +307,7 @@ An error occurred while trying to process this book.
protected override MessageBoxDefaultButton SkipDialogDefaultButton => MessageBoxDefaultButton.Button1;
protected override DialogResult SkipResult => DialogResult.Ignore;
public BackupLoop(LogMe logMe, IProcessable processable, AutomatedBackupsForm automatedBackupsForm)
public BackupLoop(LogMe logMe, Processable processable, AutomatedBackupsForm automatedBackupsForm)
: base(logMe, processable, automatedBackupsForm) { }
protected override async Task RunAsync()