Minor edits and reorganizations.

This commit is contained in:
Michael Bucari-Tovo 2021-06-26 01:52:18 -06:00
parent 9930daa914
commit 6bd809c7c6
4 changed files with 77 additions and 67 deletions

View File

@ -3,7 +3,6 @@ using Dinah.Core.Diagnostics;
using Dinah.Core.IO; using Dinah.Core.IO;
using Dinah.Core.StepRunner; using Dinah.Core.StepRunner;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -18,9 +17,11 @@ namespace AaxDecrypter
string outDir { get; } string outDir { get; }
string outputFileName { get; } string outputFileName { get; }
ChapterInfo chapters { get; } ChapterInfo chapters { get; }
TagLib.Mpeg4.File tags { get; }
void SetOutputFilename(string outFileName); void SetOutputFilename(string outFileName);
string Title { get; }
string Author { get; }
string Narrator { get; }
byte[] CoverArt { get; }
} }
public interface IAdvancedAaxcToM4bConverter : ISimpleAaxToM4bConverter2 public interface IAdvancedAaxcToM4bConverter : ISimpleAaxToM4bConverter2
{ {
@ -32,20 +33,17 @@ namespace AaxDecrypter
} }
public class AaxcDownloadConverter : IAdvancedAaxcToM4bConverter public class AaxcDownloadConverter : IAdvancedAaxcToM4bConverter
{ {
public event EventHandler<int> DecryptProgressUpdate;
public string AppName { get; set; } = nameof(AaxcDownloadConverter); public string AppName { get; set; } = nameof(AaxcDownloadConverter);
public string outDir { get; private set; } public string outDir { get; private set; }
public string outputFileName { get; private set; } public string outputFileName { get; private set; }
public ChapterInfo chapters { get; private set; } public ChapterInfo chapters { get; private set; }
public TagLib.Mpeg4.File tags { get; private set; } public string Title => aaxcTagLib.Tag.Title.Replace(" (Unabridged)", "");
public event EventHandler<int> DecryptProgressUpdate; public string Author => aaxcTagLib.Tag.FirstPerformer ?? "[unknown]";
public string Narrator => string.IsNullOrWhiteSpace(aaxcTagLib.Tag.FirstComposer) ? aaxcTagLib.GetTag(TagLib.TagTypes.Apple).Narrator : aaxcTagLib.Tag.FirstComposer;
public string Title => tags.Tag.Title.Replace(" (Unabridged)", ""); public byte[] CoverArt => aaxcTagLib.Tag.Pictures.Length > 0 ? aaxcTagLib.Tag.Pictures[0].Data.Data : default;
public string Author => tags.Tag.FirstPerformer ?? "[unknown]";
public string Narrator => string.IsNullOrWhiteSpace(tags.Tag.FirstComposer) ? tags.GetTag(TagLib.TagTypes.Apple).Narrator : tags.Tag.FirstComposer;
public byte[] CoverArt => tags.Tag.Pictures.Length > 0 ? tags.Tag.Pictures[0].Data.Data : default;
private TagLib.Mpeg4.File aaxcTagLib { get; set; }
private StepSequence steps { get; } private StepSequence steps { get; }
private DownloadLicense downloadLicense { get; set; } private DownloadLicense downloadLicense { get; set; }
private string metadataPath => Path.Combine(outDir, Path.GetFileName(outputFileName) + ".ffmeta"); private string metadataPath => Path.Combine(outDir, Path.GetFileName(outputFileName) + ".ffmeta");
@ -73,9 +71,9 @@ namespace AaxDecrypter
["Step 1: Create Dir"] = Step1_CreateDir, ["Step 1: Create Dir"] = Step1_CreateDir,
["Step 2: Download and Combine Audiobook"] = Step2_DownloadAndCombine, ["Step 2: Download and Combine Audiobook"] = Step2_DownloadAndCombine,
["Step 2: Restore Aaxc Metadata"] = Step3_RestoreMetadata, ["Step 3: Restore Aaxc Metadata"] = Step3_RestoreMetadata,
["Step 3 Create Cue"] = Step4_CreateCue, ["Step 4: Create Cue"] = Step4_CreateCue,
["Step 4 Create Nfo"] = Step5_CreateNfo, ["Step 5: Create Nfo"] = Step5_CreateNfo,
}; };
downloadLicense = dlLic; downloadLicense = dlLic;
@ -90,12 +88,12 @@ namespace AaxDecrypter
var networkFile = await NetworkFileAbstraction.CreateAsync(client, new Uri(downloadLicense.DownloadUrl)); var networkFile = await NetworkFileAbstraction.CreateAsync(client, new Uri(downloadLicense.DownloadUrl));
tags = await Task.Run(() => TagLib.File.Create(networkFile, "audio/mp4", TagLib.ReadStyle.Average) as TagLib.Mpeg4.File); aaxcTagLib = await Task.Run(() => TagLib.File.Create(networkFile, "audio/mp4", TagLib.ReadStyle.Average) as TagLib.Mpeg4.File);
var defaultFilename = Path.Combine( var defaultFilename = Path.Combine(
outDir, outDir,
PathLib.ToPathSafeString(tags.Tag.FirstPerformer??"[unknown]"), PathLib.ToPathSafeString(aaxcTagLib.Tag.FirstPerformer??"[unknown]"),
PathLib.ToPathSafeString(tags.Tag.Title.Replace(" (Unabridged)", "")) + ".m4b" PathLib.ToPathSafeString(aaxcTagLib.Tag.Title.Replace(" (Unabridged)", "")) + ".m4b"
); );
SetOutputFilename(defaultFilename); SetOutputFilename(defaultFilename);
@ -120,7 +118,7 @@ namespace AaxDecrypter
return false; return false;
} }
var speedup = (int)(tags.Properties.Duration.TotalSeconds / (long)Elapsed.TotalSeconds); var speedup = (int)(aaxcTagLib.Properties.Duration.TotalSeconds / (long)Elapsed.TotalSeconds);
Console.WriteLine("Speedup is " + speedup + "x realtime."); Console.WriteLine("Speedup is " + speedup + "x realtime.");
Console.WriteLine("Done"); Console.WriteLine("Done");
return true; return true;
@ -162,37 +160,9 @@ namespace AaxDecrypter
private void AaxcProcesser_ProgressUpdate(object sender, TimeSpan e) private void AaxcProcesser_ProgressUpdate(object sender, TimeSpan e)
{ {
double progressPercent = 100 * e.TotalSeconds / tags.Properties.Duration.TotalSeconds; double progressPercent = 100 * e.TotalSeconds / aaxcTagLib.Properties.Duration.TotalSeconds;
DecryptProgressUpdate?.Invoke(this, (int)progressPercent); DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
speedSamples.Enqueue(new DataRate
{
SampleTime = DateTime.Now,
ProcessPosition = e
});
int sampleNum = 5;
if (speedSamples.Count < sampleNum) return;
var oldestSample = speedSamples.Dequeue();
double harmonicDenom = 0;
foreach (var sample in speedSamples)
{
double inverseRate = (sample.SampleTime - oldestSample.SampleTime).TotalSeconds / (sample.ProcessPosition.TotalSeconds - oldestSample.ProcessPosition.TotalSeconds);
harmonicDenom += inverseRate;
oldestSample = sample;
}
double averageRate = (sampleNum - 1) / harmonicDenom;
}
private Queue<DataRate> speedSamples = new Queue<DataRate>(5);
private class DataRate
{
public DateTime SampleTime;
public TimeSpan ProcessPosition;
} }
public bool Step3_RestoreMetadata() public bool Step3_RestoreMetadata()
@ -202,7 +172,7 @@ namespace AaxDecrypter
var destTags = outFile.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag; var destTags = outFile.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag;
destTags.Clear(); destTags.Clear();
var sourceTag = tags.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag; var sourceTag = aaxcTagLib.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag;
//copy all metadata fields in the source file, even those that TagLib doesn't //copy all metadata fields in the source file, even those that TagLib doesn't
//recognize, to the output file. //recognize, to the output file.
@ -222,7 +192,7 @@ namespace AaxDecrypter
public bool Step5_CreateNfo() public bool Step5_CreateNfo()
{ {
File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".nfo"), NFO.CreateContents(AppName, tags, chapters)); File.WriteAllText(PathLib.ReplaceExtension(outputFileName, ".nfo"), NFO.CreateContents(AppName, aaxcTagLib, chapters));
return true; return true;
} }
} }

View File

@ -1,8 +1,6 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace AaxDecrypter namespace AaxDecrypter
{ {

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace AaxDecrypter namespace AaxDecrypter
{ {
/// <summary> /// <summary>
/// Download audible aaxc, decrypt, remux,and add metadata. /// Download audible aaxc, decrypt, remux,and add metadata.
/// </summary> /// </summary>
@ -22,23 +22,57 @@ namespace AaxDecrypter
{ {
FFMpegPath = ffmpegPath; FFMpegPath = ffmpegPath;
} }
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string outputFile)
{
//This process gets the aaxc from the url and streams the decrypted
//m4b to the output file. Preserves album art, and ignores metadata.
var StartInfo = new ProcessStartInfo
{
FileName = FFMpegPath,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
ArgumentList =
{
"-ignore_chapters", //prevents ffmpeg from copying chapter info from aaxc to output file
"true",
"-audible_key",
audibleKey,
"-audible_iv",
audibleIV,
"-user_agent",
userAgent,
"-i",
aaxcUrl,
"-c", //audio codec
"copy", //copy stream
"-f", //force output format: adts
"mp4",
outputFile, //pipe output to standard output
"-y"
}
};
await ProcessBool(StartInfo);
}
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string metadataPath, string outputFile) public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string metadataPath, string outputFile)
{ {
//This process gets the aaxc from the url and streams the decrypted //This process gets the aaxc from the url and streams the decrypted
//m4b to the output file. Preserves album art, but replaces metadata. //m4b to the output file. Preserves album art, but replaces metadata.
var downloader = new Process var StartInfo = new ProcessStartInfo
{ {
StartInfo = new ProcessStartInfo FileName = FFMpegPath,
{ RedirectStandardError = true,
FileName = FFMpegPath, CreateNoWindow = true,
RedirectStandardError = true, WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true, UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden, WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
UseShellExecute = false, ArgumentList =
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
ArgumentList =
{ {
"-ignore_chapters", //prevents ffmpeg from copying chapter info from aaxc to output file "-ignore_chapters", //prevents ffmpeg from copying chapter info from aaxc to output file
"true", "true",
@ -63,7 +97,15 @@ namespace AaxDecrypter
outputFile, //pipe output to standard output outputFile, //pipe output to standard output
"-y" "-y"
} }
} };
await ProcessBool(StartInfo);
}
private async Task ProcessBool(ProcessStartInfo startInfo)
{
var downloader = new Process
{
StartInfo = startInfo
}; };
IsRunning = true; IsRunning = true;
@ -79,6 +121,7 @@ namespace AaxDecrypter
IsRunning = false; IsRunning = false;
Succeeded = downloader.ExitCode == 0; Succeeded = downloader.ExitCode == 0;
} }
private void Remuxer_ErrorDataReceived(object sender, DataReceivedEventArgs e) private void Remuxer_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{ {
if (string.IsNullOrEmpty(e.Data)) if (string.IsNullOrEmpty(e.Data))
@ -104,6 +147,5 @@ namespace AaxDecrypter
process.Kill(); process.Kill();
} }
} }
} }
} }

View File

@ -13,7 +13,7 @@
<!-- <PublishSingleFile>true</PublishSingleFile> --> <!-- <PublishSingleFile>true</PublishSingleFile> -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<Version>4.4.0.120</Version> <Version>4.4.0.121</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>