commit
c1f50a184a
@ -18,37 +18,19 @@
|
|||||||
<None Update="DecryptLib\AtomicParsley.exe">
|
<None Update="DecryptLib\AtomicParsley.exe">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\avcodec-57.dll">
|
<None Update="DecryptLib\avcodec-58.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\avdevice-57.dll">
|
<None Update="DecryptLib\avdevice-58.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\avfilter-6.dll">
|
<None Update="DecryptLib\avfilter-7.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\avformat-57.dll">
|
<None Update="DecryptLib\avformat-58.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</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">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\cyggcc_s-1.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\cygmp4v2-2.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\cygstdc++-6.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\cygwin1.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\cygz.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\ffmpeg.exe">
|
<None Update="DecryptLib\ffmpeg.exe">
|
||||||
@ -57,16 +39,13 @@
|
|||||||
<None Update="DecryptLib\ffprobe.exe">
|
<None Update="DecryptLib\ffprobe.exe">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\mp4trackdump.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\postproc-54.dll">
|
<None Update="DecryptLib\postproc-54.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\swresample-2.dll">
|
<None Update="DecryptLib\swresample-3.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\swscale-4.dll">
|
<None Update="DecryptLib\swscale-5.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\taglib-sharp.dll">
|
<None Update="DecryptLib\taglib-sharp.dll">
|
||||||
|
|||||||
@ -48,7 +48,8 @@ namespace AaxDecrypter
|
|||||||
public event EventHandler<int> DecryptProgressUpdate;
|
public event EventHandler<int> DecryptProgressUpdate;
|
||||||
|
|
||||||
public string inputFileName { get; }
|
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; }
|
private StepSequence steps { get; }
|
||||||
public byte[] coverBytes { get; private set; }
|
public byte[] coverBytes { get; private set; }
|
||||||
@ -62,20 +63,21 @@ namespace AaxDecrypter
|
|||||||
public Tags tags { get; private set; }
|
public Tags tags { get; private set; }
|
||||||
public EncodingInfo encodingInfo { get; private set; }
|
public EncodingInfo encodingInfo { get; private set; }
|
||||||
|
|
||||||
private Func<Task<string>> getKeyFuncAsync { get; }
|
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string audible_key, string audible_iv, Chapters chapters = null)
|
||||||
|
|
||||||
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string decryptKey, Func<Task<string>> getKeyFunc, 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);
|
converter.chapters = chapters ?? new AAXChapters(inputFile);
|
||||||
await converter.prelimProcessing();
|
await converter.prelimProcessing();
|
||||||
converter.printPrelim();
|
converter.printPrelim();
|
||||||
|
|
||||||
return converter;
|
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))
|
if (!File.Exists(inputFile))
|
||||||
throw new ArgumentNullException(nameof(inputFile), "File does not exist");
|
throw new ArgumentNullException(nameof(inputFile), "File does not exist");
|
||||||
|
|
||||||
@ -94,8 +96,8 @@ namespace AaxDecrypter
|
|||||||
};
|
};
|
||||||
|
|
||||||
inputFileName = inputFile;
|
inputFileName = inputFile;
|
||||||
this.decryptKey = decryptKey;
|
this.audible_key = audible_key;
|
||||||
this.getKeyFuncAsync = getKeyFunc;
|
this.audible_iv = audible_iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task prelimProcessing()
|
private async Task prelimProcessing()
|
||||||
@ -171,27 +173,16 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
DecryptProgressUpdate?.Invoke(this, 0);
|
DecryptProgressUpdate?.Invoke(this, 0);
|
||||||
|
|
||||||
var tempRipFile = Path.Combine(outDir, "funny.aac");
|
var tempRipFile = Path.Combine(outDir, "funny.mp4");
|
||||||
|
|
||||||
var fail = "WARNING-Decrypt failure. ";
|
var fail = "WARNING-Decrypt failure. ";
|
||||||
|
|
||||||
int returnCode;
|
int returnCode;
|
||||||
if (string.IsNullOrWhiteSpace(decryptKey))
|
|
||||||
{
|
|
||||||
returnCode = getKey_decrypt(tempRipFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
returnCode = decrypt(tempRipFile);
|
returnCode = decrypt(tempRipFile);
|
||||||
if (returnCode == -99)
|
if (returnCode == -99)
|
||||||
{
|
Console.WriteLine($"{fail}Incorrect decrypt key.");
|
||||||
Console.WriteLine($"{fail}Incorrect decrypt key: {decryptKey}");
|
else if (returnCode == 100)
|
||||||
decryptKey = null;
|
|
||||||
returnCode = getKey_decrypt(tempRipFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnCode == 100)
|
|
||||||
Console.WriteLine($"{fail}Thread completed without changing return code. This shouldn't be possible");
|
Console.WriteLine($"{fail}Thread completed without changing return code. This shouldn't be possible");
|
||||||
else if (returnCode == 0)
|
else if (returnCode == 0)
|
||||||
{
|
{
|
||||||
@ -200,8 +191,6 @@ namespace AaxDecrypter
|
|||||||
DecryptProgressUpdate?.Invoke(this, 100);
|
DecryptProgressUpdate?.Invoke(this, 100);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (returnCode == -99)
|
|
||||||
Console.WriteLine($"{fail}Incorrect decrypt key: {decryptKey}");
|
|
||||||
else // any other returnCode
|
else // any other returnCode
|
||||||
Console.WriteLine($"{fail}Unknown failure code: {returnCode}");
|
Console.WriteLine($"{fail}Unknown failure code: {returnCode}");
|
||||||
|
|
||||||
@ -210,24 +199,16 @@ namespace AaxDecrypter
|
|||||||
return false;
|
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)
|
private int decrypt(string tempRipFile)
|
||||||
{
|
{
|
||||||
FileExt.SafeDelete(tempRipFile);
|
FileExt.SafeDelete(tempRipFile);
|
||||||
|
|
||||||
Console.WriteLine("Decrypting with key " + decryptKey);
|
Console.WriteLine($"Decrypting with key={audible_key}, iv={audible_iv}");
|
||||||
|
|
||||||
var returnCode = 100;
|
var returnCode = 100;
|
||||||
var thread = new Thread(() => returnCode = ngDecrypt());
|
var thread = new Thread((b) => returnCode = ngDecrypt(b));
|
||||||
thread.Start();
|
thread.Start(tempRipFile);
|
||||||
|
|
||||||
double fileLen = new FileInfo(inputFileName).Length;
|
double fileLen = new FileInfo(inputFileName).Length;
|
||||||
while (thread.IsAlive && returnCode == 100)
|
while (thread.IsAlive && returnCode == 100)
|
||||||
@ -244,19 +225,29 @@ namespace AaxDecrypter
|
|||||||
return returnCode;
|
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
|
var info = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = DecryptSupportLibraries.mp4trackdumpPath,
|
FileName = DecryptSupportLibraries.ffmpegPath,
|
||||||
Arguments = "-c " + encodingInfo.channels + " -r " + encodingInfo.sampleRate + " \"" + inputFileName + "\""
|
Arguments = args
|
||||||
};
|
};
|
||||||
info.EnvironmentVariables["VARIABLE"] = decryptKey;
|
|
||||||
|
|
||||||
var result = info.RunHidden();
|
var result = info.RunHidden();
|
||||||
|
|
||||||
// bad checksum -- bad decrypt key
|
// failed to decrypt
|
||||||
if (result.Output.Contains("checksums mismatch, aborting!"))
|
if (result.Error.Contains("aac bitstream error"))
|
||||||
return -99;
|
return -99;
|
||||||
|
|
||||||
return result.ExitCode;
|
return result.ExitCode;
|
||||||
|
|||||||
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
|
// OTHER EXTERNAL DEPENDENCIES
|
||||||
// ffprobe has these pre-req.s as I'm using it:
|
// 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)
|
// 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 ffmpegPath { get; } = Path.Combine(decryptLib_, "ffmpeg.exe");
|
||||||
public static string ffprobePath { get; } = Path.Combine(decryptLib_, "ffprobe.exe");
|
public static string ffprobePath { get; } = Path.Combine(decryptLib_, "ffprobe.exe");
|
||||||
public static string atomicParsleyPath { get; } = Path.Combine(decryptLib_, "AtomicParsley.exe");
|
public static string atomicParsleyPath { get; } = Path.Combine(decryptLib_, "AtomicParsley.exe");
|
||||||
public static string mp4trackdumpPath { get; } = Path.Combine(decryptLib_, "mp4trackdump.exe");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,8 @@ namespace DataLayer
|
|||||||
|
|
||||||
// mutable
|
// mutable
|
||||||
public string PictureId { get; set; }
|
public string PictureId { get; set; }
|
||||||
|
public string AudibleKey { get; set; }
|
||||||
|
public string AudibleIV { get; set; }
|
||||||
|
|
||||||
// book details
|
// book details
|
||||||
public bool IsAbridged { get; private set; }
|
public bool IsAbridged { get; private set; }
|
||||||
|
|||||||
387
DataLayer/Migrations/20210619030017_AddAaxcDecryptionKeys.Designer.cs
generated
Normal file
387
DataLayer/Migrations/20210619030017_AddAaxcDecryptionKeys.Designer.cs
generated
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using DataLayer;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace DataLayer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LibationContext))]
|
||||||
|
[Migration("20210619030017_AddAaxcDecryptionKeys")]
|
||||||
|
partial class AddAaxcDecryptionKeys
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "5.0.5");
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Book", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("BookId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleIV")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleProductId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DatePublished")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAbridged")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LengthInMinutes")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Locale")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PictureId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("BookId");
|
||||||
|
|
||||||
|
b.HasIndex("AudibleProductId");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Books");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.BookContributor", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ContributorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Role")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<byte>("Order")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("BookId", "ContributorId", "Role");
|
||||||
|
|
||||||
|
b.HasIndex("BookId");
|
||||||
|
|
||||||
|
b.HasIndex("ContributorId");
|
||||||
|
|
||||||
|
b.ToTable("BookContributor");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleCategoryId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("ParentCategoryCategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("CategoryId");
|
||||||
|
|
||||||
|
b.HasIndex("AudibleCategoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ParentCategoryCategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
CategoryId = -1,
|
||||||
|
AudibleCategoryId = "",
|
||||||
|
Name = ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Contributor", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ContributorId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleContributorId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("ContributorId");
|
||||||
|
|
||||||
|
b.HasIndex("Name");
|
||||||
|
|
||||||
|
b.ToTable("Contributors");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ContributorId = -1,
|
||||||
|
Name = ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.LibraryBook", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Account")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("BookId");
|
||||||
|
|
||||||
|
b.ToTable("Library");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Series", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SeriesId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleSeriesId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("SeriesId");
|
||||||
|
|
||||||
|
b.HasIndex("AudibleSeriesId");
|
||||||
|
|
||||||
|
b.ToTable("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.SeriesBook", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SeriesId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float?>("Index")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("SeriesId", "BookId");
|
||||||
|
|
||||||
|
b.HasIndex("BookId");
|
||||||
|
|
||||||
|
b.HasIndex("SeriesId");
|
||||||
|
|
||||||
|
b.ToTable("SeriesBook");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Book", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DataLayer.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.OwnsOne("DataLayer.Rating", "Rating", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.Property<float>("OverallRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b1.Property<float>("PerformanceRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b1.Property<float>("StoryRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b1.HasKey("BookId");
|
||||||
|
|
||||||
|
b1.ToTable("Books");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("BookId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.OwnsMany("DataLayer.Supplement", "Supplements", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<int>("SupplementId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.Property<string>("Url")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.HasKey("SupplementId");
|
||||||
|
|
||||||
|
b1.HasIndex("BookId");
|
||||||
|
|
||||||
|
b1.ToTable("Supplement");
|
||||||
|
|
||||||
|
b1.WithOwner("Book")
|
||||||
|
.HasForeignKey("BookId");
|
||||||
|
|
||||||
|
b1.Navigation("Book");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.OwnsOne("DataLayer.UserDefinedItem", "UserDefinedItem", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<int>("BookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.Property<string>("Tags")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.HasKey("BookId");
|
||||||
|
|
||||||
|
b1.ToTable("UserDefinedItem");
|
||||||
|
|
||||||
|
b1.WithOwner("Book")
|
||||||
|
.HasForeignKey("BookId");
|
||||||
|
|
||||||
|
b1.OwnsOne("DataLayer.Rating", "Rating", b2 =>
|
||||||
|
{
|
||||||
|
b2.Property<int>("UserDefinedItemBookId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b2.Property<float>("OverallRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b2.Property<float>("PerformanceRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b2.Property<float>("StoryRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b2.HasKey("UserDefinedItemBookId");
|
||||||
|
|
||||||
|
b2.ToTable("UserDefinedItem");
|
||||||
|
|
||||||
|
b2.WithOwner()
|
||||||
|
.HasForeignKey("UserDefinedItemBookId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b1.Navigation("Book");
|
||||||
|
|
||||||
|
b1.Navigation("Rating");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
|
||||||
|
b.Navigation("Rating");
|
||||||
|
|
||||||
|
b.Navigation("Supplements");
|
||||||
|
|
||||||
|
b.Navigation("UserDefinedItem");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.BookContributor", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DataLayer.Book", "Book")
|
||||||
|
.WithMany("ContributorsLink")
|
||||||
|
.HasForeignKey("BookId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("DataLayer.Contributor", "Contributor")
|
||||||
|
.WithMany("BooksLink")
|
||||||
|
.HasForeignKey("ContributorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
|
|
||||||
|
b.Navigation("Contributor");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Category", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DataLayer.Category", "ParentCategory")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ParentCategoryCategoryId");
|
||||||
|
|
||||||
|
b.Navigation("ParentCategory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.LibraryBook", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DataLayer.Book", "Book")
|
||||||
|
.WithOne()
|
||||||
|
.HasForeignKey("DataLayer.LibraryBook", "BookId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.SeriesBook", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DataLayer.Book", "Book")
|
||||||
|
.WithMany("SeriesLink")
|
||||||
|
.HasForeignKey("BookId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("DataLayer.Series", "Series")
|
||||||
|
.WithMany("BooksLink")
|
||||||
|
.HasForeignKey("SeriesId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
|
|
||||||
|
b.Navigation("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Book", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContributorsLink");
|
||||||
|
|
||||||
|
b.Navigation("SeriesLink");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Contributor", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("BooksLink");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Series", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("BooksLink");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
DataLayer/Migrations/20210619030017_AddAaxcDecryptionKeys.cs
Normal file
33
DataLayer/Migrations/20210619030017_AddAaxcDecryptionKeys.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace DataLayer.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddAaxcDecryptionKeys : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "AudibleIV",
|
||||||
|
table: "Books",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "AudibleKey",
|
||||||
|
table: "Books",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AudibleIV",
|
||||||
|
table: "Books");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AudibleKey",
|
||||||
|
table: "Books");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ namespace DataLayer.Migrations
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "3.1.7");
|
.HasAnnotation("ProductVersion", "5.0.5");
|
||||||
|
|
||||||
modelBuilder.Entity("DataLayer.Book", b =>
|
modelBuilder.Entity("DataLayer.Book", b =>
|
||||||
{
|
{
|
||||||
@ -22,6 +22,12 @@ namespace DataLayer.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleIV")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("AudibleKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("AudibleProductId")
|
b.Property<string>("AudibleProductId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
@ -244,6 +250,8 @@ namespace DataLayer.Migrations
|
|||||||
|
|
||||||
b1.WithOwner("Book")
|
b1.WithOwner("Book")
|
||||||
.HasForeignKey("BookId");
|
.HasForeignKey("BookId");
|
||||||
|
|
||||||
|
b1.Navigation("Book");
|
||||||
});
|
});
|
||||||
|
|
||||||
b.OwnsOne("DataLayer.UserDefinedItem", "UserDefinedItem", b1 =>
|
b.OwnsOne("DataLayer.UserDefinedItem", "UserDefinedItem", b1 =>
|
||||||
@ -282,7 +290,19 @@ namespace DataLayer.Migrations
|
|||||||
b2.WithOwner()
|
b2.WithOwner()
|
||||||
.HasForeignKey("UserDefinedItemBookId");
|
.HasForeignKey("UserDefinedItemBookId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
b1.Navigation("Book");
|
||||||
|
|
||||||
|
b1.Navigation("Rating");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
|
||||||
|
b.Navigation("Rating");
|
||||||
|
|
||||||
|
b.Navigation("Supplements");
|
||||||
|
|
||||||
|
b.Navigation("UserDefinedItem");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DataLayer.BookContributor", b =>
|
modelBuilder.Entity("DataLayer.BookContributor", b =>
|
||||||
@ -298,6 +318,10 @@ namespace DataLayer.Migrations
|
|||||||
.HasForeignKey("ContributorId")
|
.HasForeignKey("ContributorId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
|
|
||||||
|
b.Navigation("Contributor");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DataLayer.Category", b =>
|
modelBuilder.Entity("DataLayer.Category", b =>
|
||||||
@ -305,6 +329,8 @@ namespace DataLayer.Migrations
|
|||||||
b.HasOne("DataLayer.Category", "ParentCategory")
|
b.HasOne("DataLayer.Category", "ParentCategory")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ParentCategoryCategoryId");
|
.HasForeignKey("ParentCategoryCategoryId");
|
||||||
|
|
||||||
|
b.Navigation("ParentCategory");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DataLayer.LibraryBook", b =>
|
modelBuilder.Entity("DataLayer.LibraryBook", b =>
|
||||||
@ -314,6 +340,8 @@ namespace DataLayer.Migrations
|
|||||||
.HasForeignKey("DataLayer.LibraryBook", "BookId")
|
.HasForeignKey("DataLayer.LibraryBook", "BookId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DataLayer.SeriesBook", b =>
|
modelBuilder.Entity("DataLayer.SeriesBook", b =>
|
||||||
@ -329,6 +357,27 @@ namespace DataLayer.Migrations
|
|||||||
.HasForeignKey("SeriesId")
|
.HasForeignKey("SeriesId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Book");
|
||||||
|
|
||||||
|
b.Navigation("Series");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Book", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContributorsLink");
|
||||||
|
|
||||||
|
b.Navigation("SeriesLink");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Contributor", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("BooksLink");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DataLayer.Series", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("BooksLink");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,11 +119,7 @@ namespace FileLiberator
|
|||||||
{
|
{
|
||||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||||
|
|
||||||
var account = persister
|
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, libraryBook.Book.AudibleKey, libraryBook.Book.AudibleIV, chapters);
|
||||||
.AccountsSettings
|
|
||||||
.GetAccount(libraryBook.Account, libraryBook.Book.Locale);
|
|
||||||
|
|
||||||
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, account.DecryptKey, api.GetActivationBytesAsync, chapters);
|
|
||||||
converter.AppName = "Libation";
|
converter.AppName = "Libation";
|
||||||
|
|
||||||
TitleDiscovered?.Invoke(this, converter.tags.title);
|
TitleDiscovered?.Invoke(this, converter.tags.title);
|
||||||
@ -143,8 +139,6 @@ namespace FileLiberator
|
|||||||
if (!success)
|
if (!success)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
account.DecryptKey = converter.decryptKey;
|
|
||||||
|
|
||||||
return converter.outputFileName;
|
return converter.outputFileName;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@ -6,7 +6,8 @@ using DataLayer;
|
|||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.ErrorHandling;
|
using Dinah.Core.ErrorHandling;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
using InternalUtilities;
|
using System.Net.Http;
|
||||||
|
using Dinah.Core.Net.Http;
|
||||||
|
|
||||||
namespace FileLiberator
|
namespace FileLiberator
|
||||||
{
|
{
|
||||||
@ -29,7 +30,7 @@ namespace FileLiberator
|
|||||||
public override async Task<StatusHandler> ProcessItemAsync(LibraryBook libraryBook)
|
public override async Task<StatusHandler> ProcessItemAsync(LibraryBook libraryBook)
|
||||||
{
|
{
|
||||||
var tempAaxFilename = getDownloadPath(libraryBook);
|
var tempAaxFilename = getDownloadPath(libraryBook);
|
||||||
var actualFilePath = await downloadBookAsync(libraryBook, tempAaxFilename);
|
var actualFilePath = await downloadAaxcBookAsync(libraryBook, tempAaxFilename);
|
||||||
moveBook(libraryBook, actualFilePath);
|
moveBook(libraryBook, actualFilePath);
|
||||||
return verifyDownload(libraryBook);
|
return verifyDownload(libraryBook);
|
||||||
}
|
}
|
||||||
@ -40,16 +41,23 @@ namespace FileLiberator
|
|||||||
libraryBook.Book.Title,
|
libraryBook.Book.Title,
|
||||||
"aax",
|
"aax",
|
||||||
libraryBook.Book.AudibleProductId);
|
libraryBook.Book.AudibleProductId);
|
||||||
|
private async Task<string> downloadAaxcBookAsync(LibraryBook libraryBook, string tempAaxFilename)
|
||||||
private async Task<string> downloadBookAsync(LibraryBook libraryBook, string tempAaxFilename)
|
|
||||||
{
|
{
|
||||||
validate(libraryBook);
|
validate(libraryBook);
|
||||||
|
|
||||||
var api = await GetApiAsync(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(
|
var actualFilePath = await PerformDownloadAsync(
|
||||||
tempAaxFilename,
|
tempAaxFilename,
|
||||||
(p) => api.DownloadAaxWorkaroundAsync(libraryBook.Book.AudibleProductId, tempAaxFilename, p));
|
(p) => client.DownloadFileAsync(dlLic.DownloadUri.AbsoluteUri, tempAaxFilename, p));
|
||||||
|
|
||||||
System.Threading.Thread.Sleep(100);
|
System.Threading.Thread.Sleep(100);
|
||||||
// if bad file download, a 0-33 byte file will be created
|
// if bad file download, a 0-33 byte file will be created
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
<Version>4.4.0.5</Version>
|
<Version>4.4.0.34</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user