Convert IProcessable to abstract class Processable.

This commit is contained in:
Michael Bucari-Tovo 2021-10-05 16:10:56 -06:00
parent be5e18d977
commit 6e66314605
11 changed files with 143 additions and 141 deletions

View file

@ -12,39 +12,32 @@ using System.Threading.Tasks;
namespace FileLiberator
{
public class ConvertToMp3 : IAudioDecodable
public class ConvertToMp3 : Processable, IAudioDecodable
{
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 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
{
@ -78,8 +71,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 +83,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

@ -13,26 +13,19 @@ using FileManager;
namespace FileLiberator
{
public class DownloadDecryptBook : IAudioDecodable
public class DownloadDecryptBook : Processable, IAudioDecodable
{
private AudiobookDownloadBase aaxcDownloader;
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 +50,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
{
@ -101,8 +94,8 @@ namespace FileLiberator
aaxcDownloader = contentLic.DrmType == AudibleApi.Common.DrmType.Adrm
? new AaxcDownloadConverter(outFileName, cacheDir, audiobookDlLic, outputFormat, Configuration.Instance.SplitFilesByChapter) { AppName = "Libation" }
: new UnencryptedAudiobookDownloader(outFileName, cacheDir, audiobookDlLic);
aaxcDownloader.DecryptProgressUpdate += (s, progress) => StreamingProgressChanged?.Invoke(this, progress);
aaxcDownloader.DecryptTimeRemaining += (s, remaining) => StreamingTimeRemaining?.Invoke(this, remaining);
aaxcDownloader.DecryptProgressUpdate += (s, progress) => OnStreamingProgressChanged(progress);
aaxcDownloader.DecryptTimeRemaining += (s, remaining) => OnStreamingTimeRemaining(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);
@ -119,7 +112,7 @@ namespace FileLiberator
}
finally
{
StreamingCompleted?.Invoke(this, $"Completed downloading and decrypting {libraryBook.Book.Title}");
OnStreamingCompleted($"Completed downloading and decrypting {libraryBook.Book.Title}");
}
}
@ -214,7 +207,7 @@ 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()
{

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

@ -2,7 +2,7 @@
namespace FileLiberator
{
public interface IAudioDecodable : IProcessable
public interface IAudioDecodable
{
event EventHandler<Action<byte[]>> RequestCoverArt;
event EventHandler<string> TitleDiscovered;

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

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core;
using Dinah.Core.ErrorHandling;
using Dinah.Core.Net.Http;
namespace FileLiberator
{
public abstract class Processable : IStreamable
{
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;
public event EventHandler<string> StreamingBegin;
public event EventHandler<DownloadProgress> StreamingProgressChanged;
public event EventHandler<TimeSpan> StreamingTimeRemaining;
public event EventHandler<string> StreamingCompleted;
// when used in foreach: stateful. deferred execution
public IEnumerable<LibraryBook> GetValidLibraryBooks(IEnumerable<LibraryBook> library)
=> library.Where(libraryBook =>
Validate(libraryBook)
&& (libraryBook.Book.ContentType != ContentType.Episode || FileManager.Configuration.Instance.DownloadEpisodes)
);
public 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;
}
public async Task<StatusHandler> TryProcessAsync( LibraryBook libraryBook)
=> Validate(libraryBook)
? await ProcessAsync(libraryBook)
: new StatusHandler();
/// <returns>True == Valid</returns>
public abstract bool Validate(LibraryBook libraryBook);
/// <returns>True == success</returns>
public abstract Task<StatusHandler> ProcessAsync(LibraryBook libraryBook);
public virtual void OnBegin(LibraryBook libraryBook)
{
Begin?.Invoke(this, libraryBook);
}
public virtual void OnCompleted(LibraryBook libraryBook)
{
Completed?.Invoke(this, libraryBook);
}
public virtual void OnStatusUpdate(string status)
{
StatusUpdate?.Invoke(this, status);
}
public virtual void OnStreamingBegin(string filePath)
{
StreamingBegin?.Invoke(this, filePath);
}
public virtual void OnStreamingCompleted(string filePath)
{
StreamingCompleted?.Invoke(this, filePath);
}
public virtual void OnStreamingProgressChanged(DownloadProgress progress)
{
StreamingProgressChanged?.Invoke(this, progress);
}
public virtual void OnStreamingTimeRemaining(TimeSpan timeRemaining)
{
StreamingTimeRemaining?.Invoke(this, timeRemaining);
}
}
}