Merge pull request #27 from Mbucari/master

Add support for AXXC
This commit is contained in:
rmcrackan 2021-06-21 14:01:02 -04:00 committed by GitHub
commit c1f50a184a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 536 additions and 94 deletions

View File

@ -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">

View File

@ -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;

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.

View File

@ -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");
} }
} }

View File

@ -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; }

View 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
}
}
}

View 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");
}
}
}

View File

@ -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
} }

View File

@ -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

View File

@ -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

View File

@ -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>