Version 1.0

This commit is contained in:
KrumpetPirate 2015-12-13 16:48:30 -06:00
parent ed281c6336
commit 325ea95ebb
3 changed files with 143 additions and 39 deletions

106
AAXtoMP3.pl Executable file
View File

@ -0,0 +1,106 @@
#!/usr/bin/env perl
use strict;
use warnings;
use v5.22.0;
use autodie;
use Getopt::Long qw/GetOptions/;
Getopt::Long::Configure qw/gnu_getopt/;
use File::Basename qw/fileparse/;
use IO::CaptureOutput qw/capture_exec/;
say "Starting $0...";
my $VERBOSE;
my $AUTHCODE;
my $INPUT_FILE;
my $CHAPTER;
GetOptions(
'auth|a=s' => \$AUTHCODE,
'input|i=s' => \$INPUT_FILE,
'verbose|v' => \$VERBOSE,
'chapter|c' => \$CHAPTER,
) or die "Usage: $0 -verbose -chapter -auth <AUDIBLE AUTH CODE> -input <INPUT FILE PATH>";
die "Usage: $0 -verbose -chapter -auth <AUDIBLE AUTH CODE> -input <INPUT AAX PATH>"
unless ($INPUT_FILE && $AUTHCODE);
die "$INPUT_FILE is not a valid path" unless (-f $INPUT_FILE);
my ($filename, $dir, $extension) = fileparse($INPUT_FILE, qr/\.[^.]*/);
my $ret = system_execute("ffprobe $INPUT_FILE");
my @fflines = split /\n/, $ret;
my $file_type = pull_from_ffprobe("major_brand", @fflines);
my $file_title = pull_from_ffprobe("title", @fflines);
my $file_author = pull_from_ffprobe("artist", @fflines);
my @chapters = grep { m/^\s+Chapter/ } @fflines;
die "Input file ffprobe does not appear to match an AAX file type metadata"
unless $file_type =~ /aax/;
my $output;
if ($file_title && $file_author) {
$output = "$file_title by $file_author";
} else {
$output = $filename;
}
my $output_sh_safe = quotemeta $output;
if (@chapters && $CHAPTER) {
say "Attempting to convert AAX to MP3 by chapter. This will increase the processing time...";
system_execute("mkdir -p $dir$output_sh_safe");
my $chapter_index = 1;
foreach my $chapter (@chapters) {
my ($start, $duration) = extract_ts($chapter);
my $output_fn = quotemeta "$dir$output/$output (Chapter $chapter_index).mp3";
say "Converting Chapter $chapter_index START: $start DURATION: $duration...";
$ret = system_execute("ffmpeg -activation_bytes $AUTHCODE -i $INPUT_FILE -vn -c:a libmp3lame -ab 128k -ss $start -t $duration $output_fn");
$chapter_index++;
say $ret if $VERBOSE;
}
} else {
say "Using Audible auth code to copy AAX audio directly to MP3 format...";
$ret = system_execute("ffmpeg -activation_bytes $AUTHCODE -i $INPUT_FILE -vn -c:a libmp3lame -ab 128k $dir$output_sh_safe.mp3");
say $ret if $VERBOSE;
}
say "End of $0...";
sub system_execute {
my ($stdout, $stderr, $success, $exit_code) = capture_exec(@_);
say "stdout: $stdout\nstderr: $stderr\nsuccess: $success\nexit code: $exit_code" if ($VERBOSE);
if ($success) {
return $stdout if $stdout;
return $stderr if $stderr;
} else {
my $command = join " ", @_;
die "Command $command was not successful, debug.";
}
}
sub extract_ts {
my $line = shift;
$line =~ s/.*://;
$line =~ s/^\s*(.*?)\s*$/$1/;
my @parts = split /\,/, $line;
my $start = $parts[0];
my $end = $parts[1];
$start =~ s/.* //;
$end =~ s/.* //;
my $duration = $end - $start;
return (convert_seconds($start), convert_seconds($duration));
}
sub convert_seconds {
my $sec = shift;
my $time = sprintf "%02d:%02d:%02d.%03d",
(gmtime($sec))[2,1,0, 0 % 1000];
}
sub pull_from_ffprobe {
my $desired = shift;
my @fflines = @_;
return unless ($desired && @fflines);
my ($line) = grep { m/^\s+$desired/ } @fflines;
$line =~ s/^\s*(.*?)\s*$/$1/;
$line =~ s/.*://;
$line =~ s/^\s*(.*?)\s*$/$1/;
return $line;
}

View File

@ -1,37 +0,0 @@
#!/usr/bin/python3
import sys
import getopt
import shutil
def usage():
print('Usage: '+sys.argv[0]+' -a <AMAZON AUTH STRING> -f <AAX FILE>')
def main(argv):
try:
opts, args = getopt.getopt(sys.argv[1:], 'a:f:h', ['auth=', 'file=', 'help'])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
sys.exit(2)
elif opt in ('-a', '--auth'):
auth_string = arg
elif opt in ('-f', '--file'):
input_file = arg
else:
usage()
sys.exit(2)
if not auth_string:
usage()
sys.exit(2)
if not input_file:
usage()
sys.exit(2)
print(auth_string)
print(input_file)
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -1,5 +1,6 @@
# AAXtoMP3 # AAXtoMP3
The purpose of this software is to convert AAX files to a more common MP3 format. The purpose of this software is to convert AAX files to a more common MP3 format
through a basic perl script frontend to FFMPEG.
Audible uses this file format to maintain DRM restrictions on their audio Audible uses this file format to maintain DRM restrictions on their audio
books and if you download your book through your library it will be books and if you download your book through your library it will be
@ -16,8 +17,42 @@ You will need your four byte authitication code that comes from Audible's
servers. This will be used by ffmpeg to perform the initial audio convert. You servers. This will be used by ffmpeg to perform the initial audio convert. You
can obtain this string from a tool like [audible-activator](https://github.com/inAudible-NG/audible-activator). can obtain this string from a tool like [audible-activator](https://github.com/inAudible-NG/audible-activator).
## Anti-Piracy Notice ## Requirements
* perl version 5.22.0 or later
* ffmpeg version 2.8.3 or later
You will also require the following perl modules:
* autodie
* Getopt::Long
* File::Basename
* IO::CaptureOutput
I would suggest installing cpanminus either through CPAN or (preferably) through your
distro's repositories. Take note that many perl modules can be packaged in your repos
as well so take a look there before resorting to cpan/cpanminus.
## Usage
```
perl AAXtoMP3.pl -a AUTHCODE -i AAXFILE -v -c
```
* -a: **your** Audible auth code (it won't correctly decode otherwise) (required)
* -i: the input AAX file to be converted (required)
* -v: verbose (optional)
* -c: Convert to chapters based on input file's metadata information
## Known issues
Currently the chapters mode (activated by the -c flag) does not work correctly.
Parsing the metadata works fine but when the timestamps are converted to
HH:MM:SS.xxx format there is some sort of hickup. It could be that Audible has some
delay in the file to prevent this, but starting from Chapter 2 of the book it will
no longer sync. I don't know if I will ever fix this, so avoid using the -c flag for now
to produce one large MP3 file for the audiobook.
Also this was tested on Linux with the above requirements. No effort will be made to
port this work to any other operating system, though it may work fine. Want a Windows/
OSX port? You'll have to fork the work.
## Anti-Piracy Notice
Note that this project does NOT crack the DRM. It simplys allows the user to Note that this project does NOT crack the DRM. It simplys allows the user to
use their own encryption key (fetched from Audible servers) to decrypt the use their own encryption key (fetched from Audible servers) to decrypt the
audiobook in the same manner that the official audiobook playing software does. audiobook in the same manner that the official audiobook playing software does.