diff --git a/AaxDecrypter/AaxcDownloadConverter.cs b/AaxDecrypter/AaxcDownloadConverter.cs index 6cb90ee6..11038eb1 100644 --- a/AaxDecrypter/AaxcDownloadConverter.cs +++ b/AaxDecrypter/AaxcDownloadConverter.cs @@ -3,10 +3,7 @@ using Dinah.Core.Diagnostics; using Dinah.Core.IO; using Dinah.Core.StepRunner; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Threading.Tasks; namespace AaxDecrypter { @@ -20,7 +17,7 @@ namespace AaxDecrypter string AppName { get; set; } string outDir { get; } string outputFileName { get; } - ChapterInfo chapters { get; } + DownloadLicense downloadLicense { get; } AaxcTagLibFile aaxcTagLib { get; } byte[] coverArt { get; } void SetCoverArt(byte[] coverArt); @@ -45,23 +42,22 @@ namespace AaxDecrypter public string AppName { get; set; } = nameof(AaxcDownloadConverter); public string outDir { get; private set; } public string outputFileName { get; private set; } - public ChapterInfo chapters { get; private set; } + public DownloadLicense downloadLicense { get; private set; } public AaxcTagLibFile aaxcTagLib { get; private set; } public byte[] coverArt { get; private set; } private StepSequence steps { get; } - private DownloadLicense downloadLicense { get; set; } private FFMpegAaxcProcesser aaxcProcesser; private bool isCanceled { get; set; } - public static AaxcDownloadConverter Create(string outDirectory, DownloadLicense dlLic, ChapterInfo chapters = null) + public static AaxcDownloadConverter Create(string outDirectory, DownloadLicense dlLic) { - var converter = new AaxcDownloadConverter(outDirectory, dlLic, chapters); + var converter = new AaxcDownloadConverter(outDirectory, dlLic); converter.SetOutputFilename(Path.GetTempFileName()); return converter; } - private AaxcDownloadConverter(string outDirectory, DownloadLicense dlLic, ChapterInfo chapters) + private AaxcDownloadConverter(string outDirectory, DownloadLicense dlLic) { ArgumentValidator.EnsureNotNullOrWhiteSpace(outDirectory, nameof(outDirectory)); ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic)); @@ -86,7 +82,6 @@ namespace AaxDecrypter aaxcProcesser.ProgressUpdate += AaxcProcesser_ProgressUpdate; downloadLicense = dlLic; - this.chapters = chapters; } public void SetOutputFilename(string outFileName) @@ -147,13 +142,14 @@ namespace AaxDecrypter RetrievedTags?.Invoke(this, aaxcTagLib); RetrievedCoverArt?.Invoke(this, coverArt); - return !isCanceled; + return !isCanceled; } public bool Step3_DownloadAndCombine() { DecryptProgressUpdate?.Invoke(this, int.MaxValue); - bool userSuppliedChapters = chapters != null; + + bool userSuppliedChapters = downloadLicense.ChapterInfo != null; string metadataPath = null; @@ -162,7 +158,7 @@ namespace AaxDecrypter //Only write chaopters to the metadata file. All other aaxc metadata will be //wiped out but is restored in Step 3. metadataPath = Path.Combine(outDir, Path.GetFileName(outputFileName) + ".ffmeta"); - File.WriteAllText(metadataPath, chapters.ToFFMeta(true)); + File.WriteAllText(metadataPath, downloadLicense.ChapterInfo.ToFFMeta(true)); } aaxcProcesser.ProcessBook( @@ -172,7 +168,7 @@ namespace AaxDecrypter .GetResult(); if (!userSuppliedChapters && aaxcProcesser.Succeeded) - chapters = new ChapterInfo(outputFileName); + downloadLicense.ChapterInfo = new ChapterInfo(outputFileName); if (userSuppliedChapters) FileExt.SafeDelete(metadataPath); @@ -188,7 +184,7 @@ namespace AaxDecrypter double estTimeRemaining = remainingSecsToProcess / e.ProcessSpeed; if (double.IsNormal(estTimeRemaining)) - DecryptTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining)); + DecryptTimeRemaining?.Invoke(this, TimeSpan.FromSeconds(estTimeRemaining)); double progressPercent = 100 * e.ProcessPosition.TotalSeconds / aaxcTagLib.Properties.Duration.TotalSeconds; @@ -215,13 +211,13 @@ namespace AaxDecrypter public bool Step5_CreateCue() { - File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".cue"), Cue.CreateContents(Path.GetFileName(outputFileName), chapters)); + File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".cue"), Cue.CreateContents(Path.GetFileName(outputFileName), downloadLicense.ChapterInfo)); return !isCanceled; } public bool Step6_CreateNfo() { - File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".nfo"), NFO.CreateContents(AppName, aaxcTagLib, chapters)); + File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".nfo"), NFO.CreateContents(AppName, aaxcTagLib, downloadLicense.ChapterInfo)); return !isCanceled; } diff --git a/AaxDecrypter/Chapters.cs b/AaxDecrypter/Chapters.cs index 83d0f117..8a05e7e2 100644 --- a/AaxDecrypter/Chapters.cs +++ b/AaxDecrypter/Chapters.cs @@ -1,5 +1,6 @@ using Dinah.Core; using Dinah.Core.Diagnostics; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -66,8 +67,8 @@ namespace AaxDecrypter public class Chapter { public string Title { get; } - public long StartOffsetMs { get; } - public long EndOffsetMs { get; } + public TimeSpan StartOffset { get; } + public TimeSpan EndOffset { get; } public Chapter(string title, long startOffsetMs, long lengthMs) { ArgumentValidator.EnsureNotNullOrEmpty(title, nameof(title)); @@ -75,16 +76,16 @@ namespace AaxDecrypter ArgumentValidator.EnsureGreaterThan(lengthMs, nameof(lengthMs), 0); Title = title; - StartOffsetMs = startOffsetMs; - EndOffsetMs = StartOffsetMs + lengthMs; + StartOffset = TimeSpan.FromMilliseconds(startOffsetMs); + EndOffset = StartOffset + TimeSpan.FromMilliseconds(lengthMs); } public string ToFFMeta() { return "[CHAPTER]\n" + "TIMEBASE=1/1000\n" + - "START=" + StartOffsetMs + "\n" + - "END=" + EndOffsetMs + "\n" + + "START=" + StartOffset.TotalMilliseconds + "\n" + + "END=" + EndOffset.TotalMilliseconds + "\n" + "title=" + Title; } } diff --git a/AaxDecrypter/Cue.cs b/AaxDecrypter/Cue.cs index cc892aa2..8f492f66 100644 --- a/AaxDecrypter/Cue.cs +++ b/AaxDecrypter/Cue.cs @@ -17,11 +17,10 @@ namespace AaxDecrypter foreach (var c in chapters.Chapters) { trackCount++; - var startTime = TimeSpan.FromMilliseconds(c.StartOffsetMs); stringBuilder.AppendLine($"TRACK {trackCount} AUDIO"); stringBuilder.AppendLine($" TITLE \"{c.Title}\""); - stringBuilder.AppendLine($" INDEX 01 {(int)startTime.TotalMinutes}:{startTime:ss\\:ff}"); + stringBuilder.AppendLine($" INDEX 01 {(int)c.StartOffset.TotalMinutes}:{c.StartOffset:ss\\:ff}"); } return stringBuilder.ToString(); diff --git a/AaxDecrypter/DownloadLicense.cs b/AaxDecrypter/DownloadLicense.cs index d75b4192..633e8bf2 100644 --- a/AaxDecrypter/DownloadLicense.cs +++ b/AaxDecrypter/DownloadLicense.cs @@ -1,9 +1,4 @@ using Dinah.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace AaxDecrypter { @@ -13,6 +8,7 @@ namespace AaxDecrypter public string AudibleKey { get; } public string AudibleIV { get; } public string UserAgent { get; } + public ChapterInfo ChapterInfo { get; set; } public DownloadLicense(string downloadUrl, string audibleKey, string audibleIV, string userAgent) { diff --git a/FileLiberator/BackupBook.cs b/FileLiberator/BackupBook.cs index b778eec0..5a06ce73 100644 --- a/FileLiberator/BackupBook.cs +++ b/FileLiberator/BackupBook.cs @@ -1,9 +1,7 @@ using System; -using System.Linq; using System.Threading.Tasks; using DataLayer; using Dinah.Core.ErrorHandling; -using FileLiberator; using FileManager; namespace FileLiberator diff --git a/FileLiberator/DownloadDecryptBook.cs b/FileLiberator/DownloadDecryptBook.cs index 66e57d42..0cead1c7 100644 --- a/FileLiberator/DownloadDecryptBook.cs +++ b/FileLiberator/DownloadDecryptBook.cs @@ -69,24 +69,30 @@ namespace FileLiberator var api = await InternalUtilities.AudibleApiActions.GetApiAsync(libraryBook.Account, libraryBook.Book.Locale); - var dlLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId); + var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId); - var aaxcDecryptDlLic = new DownloadLicense(dlLic.DownloadUrl, dlLic.AudibleKey, dlLic.AudibleIV, Resources.UserAgent); + var aaxcDecryptDlLic = new DownloadLicense + ( + contentLic.ContentMetadata?.ContentUrl?.OfflineUrl, + contentLic.Voucher?.Key, + contentLic.Voucher?.Iv, + Resources.UserAgent + ); if (Configuration.Instance.AllowLibationFixup) { - var contentMetadata = await api.GetLibraryBookMetadataAsync(libraryBook.Book.AudibleProductId); - var aaxcDecryptChapters = new ChapterInfo(); + aaxcDecryptDlLic.ChapterInfo = new ChapterInfo(); - foreach (var chap in contentMetadata?.ChapterInfo?.Chapters) - aaxcDecryptChapters.AddChapter(new Chapter(chap.Title, chap.StartOffsetMs, chap.LengthMs)); + foreach (var chap in contentLic.ContentMetadata?.ChapterInfo?.Chapters) + aaxcDecryptDlLic.ChapterInfo.AddChapter( + new Chapter( + chap.Title, + chap.StartOffsetMs, + chap.LengthMs + )); + } - aaxcDownloader = AaxcDownloadConverter.Create(destinationDir, aaxcDecryptDlLic, aaxcDecryptChapters); - } - else - { - aaxcDownloader = AaxcDownloadConverter.Create(destinationDir, aaxcDecryptDlLic); - } + aaxcDownloader = AaxcDownloadConverter.Create(destinationDir, aaxcDecryptDlLic); aaxcDownloader.AppName = "Libation"; diff --git a/FileLiberator/DownloadPdf.cs b/FileLiberator/DownloadPdf.cs index 917d1de6..ceab5ff6 100644 --- a/FileLiberator/DownloadPdf.cs +++ b/FileLiberator/DownloadPdf.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; diff --git a/FileLiberator/IProcessableExt.cs b/FileLiberator/IProcessableExt.cs index 0ad10969..ef7bed21 100644 --- a/FileLiberator/IProcessableExt.cs +++ b/FileLiberator/IProcessableExt.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ApplicationServices; diff --git a/LibationWinForms/BookLiberation/ProcessorAutomationController.cs b/LibationWinForms/BookLiberation/ProcessorAutomationController.cs index c25f7e6a..1b6455e2 100644 --- a/LibationWinForms/BookLiberation/ProcessorAutomationController.cs +++ b/LibationWinForms/BookLiberation/ProcessorAutomationController.cs @@ -265,25 +265,32 @@ namespace LibationWinForms.BookLiberation 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 setArt) + void requestCoverArt(object _, Action setCoverArtDelegate) { var picDef = new FileManager.PictureDefinition(libraryBook.Book.PictureId, FileManager.PictureSize._500x500); (bool isDefault, byte[] picture) = FileManager.PictureStorage.GetPicture(picDef); if (isDefault) { - void pictureCached(object _, string pictureId) => onPictureCached(libraryBook, pictureId, setArt, pictureCached); + void pictureCached(object _, string pictureId) + { + if (pictureId == libraryBook.Book.PictureId) + { + FileManager.PictureStorage.PictureCached -= pictureCached; + + var picDef = new FileManager.PictureDefinition(libraryBook.Book.PictureId, FileManager.PictureSize._500x500); + (_, picture) = FileManager.PictureStorage.GetPicture(picDef); + + setCoverArtDelegate(picture); + } + }; FileManager.PictureStorage.PictureCached += pictureCached; } else - setArt(picture); + setCoverArtDelegate(picture); } - - - #endregion #region subscribe new form to model's events @@ -319,18 +326,7 @@ namespace LibationWinForms.BookLiberation }; #endregion } - private static void onPictureCached(LibraryBook libraryBook, string picId, Action setArt, EventHandler pictureCacheDelegate) - { - if (picId == libraryBook.Book.PictureId) - { - FileManager.PictureStorage.PictureCached -= pictureCacheDelegate; - - var picDef = new FileManager.PictureDefinition(libraryBook.Book.PictureId, FileManager.PictureSize._500x500); - (_, byte[] picture) = FileManager.PictureStorage.GetPicture(picDef); - - setArt(picture); - } - } + private static (AutomatedBackupsForm, LogMe) attachToBackupsForm(IDownloadableProcessable downloadable) { #region create form and logger