Download and decrypt AAXC files. Upgraded ffmpeg to 4.4-19.
This commit is contained in:
parent
54c21e969e
commit
310b90962c
@ -18,19 +18,19 @@
|
||||
<None Update="DecryptLib\AtomicParsley.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\avcodec-57.dll">
|
||||
<None Update="DecryptLib\avcodec-58.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\avdevice-57.dll">
|
||||
<None Update="DecryptLib\avdevice-58.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\avfilter-6.dll">
|
||||
<None Update="DecryptLib\avfilter-7.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\avformat-57.dll">
|
||||
<None Update="DecryptLib\avformat-58.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\avutil-55.dll">
|
||||
<None Update="DecryptLib\avutil-56.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\cygcrypto-1.0.0.dll">
|
||||
@ -63,10 +63,10 @@
|
||||
<None Update="DecryptLib\postproc-54.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\swresample-2.dll">
|
||||
<None Update="DecryptLib\swresample-3.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\swscale-4.dll">
|
||||
<None Update="DecryptLib\swscale-5.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="DecryptLib\taglib-sharp.dll">
|
||||
|
||||
@ -48,7 +48,8 @@ namespace AaxDecrypter
|
||||
public event EventHandler<int> DecryptProgressUpdate;
|
||||
|
||||
public string inputFileName { get; }
|
||||
public string decryptKey { get; private set; }
|
||||
public string audible_key { get; private set; }
|
||||
public string audible_iv { get; private set; }
|
||||
|
||||
private StepSequence steps { get; }
|
||||
public byte[] coverBytes { get; private set; }
|
||||
@ -62,20 +63,21 @@ namespace AaxDecrypter
|
||||
public Tags tags { get; private set; }
|
||||
public EncodingInfo encodingInfo { get; private set; }
|
||||
|
||||
private Func<Task<string>> getKeyFuncAsync { get; }
|
||||
|
||||
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string decryptKey, Func<Task<string>> getKeyFunc, Chapters chapters = null)
|
||||
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string audible_key, string audible_iv, Chapters chapters = null)
|
||||
{
|
||||
var converter = new AaxToM4bConverter(inputFile, decryptKey, getKeyFunc);
|
||||
var converter = new AaxToM4bConverter(inputFile, audible_key, audible_iv);
|
||||
converter.chapters = chapters ?? new AAXChapters(inputFile);
|
||||
await converter.prelimProcessing();
|
||||
converter.printPrelim();
|
||||
|
||||
return converter;
|
||||
}
|
||||
private AaxToM4bConverter(string inputFile, string decryptKey, Func<Task<string>> getKeyFunc)
|
||||
private AaxToM4bConverter(string inputFile, string audible_key, string audible_iv)
|
||||
{
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(inputFile, nameof(inputFile));
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(inputFile, nameof(inputFile));
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(audible_key, nameof(audible_key));
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(audible_iv, nameof(audible_iv));
|
||||
|
||||
if (!File.Exists(inputFile))
|
||||
throw new ArgumentNullException(nameof(inputFile), "File does not exist");
|
||||
|
||||
@ -94,8 +96,8 @@ namespace AaxDecrypter
|
||||
};
|
||||
|
||||
inputFileName = inputFile;
|
||||
this.decryptKey = decryptKey;
|
||||
this.getKeyFuncAsync = getKeyFunc;
|
||||
this.audible_key = audible_key;
|
||||
this.audible_iv = audible_iv;
|
||||
}
|
||||
|
||||
private async Task prelimProcessing()
|
||||
@ -109,17 +111,17 @@ namespace AaxDecrypter
|
||||
PathLib.ToPathSafeString(tags.title) + ".m4b"
|
||||
);
|
||||
|
||||
// set default name
|
||||
SetOutputFilename(defaultFilename);
|
||||
// set default name
|
||||
SetOutputFilename(defaultFilename);
|
||||
|
||||
await Task.Run(() => saveCover(inputFileName));
|
||||
}
|
||||
|
||||
private void saveCover(string aaxFile)
|
||||
{
|
||||
using var file = TagLib.File.Create(aaxFile, "audio/mp4", TagLib.ReadStyle.Average);
|
||||
coverBytes = file.Tag.Pictures[0].Data.Data;
|
||||
}
|
||||
using var file = TagLib.File.Create(aaxFile, "audio/mp4", TagLib.ReadStyle.Average);
|
||||
coverBytes = file.Tag.Pictures[0].Data.Data;
|
||||
}
|
||||
|
||||
private void printPrelim()
|
||||
{
|
||||
@ -171,27 +173,16 @@ namespace AaxDecrypter
|
||||
{
|
||||
DecryptProgressUpdate?.Invoke(this, 0);
|
||||
|
||||
var tempRipFile = Path.Combine(outDir, "funny.aac");
|
||||
var tempRipFile = Path.Combine(outDir, "funny.mp4");
|
||||
|
||||
var fail = "WARNING-Decrypt failure. ";
|
||||
|
||||
int returnCode;
|
||||
if (string.IsNullOrWhiteSpace(decryptKey))
|
||||
{
|
||||
returnCode = getKey_decrypt(tempRipFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnCode = decrypt(tempRipFile);
|
||||
if (returnCode == -99)
|
||||
{
|
||||
Console.WriteLine($"{fail}Incorrect decrypt key: {decryptKey}");
|
||||
decryptKey = null;
|
||||
returnCode = getKey_decrypt(tempRipFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnCode == 100)
|
||||
returnCode = decrypt(tempRipFile);
|
||||
if (returnCode == -99)
|
||||
Console.WriteLine($"{fail}Incorrect decrypt key.");
|
||||
else if (returnCode == 100)
|
||||
Console.WriteLine($"{fail}Thread completed without changing return code. This shouldn't be possible");
|
||||
else if (returnCode == 0)
|
||||
{
|
||||
@ -200,8 +191,6 @@ namespace AaxDecrypter
|
||||
DecryptProgressUpdate?.Invoke(this, 100);
|
||||
return true;
|
||||
}
|
||||
else if (returnCode == -99)
|
||||
Console.WriteLine($"{fail}Incorrect decrypt key: {decryptKey}");
|
||||
else // any other returnCode
|
||||
Console.WriteLine($"{fail}Unknown failure code: {returnCode}");
|
||||
|
||||
@ -210,24 +199,16 @@ namespace AaxDecrypter
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getKey_decrypt(string tempRipFile)
|
||||
{
|
||||
decryptKey = getKey();
|
||||
return decrypt(tempRipFile);
|
||||
}
|
||||
|
||||
// I am NOT happy about doing async this way. Async needs to be added to Step framework
|
||||
string getKey() => getKeyFuncAsync().GetAwaiter().GetResult();
|
||||
|
||||
private int decrypt(string tempRipFile)
|
||||
{
|
||||
FileExt.SafeDelete(tempRipFile);
|
||||
|
||||
Console.WriteLine("Decrypting with key " + decryptKey);
|
||||
Console.WriteLine($"Decrypting with key={audible_key}, iv={audible_iv}");
|
||||
|
||||
var returnCode = 100;
|
||||
var thread = new Thread(() => returnCode = ngDecrypt());
|
||||
thread.Start();
|
||||
var thread = new Thread((b) => returnCode = ngDecrypt(b));
|
||||
thread.Start(tempRipFile);
|
||||
|
||||
double fileLen = new FileInfo(inputFileName).Length;
|
||||
while (thread.IsAlive && returnCode == 100)
|
||||
@ -244,25 +225,35 @@ namespace AaxDecrypter
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
private int ngDecrypt()
|
||||
private int ngDecrypt(object tempFileNameObj)
|
||||
{
|
||||
var tempFileName = tempFileNameObj as string;
|
||||
|
||||
string args = "-audible_key "
|
||||
+ audible_key
|
||||
+ " -audible_iv "
|
||||
+ audible_iv
|
||||
+ " -i "
|
||||
+ "\"" + inputFileName + "\""
|
||||
+ " -c:a copy -vn -sn -dn -y "
|
||||
+ "\"" + tempFileName + "\"";
|
||||
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = DecryptSupportLibraries.mp4trackdumpPath,
|
||||
Arguments = "-c " + encodingInfo.channels + " -r " + encodingInfo.sampleRate + " \"" + inputFileName + "\""
|
||||
FileName = DecryptSupportLibraries.ffmpegPath,
|
||||
Arguments = args
|
||||
};
|
||||
info.EnvironmentVariables["VARIABLE"] = decryptKey;
|
||||
|
||||
var result = info.RunHidden();
|
||||
|
||||
// bad checksum -- bad decrypt key
|
||||
if (result.Output.Contains("checksums mismatch, aborting!"))
|
||||
// failed to decrypt
|
||||
if (result.Error.Contains("aac bitstream error"))
|
||||
return -99;
|
||||
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
// temp file names for steps 3, 4, 5
|
||||
// temp file names for steps 3, 4, 5
|
||||
string tempChapsGuid { get; } = Guid.NewGuid().ToString().ToUpper().Replace("-", "");
|
||||
string tempChapsPath => Path.Combine(outDir, $"tempChaps_{tempChapsGuid}.mp4");
|
||||
string mp4_file => outputFileWithNewExt(".mp4");
|
||||
|
||||
BIN
AaxDecrypter/DecryptLib/avcodec-58.dll
Normal file
BIN
AaxDecrypter/DecryptLib/avcodec-58.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
AaxDecrypter/DecryptLib/avdevice-58.dll
Normal file
BIN
AaxDecrypter/DecryptLib/avdevice-58.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
AaxDecrypter/DecryptLib/avformat-58.dll
Normal file
BIN
AaxDecrypter/DecryptLib/avformat-58.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
AaxDecrypter/DecryptLib/avutil-56.dll
Normal file
BIN
AaxDecrypter/DecryptLib/avutil-56.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
AaxDecrypter/DecryptLib/swresample-3.dll
Normal file
BIN
AaxDecrypter/DecryptLib/swresample-3.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
AaxDecrypter/DecryptLib/swscale-5.dll
Normal file
BIN
AaxDecrypter/DecryptLib/swscale-5.dll
Normal file
Binary file not shown.
@ -6,7 +6,7 @@ namespace AaxDecrypter
|
||||
{
|
||||
// OTHER EXTERNAL DEPENDENCIES
|
||||
// ffprobe has these pre-req.s as I'm using it:
|
||||
// avcodec-57.dll, avdevice-57.dll, avfilter-6.dll, avformat-57.dll, avutil-55.dll, postproc-54.dll, swresample-2.dll, swscale-4.dll, taglib-sharp.dll
|
||||
// avcodec-58.dll, avdevice-58.dll, avfilter-7.dll, avformat-58.dll, avutil-56.dll, postproc-54.dll, swresample-3.dll, swscale-5.dll, taglib-sharp.dll
|
||||
//
|
||||
// something else needs the cygwin files (cyg*.dll)
|
||||
|
||||
@ -16,6 +16,5 @@ namespace AaxDecrypter
|
||||
public static string ffmpegPath { get; } = Path.Combine(decryptLib_, "ffmpeg.exe");
|
||||
public static string ffprobePath { get; } = Path.Combine(decryptLib_, "ffprobe.exe");
|
||||
public static string atomicParsleyPath { get; } = Path.Combine(decryptLib_, "AtomicParsley.exe");
|
||||
public static string mp4trackdumpPath { get; } = Path.Combine(decryptLib_, "mp4trackdump.exe");
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,11 +119,7 @@ namespace FileLiberator
|
||||
{
|
||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||
|
||||
var account = persister
|
||||
.AccountsSettings
|
||||
.GetAccount(libraryBook.Account, libraryBook.Book.Locale);
|
||||
|
||||
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, account.DecryptKey, api.GetActivationBytesAsync, chapters);
|
||||
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, libraryBook.Book.AudibleKey, libraryBook.Book.AudibleIV, chapters);
|
||||
converter.AppName = "Libation";
|
||||
|
||||
TitleDiscovered?.Invoke(this, converter.tags.title);
|
||||
@ -143,8 +139,6 @@ namespace FileLiberator
|
||||
if (!success)
|
||||
return null;
|
||||
|
||||
account.DecryptKey = converter.decryptKey;
|
||||
|
||||
return converter.outputFileName;
|
||||
}
|
||||
finally
|
||||
|
||||
@ -6,7 +6,8 @@ using DataLayer;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.ErrorHandling;
|
||||
using FileManager;
|
||||
using InternalUtilities;
|
||||
using System.Net.Http;
|
||||
using Dinah.Core.Net.Http;
|
||||
|
||||
namespace FileLiberator
|
||||
{
|
||||
@ -29,7 +30,7 @@ namespace FileLiberator
|
||||
public override async Task<StatusHandler> ProcessItemAsync(LibraryBook libraryBook)
|
||||
{
|
||||
var tempAaxFilename = getDownloadPath(libraryBook);
|
||||
var actualFilePath = await downloadBookAsync(libraryBook, tempAaxFilename);
|
||||
var actualFilePath = await downloadAacxBookAsync(libraryBook, tempAaxFilename);
|
||||
moveBook(libraryBook, actualFilePath);
|
||||
return verifyDownload(libraryBook);
|
||||
}
|
||||
@ -40,7 +41,53 @@ namespace FileLiberator
|
||||
libraryBook.Book.Title,
|
||||
"aax",
|
||||
libraryBook.Book.AudibleProductId);
|
||||
private async Task<string> downloadAacxBookAsync(LibraryBook libraryBook, string tempAaxFilename)
|
||||
{
|
||||
validate(libraryBook);
|
||||
|
||||
var api = await GetApiAsync(libraryBook);
|
||||
|
||||
var dlLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
||||
|
||||
libraryBook.Book.AudibleKey = dlLic.AudibleKey;
|
||||
libraryBook.Book.AudibleIV = dlLic.AudibleIV;
|
||||
|
||||
var client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", Resources.UserAgent);
|
||||
|
||||
var actualFilePath = await PerformDownloadAsync(
|
||||
tempAaxFilename,
|
||||
(p) => client.DownloadFileAsync(dlLic.DownloadUri.AbsoluteUri, tempAaxFilename, p));
|
||||
|
||||
System.Threading.Thread.Sleep(100);
|
||||
// if bad file download, a 0-33 byte file will be created
|
||||
// if service unavailable, a 52 byte string will be saved as file
|
||||
var length = new FileInfo(actualFilePath).Length;
|
||||
|
||||
if (length > 100)
|
||||
return actualFilePath;
|
||||
|
||||
var contents = File.ReadAllText(actualFilePath);
|
||||
File.Delete(actualFilePath);
|
||||
|
||||
var exMsg = contents.StartsWithInsensitive(SERVICE_UNAVAILABLE)
|
||||
? SERVICE_UNAVAILABLE
|
||||
: "Error downloading file";
|
||||
|
||||
var ex = new Exception(exMsg);
|
||||
Serilog.Log.Logger.Error(ex, "Download error {@DebugInfo}", new
|
||||
{
|
||||
libraryBook.Book.Title,
|
||||
libraryBook.Book.AudibleProductId,
|
||||
libraryBook.Book.Locale,
|
||||
Account = libraryBook.Account?.ToMask() ?? "[empty]",
|
||||
tempAaxFilename,
|
||||
actualFilePath,
|
||||
length,
|
||||
contents
|
||||
});
|
||||
throw ex;
|
||||
}
|
||||
private async Task<string> downloadBookAsync(LibraryBook libraryBook, string tempAaxFilename)
|
||||
{
|
||||
validate(libraryBook);
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
|
||||
<Version>4.4.0.5</Version>
|
||||
<Version>4.4.0.34</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user