Minor edits and reorganizations.
This commit is contained in:
parent
9930daa914
commit
6bd809c7c6
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user