58 Commits
v1.2 ... v1.3

Author SHA1 Message Date
5ea4bd10a4 Update for GNU find, README cleanup 2021-09-03 13:25:30 -04:00
596108d56e Merge pull request #171 from fabh2o/aaxc
AAXC support, audible-cli integration
2021-09-03 10:08:27 -04:00
63ffc47aa5 use the var $decrypt_param with all ffmpeg and ffprobe call 2021-09-02 20:11:12 +02:00
b7fbe831c7 invert authcode required 2021-09-02 19:59:37 +02:00
1663daebdc add jq as dependency 2021-09-02 19:57:54 +02:00
78d6e931ff docs about aaxc 2021-09-02 19:35:14 +02:00
9e2d84cb25 updated docs to automatic source file format switch 2021-09-02 19:21:41 +02:00
b78e4b59b9 auto format selection, fix typo 2021-09-02 19:13:02 +02:00
99864fe428 docs 2021-09-02 18:24:57 +02:00
e9b111aa8a fully support aaxc 2021-09-02 17:49:36 +02:00
3d062fdba7 --aaxc flag, validate voucher and get key and id 2021-09-02 16:16:14 +02:00
eff626ee95 move info after req 2021-07-10 21:20:43 +02:00
64713e23ea Merge branch 'master' of github.com:fabh2o/AAXtoMP3 into all-in-one 2021-07-09 22:45:04 +02:00
0f2180da3c Merge pull request #162 from Nicko98/master
Call AAXtoMP3 interactively
2021-03-09 17:38:10 -05:00
051f37b3ff Made savefile invisible 2021-03-09 22:49:54 +01:00
2206cf9dd8 Updated Readme.md 2021-03-09 22:44:26 +01:00
88c9b1701f Save chosen options for next time
Now this script creates a save-file from which it loads the option the next time the script is used
Additionally aax-File drag'n'drop works now, at least on Ubuntu.
2021-03-09 22:26:48 +01:00
c6c5b5ee97 Merge pull request #157 from katyavera/patch-1
Use the current filename scheme
2021-03-02 08:56:21 -05:00
1d225d7fe2 Merge pull request #158 from katyavera/patch-2
Allow spaces in the .aax filename
2021-03-02 08:55:43 -05:00
d0a9ba392c Merge pull request #161 from katyavera/patch-3
Fix typo, reword
2021-03-02 08:54:56 -05:00
4537c7d01d Just a little correction regarding sed 2021-03-02 01:51:12 +01:00
4dfb59e091 Updated README.md 2021-03-02 01:28:47 +01:00
7f2309248f Some little improvements 2021-03-02 01:06:45 +01:00
4698f7728a Call AAXtoMP3 Interactively
This script interactively asks you for the options to call AAXtoMP3 with.
2021-03-01 04:31:39 +01:00
951146022f Fix typo, reword 2021-02-28 18:36:01 +01:00
f9b855ea1d Allow spaces in the .aax filename 2021-02-28 15:29:02 +01:00
2aa1d05040 Use the current filename scheme
The `fileNameScheme` is empty by default, so the file generated is named only `.chapters.txt` if -F is not specified.
Provided with the filename `mp4file`, mp4chaps searches for a file named `<mp4file>.chapters.txt`.
2021-02-28 15:25:40 +01:00
7310e16222 Merge pull request #156 from Nicko98/master
Fix for issue KrumpetPirate#155
2021-02-25 22:03:22 -05:00
a68353f4eb Fix for issue KrumpetPirate#155 2021-02-25 23:21:29 +01:00
af880305dd Merge branch 'custom-output-folder' of github.com:fabh2o/AAXtoMP3 into all-in-one 2021-02-11 11:11:58 +01:00
ab5d7c7f7c Merge branch 'posix-filenames' of github.com:fabh2o/AAXtoMP3 into all-in-one 2021-02-11 10:47:44 +01:00
96d9d4aa9d Merge branch 'fix-log-level-time-as-octal' of github.com:fabh2o/AAXtoMP3 into audible-cli-integration 2021-02-11 10:38:54 +01:00
cb17d422f3 Merge branch 'master' of github.com:KrumpetPirate/AAXtoMP3 into audible-cli-integration 2021-02-11 10:38:20 +01:00
afb852fdf1 cut title to 128 char + no - or : subsitution 2021-02-07 16:51:51 +01:00
d199d875bb Debugvar chapter, restored chapter number format 2021-02-07 10:26:29 +01:00
1afa763999 restored default output dir struct 2021-02-07 10:20:06 +01:00
45bd9e666f remove all apprnd-narrator traces 2021-02-07 10:15:34 +01:00
c45a4ac610 reformat usage + auduble-cli flag 2021-02-06 19:06:56 +01:00
0972886b58 Merge branch 'append-narrator' of github.com:fabh2o/AAXtoMP3 into audible-cli-integration 2021-02-06 18:51:01 +01:00
822f5c3409 forgot to update help message 2021-02-06 18:38:03 +01:00
b8bef58122 fix indentation 2021-02-06 18:34:09 +01:00
f98ded7ca7 debugvar audibleCli 2021-02-06 18:27:13 +01:00
60b762bb29 append narrator name to the output folder 2021-02-06 18:26:14 +01:00
3c1f3692d4 Merge branch 'master' of github.com:KrumpetPirate/AAXtoMP3 into audible-cli-integration 2021-02-06 13:03:31 +01:00
f74ec2e75a removed Audiobook (genre) dir from the output 2021-02-05 21:00:39 +01:00
f94cf1baa7 fix for find command: use basename 2021-02-05 16:53:43 +01:00
7aa50019a8 textwidth 80, note about dev stage of the a-cli package, rewrote file requirement 2021-02-05 16:10:38 +01:00
1f0b44d455 Merge branch 'master' of github.com:KrumpetPirate/AAXtoMP3 into audible-cli-integration 2021-02-05 15:38:35 +01:00
9ea5bf0899 restore ffmpeg to be silent 2021-02-05 15:33:07 +01:00
047d7eb6f3 validate_extra_files final touchs, mediainfo get only useful infos,
save chapter infos from audible-cli json, publisher tag,
cover crop, real track title
2021-02-05 10:22:12 +01:00
5f390b4f59 Merge branch 'master' of github.com:fabh2o/AAXtoMP3 into audible-cli-integration 2021-02-04 14:27:54 +01:00
b7e978c8bb better HQ cover processing 2021-02-04 13:45:42 +01:00
d0b5bda46d fixed anchor 2021-02-04 13:39:20 +01:00
6171eab4f1 description of flag in options 2021-02-04 13:36:40 +01:00
bcfdf0ac06 ignore jpg (cover) and json (chapters) files 2021-02-04 10:21:58 +01:00
02e1132301 validate files 2021-02-04 09:59:19 +01:00
eceb4e2f09 flag 2021-02-03 16:47:19 +01:00
4080018295 Info about audible.cli integration 2021-02-03 16:44:47 +01:00
4 changed files with 395 additions and 52 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
ACTIVATION
.authcode
*aax
*jpg
*json
Audiobook/*

202
AAXtoMP3
View File

@ -9,7 +9,7 @@ usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level <COMPRE
[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode <AUTHCODE>] [--no-clobber]
[--target_dir <PATH>] [--complete_dir <PATH>] [--validate] [--loglevel <LOGLEVEL>]
[--keep-author <N>] [--author <AUTHOR>] [--{dir,file,chapter}-naming-scheme <STRING>]
[--continue <CHAPTERNUMBER>] {FILES}\n'
[--use-audible-cli-data] [--continue <CHAPTERNUMBER>] {FILES}\n'
codec=libmp3lame # Default encoder.
extension=mp3 # Default encoder extension.
level=-1 # Compression level. Can be given for mp3, flac and opus. -1 = default/not specified.
@ -31,6 +31,9 @@ continue=0 # Default off, If set Transcoding is skipped and cha
continueAt=1 # Optional chapter to continue splitting the chapters.
keepArtist=-1 # Default off, if set change author metadata to use the passed argument as field
authorOverride= # Override the author, ignoring the metadata
audibleCli=0 # Default off, Use additional data gathered from mkb79/audible-cli
aaxc_key= # Initialize variables, in case we need them in debug_vars
aaxc_iv= # Initialize variables, in case we need them in debug_vars
# -----
# Code tip Do not have any script above this point that calls a function or a binary. If you do
@ -77,6 +80,8 @@ while true; do
-V | --validate ) VALIDATE=1; shift ;;
# continue splitting chapters at chapter continueAt
--continue ) continueAt="$2"; continue=1; shift 2 ;;
# Use additional data got with mkb79/audible-cli
--use-audible-cli-data ) audibleCli=1; shift ;;
# Compression level
--level ) level="$2"; shift 2 ;;
# Keep author number n
@ -192,14 +197,24 @@ progressbar() {
echo -ne "Chapter splitting: |$progressbar| $print_percentage% ($part/$total chapters)\r"
}
# Print out what we have already after command line processing.
debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code keepArtist authorOverride
debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code keepArtist authorOverride audibleCli
# ========================================================================
# Variable validation
if [ $(uname) = 'Linux' ]; then
GREP="grep"
FIND="find"
SED="sed"
else
GREP="ggrep"
FIND="gfind"
SED="gsed"
fi
# -----
# Detect which annoying version of grep we have
GREP=$(grep --version | grep -q GNU && echo "grep" || echo "ggrep")
if ! [[ $(type -P "$GREP") ]]; then
echo "$GREP (GNU grep) is not in your PATH"
echo "Without it, this script will break."
@ -207,9 +222,17 @@ if ! [[ $(type -P "$GREP") ]]; then
exit 1
fi
# -----
# Detect which annoying version of find we have
if ! [[ $(type -P "$FIND") ]]; then
echo "$FIND (GNU find) is not in your PATH"
echo "Without it, this script will break."
echo "On macOS, you may want to try: brew install findutils"
exit 1
fi
# -----
# Detect which annoying version of sed we have
SED=$(sed --version 2>&1 | $GREP -q GNU && echo "sed" || echo "gsed")
if ! [[ $(type -P "$SED") ]]; then
echo "$SED (GNU sed) is not in your PATH"
echo "Without it, this script will break."
@ -290,12 +313,6 @@ if [ -z $auth_code ]; then
auth_code=`head -1 ~/.authcode`
fi
fi
# No point going on if no authcode found.
if [ -z $auth_code ]; then
echo "ERROR Missing authcode"
echo "$usage"
exit 1
fi
# -----
# Check the target dir for if set if it is writable
@ -384,8 +401,8 @@ validate_aax() {
# Clear the errexit value we want to capture the output of the ffprobe below.
set +e errexit
# Take a look at the aax file and see if it is valid.
output="$(ffprobe -loglevel warning -activation_bytes ${auth_code} -i "${media_file}" 2>&1)"
# Take a look at the aax file and see if it is valid. If the source file is aaxc, we give ffprobe additional flags
output="$(ffprobe -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)"
# If invalid then say something.
if [[ $? != "0" ]] ; then
@ -398,7 +415,7 @@ validate_aax() {
# This is a big test only performed when the --validate switch is passed.
if [[ "${VALIDATE}" == "1" ]]; then
output="$(ffmpeg -hide_banner -activation_bytes ${auth_code} -i "${media_file}" -vn -f null - 2>&1)"
output="$(ffmpeg -hide_banner ${decrypt_param} -i "${media_file}" -vn -f null - 2>&1)"
if [[ $? != "0" ]] ; then
log "ERROR: Invalid File: ${media_file}"
else
@ -413,6 +430,56 @@ validate_aax() {
set -e errexit
}
validate_extra_files() {
local extra_media_file extra_find_command
extra_media_file="$1"
# Bash trick to delete, non greedy, from the end up until the first '-'
extra_title="${extra_media_file%-*}"
# Using this is not ideal, because if the naming scheme is changed then
# this part of the script will break
# AAX file: BookTitle-LC_128_44100_stereo.aax
# Cover file: BookTitle_(1215).jpg
# Chapter file: BookTitle-chapters.json
# Chapter
extra_chapter_file="${extra_title}-chapters.json"
# Cover
extra_dirname="$(dirname "${extra_media_file}")"
extra_find_command='$FIND "${extra_dirname}" -maxdepth 1 -regex ".*/${extra_title##*/}_([0-9]+)\.jpg"'
# We want the output of the find command, we will turn errexit on later
set +e errexit
extra_cover_file="$(eval ${extra_find_command})"
extra_eval_comm="$(eval echo ${extra_find_command})"
set -e errexit
if [[ "${aaxc}" == "1" ]]; then
# bash trick to get file w\o extention (delete from end to the first '.')
extra_voucher="${extra_media_file%.*}.voucher"
if [[ ! -r "${extra_voucher}" ]] ; then
log "ERROR File NOT Found: ${extra_voucher}"
return 1
fi
aaxc_key=$(jq -r '.content_license.license_response.key' "${extra_voucher}")
aaxc_iv=$(jq -r '.content_license.license_response.iv' "${extra_voucher}")
fi
debug_vars "Audible-cli variables" extra_media_file extra_title extra_chapter_file extra_cover_file extra_find_command extra_eval_comm extra_dirname extra_voucher aaxc_key aaxc_iv
# Test for chapter file existence
if [[ ! -r "${extra_chapter_file}" ]] ; then
log "ERROR File NOT Found: ${extra_chapter_file}"
return 1
fi
if [[ "x${extra_cover_file}" == "x" ]] ; then
log "ERROR Cover File NOT Found"
return 1
fi
debug "All expected audible-cli related file are here"
}
# -----
# Inspect the AAX and extract the metadata associated with the file.
save_metadata() {
@ -432,6 +499,18 @@ save_metadata() {
echo "pub :" "$(mediainfo --Inform="General;%pub%" "$media_file")" >> "$metadata_file"
echo "Mediainfo data END" >> "$metadata_file"
fi
if [[ "${audibleCli}" == "1" ]]; then
# If we use data we got with audible-cli, we delete conflicting chapter infos
$SED -i '/^ Chapter #/d' "${metadata_file}"
# Some magic: we parse the .json generated by audible-cli.
# to get the output structure like the one generated by ffprobe,
# we use some characters (#) as placeholder, add some new lines,
# put a ',' after the start value, we calculate the end of each chapter
# as start+length, and we convert (divide) the time stamps from ms to s.
# Then we delete all ':' since they make a filename invalid.
jq -r '.content_metadata.chapter_info.chapters[] | "Chapter # start: \(.start_offset_ms/1000), end: \((.start_offset_ms+.length_ms)/1000) \n#\n# Title: \(.title)"' "${extra_chapter_file}" \
| tr -d ':' >> "$metadata_file"
fi
debug "Metadata file $metadata_file"
debug_file "$metadata_file"
}
@ -453,15 +532,59 @@ get_bitrate() {
get_metadata_value bitrate | $GREP --only-matching '[0-9]\+'
}
# Save the original value, since in the for loop we overwrite
# $audibleCli in case the file is aaxc. If the file is the
# old aax, reset the variable to be the one passed by the user
originalAudibleCliVar=$audibleCli
# ========================================================================
# Main Transcode Loop
for aax_file
do
# If the file is in aaxc format, set the proper variables
if [[ ${aax_file##*.} == "aaxc" ]]; then
# File is the new .aaxc
aaxc=1
audibleCli=1
else
# File is the old .aax
aaxc=0
# If some previous file in the loop are aaxc, the $audibleCli variable has been overwritten, so we reset it to the original one
audibleCli=$originalAudibleCliVar
fi
debug_vars "Variables set based on file extention" aaxc originalAudibleCliVar audibleCli
# No point going on if no authcode found and the file is aax.
# If we use aaxc as input, we do not need it
# if the string $auth_code is null and the format is not aaxc; quit. We need the authcode
if [ -z $auth_code ] && [ "${aaxc}" = "0" ]; then
echo "ERROR Missing authcode, can't decode $aax_file"
echo "$usage"
exit 1
fi
# Validate the input aax file. Note this happens no matter what.
# It's just that if the validate option is set then we skip to next file.
# If however validate is not set and we proceed with the script any errors will
# case the script to stop.
# If the input file is aaxc, we need to first get the audible_key and audible_iv
# We get them in the function validate_extra_files
if [[ ${audibleCli} == "1" ]] ; then
# If we have additional files (obtained via audible-cli), be sure that they
# exists and they are in the correct location.
validate_extra_files "${aax_file}"
fi
# Set the needed params to decrypt the file. Needed in all command that require ffprobe or ffmpeg
# After validate_extra_files, since the -audible_key and -audible_iv are read in that function
if [[ ${aaxc} == "1" ]] ; then
decrypt_param="-audible_key ${aaxc_key} -audible_iv ${aaxc_iv}"
else
decrypt_param="-activation_bytes ${auth_code}"
fi
validate_aax "${aax_file}"
if [[ ${VALIDATE} == "1" ]] ; then
# Don't bother doing anything else with this file.
@ -488,8 +611,8 @@ do
album_artist="$(get_metadata_value album_artist)"
fi
fi
title=$(get_metadata_value title | $SED 's/'\:'/'-'/g' | $SED 's/- /-/g' | xargs -0)
title=${title:0:100}
title=$(get_metadata_value title)
title=${title:0:128}
bitrate="$(get_bitrate)k"
album="$(get_metadata_value album)"
album_date="$(get_metadata_value date)"
@ -546,11 +669,12 @@ do
# Big long DEBUG output. Fully describes the settings used for transcoding.
# Note this is a long debug command. It's not critical to operation. It's purely for people debugging
# and coders wanting to extend the script.
debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher currentDirNameScheme output_directory currentFileNameScheme output_file metadata_file working_directory
debug_vars "Book and Variable values" title auth_code aaxc aaxc_key aaxc_iv mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher currentDirNameScheme output_directory currentFileNameScheme output_file metadata_file working_directory
# Display the total length of the audiobook in format hh:mm:ss
# 10#$var force base-10 interpretation. By default it's base-8, so values like 08 or 09 are not octal numbers
total_length="$(ffprobe -v error -activation_bytes "${auth_code}" -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 ${aax_file} | cut -d . -f 1)"
total_length="$(ffprobe -v error ${decrypt_param} -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${aax_file}" | cut -d . -f 1)"
hours="$((total_length/3600))"
if [ "$((hours<10))" = "1" ]; then hours="0$hours"; fi
minutes="$((total_length/60-60*10#$hours))"
@ -569,10 +693,10 @@ do
if [ "${continue}" == "0" ]; then
# This is the main work horse command. This is the primary transcoder.
# This is the primary transcode. All the heavy lifting is here.
debug 'ffmpeg -loglevel error -stats -activation_bytes "${auth_code}" -i "${aax_file}" -vn -codec:a "${codec}" -ab ${bitrate} -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="${album_artist}" -metadata album="${album}" -metadata date="${album_date}" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="${copyright}" "${output_file}"'
debug 'ffmpeg -loglevel error -stats ${decrypt_param} -i "${aax_file}" -vn -codec:a "${codec}" -ab ${bitrate} -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="${album_artist}" -metadata album="${album}" -metadata date="${album_date}" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="${copyright}" "${output_file}"'
</dev/null ffmpeg -loglevel error \
-stats \
-activation_bytes "${auth_code}" \
${decrypt_param} \
-i "${aax_file}" \
-vn \
-codec:a "${codec}" \
@ -599,17 +723,32 @@ do
fi
# Grab the cover art if available.
cover_file="${output_directory}/cover.jpg"
extra_crop_cover=''
if [ "${continue}" == "0" ]; then
if [ "$((${loglevel} > 1))" == "1" ]; then
log "Extracting cover into ${cover_file}..."
if [ "${audibleCli}" == "1" ]; then
# We have a better quality cover file, copy it.
if [ "$((${loglevel} > 1))" == "1" ]; then
log "Copy cover file to ${cover_file}..."
fi
cp "${extra_cover_file}" "${cover_file}"
# We now set a variable, ${extra_crop_cover}, which contains an additional
# ffmpeg flag. It crops the cover so the width and the height is divisible by two.
# Since the standard (in the aax file) image resolution is 512, we set the flag
# only if we use a custom cover art.
extra_crop_cover='-vf crop=trunc(iw/2)*2:trunc(ih/2)*2'
else
# Audible-cli not used, extract the cover from the aax file
if [ "$((${loglevel} > 1))" == "1" ]; then
log "Extracting cover into ${cover_file}..."
fi
</dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${aax_file}" -an -codec:v copy "${cover_file}"
fi
</dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${aax_file}" -an -codec:v copy "${cover_file}"
fi
# -----
# OK now spit the file if that's what you want.
# If we want multiple file we take the big mp3 and split it by chapter.
# Not all audio encodings make sense with multiple chapter outputs. See options section
# for more detail
# If mode=chaptered, split the big converted file by chapter and remove it afterwards.
# Not all audio encodings make sense with multiple chapter outputs (see options section)
if [ "${mode}" == "chaptered" ]; then
# Playlist m3u support
playlist_file="${output_directory}/${currentFileNameScheme}.m3u"
@ -684,14 +823,14 @@ do
#ffmpeg version 4+ and on the output for all older versions.
split_input=""
split_output=""
if [ "$(($(ffmpeg -version | head -1 | cut -d \ -f 3 | cut -d . -f 1) > 3))" = "1" ]; then
if [ "$(($(ffmpeg -version | $SED -E 's/[^0-9]*([0-9]).*/\1/g;1q') > 3))" = "1" ]; then
split_input="-ss ${chapter_start%?} -to ${chapter_end}"
else
split_output="-ss ${chapter_start%?} -to ${chapter_end}"
fi
# Big Long chapter debug
debug_vars "Chapter Variables:" cover_file chapter_start chapter_end chapternum chapterNameScheme chapter_title chapter_file
debug_vars "Chapter Variables:" cover_file chapter_start chapter_end chapternum chapter chapterNameScheme chapter_title chapter_file
if [ "$((${continueAt} > ${chapternum}))" = "0" ]; then
# Extract chapter by time stamps start and finish of chapter.
# This extracts based on time stamps start and end.
@ -703,6 +842,7 @@ do
${split_input} \
-i "${output_file}" \
-i "${cover_file}" \
${extra_crop_cover} \
${split_output} \
-map 0:0 \
-map 1:0 \
@ -710,8 +850,8 @@ do
-metadata:s:v title="Album cover" \
-metadata:s:v comment="Cover (Front)" \
-metadata track="${chapternum}" \
-metadata title="${chapter_title}" \
-metadata:s:a title="${chapter_title}" \
-metadata title="${chapter}" \
-metadata:s:a title="${chapter}" \
-metadata:s:a track="${chapternum}" \
-map_chapters -1 \
-f ${container} \
@ -743,7 +883,7 @@ do
# ----
# ffmpeg seems to copy only chapter position, not chapter names.
if [[ ${container} == "mp4" && $(type -P mp4chaps) ]]; then
ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%02d=%02d:%02d:%02.3f\nCHAPTER%02dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${fileNameScheme}.chapters.txt"
ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%02d=%02d:%02d:%02.3f\nCHAPTER%02dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt"
mp4chaps -i "${output_file}"
fi
fi

View File

@ -1,8 +1,8 @@
# AAXtoMP3
The purpose of this software is to convert AAX files to common MP3, M4A, M4B, flac and ogg formats
The purpose of this software is to convert AAX (or AAXC) files to common MP3, M4A, M4B, flac and ogg formats
through a basic bash script frontend to FFMPEG.
Audible uses this file format to maintain DRM restrictions on their audio
Audible uses the AAX file format to maintain DRM restrictions on their audio
books and if you download your book through your library it will be
stored in this format.
@ -13,33 +13,32 @@ create a method for you to download and store your books just in case
Audible fails for some reason.
## Requirements
* bash 4.3.42 or later tested
* ffmpeg version 2.8.3 or later
* libmp3lame (came from lame package on Arch, not sure where else this is stored)
* grep Some OS distributions do not have it installed.
* sed Some OS versions will need to install gnu sed.
* bash 3.2.57 or later tested
* ffmpeg version 2.8.3 or later (4.4 or later if the input file is `.aaxc`)
* libmp3lame - (typically 'lame' in your system's package manager)
* GNU grep - macOS or BSD users may need to install through package manager
* GNU sed - see above
* GNU find - see above
* jq - only if `--use-audible-cli-data` is set or if converting an .aaxc file
* mp4art used to add cover art to m4a and m4b files. Optional
* mediainfo used to add additional media tags like narrator. Optional
## OSX
Thanks to thibaudcolas, this script has been tested on OSX 10.11.6 El Capitan. YMMV, but it should work for
conversions in OSX. It is recommended that you install GNU grep using 'brew install grep' for chapter padding to work.
## AUR
Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur.archlinux.org/packages/aaxtomp3-git/). Note that you will still need to extract your activation bytes before use.
## Usage(s)
```
bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level <COMPRESSIONLEVEL>] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode <AUTHCODE>] [-n|--no-clobber] [-t|--target_dir <PATH>] [-C|--complete_dir <PATH>] [-V|--validate] [-d|--debug] [-h|--help] [--continue <CHAPTERNUMBER>] <AAX INPUT_FILES>...
bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level <COMPRESSIONLEVEL>] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode <AUTHCODE>] [-n|--no-clobber] [-t|--target_dir <PATH>] [-C|--complete_dir <PATH>] [-V|--validate] [--use-audible-cli-data]] [-d|--debug] [-h|--help] [--continue <CHAPTERNUMBER>] <AAX/AAXC INPUT_FILES>...
```
or if you want to get guided through the options
```
bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help]
```
* **&lt;AAX INPUT_FILES&gt;**... are considered input file(s), useful for batching!
## Options
## Options for AAXtoMP3
* **-f** or **--flac** Flac Encoding and as default produces a single file.
* **-o** or **--opus** Ogg/Opus Encoding defaults to multiple file output by chapter. The extension is .ogg
* **-a** or **--aac** AAC Encoding and produce a m4a single files output.
* **-A** or **--authcode &lt;AUTHCODE&gt;** for this execution of the command use the provided &lt;AUTHCODE&gt; to decode the AAX file.
* **-A** or **--authcode &lt;AUTHCODE&gt;** for this execution of the command use the provided &lt;AUTHCODE&gt; to decode the AAX file. Not needed if the source file is .aaxc.
* **-n** or **--no-clobber** If set and the target directory already exists, AAXtoMP3 will exit without overwriting anything.
* **-t** or **--target_dir &lt;PATH&gt;** change the default output location to the named &lt;PATH&gt;. Note the default location is ./Audiobook of the directory to which each AAX file resides.
* **-C** or **--complete_dir &lt;PATH&gt;** a directory to place aax files after they have been decoded successfully. Note make a back up of your aax files prior to using this option. Just in case something goes wrong.
@ -57,23 +56,29 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level <COMPRESS
* **--dir-naming-scheme &lt;STRING&gt;** or **-D** Use a custom directory naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
* **--file-naming-scheme &lt;STRING&gt;** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
* **--chapter-naming-scheme &lt;STRING&gt;** Use a custom chapter naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more info. Needed for the files in the `aaxc` format.
## Options for interactiveAAXtoMP3
* **-a** or **--advanced** Get more options to choose. Not used right now.
* **-h** or **--help** Get a help prompt.
This script presents you the options you chose last time as default.
When you get asked for the aax-file you may just drag'n'drop it to the terminal.
### [AUTHCODE]
**Your** Audible auth code (it won't correctly decode otherwise) (required).
### AUTHCODE
**Your** Audible auth code (it won't correctly decode otherwise) (not required to decode the `aaxc` format).
#### Determining your own AUTHCODE
You will need your authentication code that comes from Audible's 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).
[audible-activator](https://github.com/inAudible-NG/audible-activator) or like [audible-cli](https://github.com/mkb79/audible-cli).
#### Specifying the AUTHCODE.
In order of __precidence__.
1. __--authcode [AUTHCODE]__ The command line option. With the highest precedence.
2. __.authcode__ If this file is placed in the current working directory and contains only the authcode it is used if the above is not.
3. __~/.authcode__ a global config file for all the tools. And is used as the default if none of the above are specified.
__Note:__ At least one of the above must be exist. The code must also match the encoding for the user that owns the AAX file(s). If the authcode does not match the AAX file no transcoding will occur.
__Note:__ At least one of the above must be exist if converting `aax` files. The code must also match the encoding for the user that owns the AAX file(s). If the authcode does not match the AAX file no transcoding will occur.
### MP3 Encoding
* This is the **default** encoding
@ -147,6 +152,7 @@ So you can use `--dir-naming-scheme '$(date +%Y)/$artist'`, but using `--file-na
* If you don't want to have the books separated by author, use `--dir-naming-scheme '$genre/$title'`
### Installing Dependencies.
In general, take a look at [command-not-found.com](https://command-not-found.com/)
#### FFMPEG,FFPROBE
__Ubuntu, Linux Mint, Debian__
```
@ -188,6 +194,7 @@ __MacOS__
brew install ffmpeg
brew install gnu-sed
brew install grep
brew install findutils
```
#### mp4art/mp4chaps
@ -224,6 +231,41 @@ __MacOS__
```
brew install mediainfo
```
## AAXC files
The AAXC format is a new Audible encryption format, meant to replace the old AAX.
The encryption has been updated, and now to decrypt the file the authcode
is not sufficient, we need two "keys" which are unique for each audiobook.
Since getting those keys is not simple, for now the method used to get them
is handled by the package audible-cli, that stores
them in a file when downloading the aaxc file. This means that in order to
decrypt the aaxc files, they must be downloaded with audible-cli.
## Audible-cli integration
Some information are not present in the AAX file. For example the chapters's
title, additional chapters division (Opening and End credits, Copyright and
more). Those information are avaiable via a non-public audible API. This
[repo](https://github.com/mkb79/Audible) provides a python API wrapper, and the
[audible-cli](https://github.com/mkb79/audible-cli) packege makes easy to get
more info. In particular the flags **--cover --cover-size 1215 --chapter**
downloads a better-quality cover (.jpg) and detailed chapter infos (.json).
More info are avaiable on the package page.
Some books might not be avaiable in the old `aax` format, but only in the newer
`aaxc` format. In that case, you can use [audible-cli](https://github.com/mkb79/audible-cli)
to download them. For example, to download all the books in your library in the newer `aaxc` format, as well as
chapters's title and an HQ cover: `audible download --all --aaxc --cover --cover-size 1215 --chapter`.
To make AAXtoMP3 use the additional data, specify the **--use-audible-cli-data**
flag: it expects the cover and the chapter files (and the voucher, if converting
an aaxc file) to be in the same location of the AAX file. The naming of these
files must be the one set by audible-cli. When converting aaxc files, the variable
is automatically set, so be sure to follow the instructions in this paragraph.
For more information on how to use the `audible-cli` package, check out the git page [audible-cli](https://github.com/mkb79/audible-cli).
Please note that right now audible-cli is in dev stage, so keep in mind that the
naming scheme of the additional files, the flags syntax and other things can
change without warning.
## Anti-Piracy Notice

159
interactiveAAXtoMP3 Normal file
View File

@ -0,0 +1,159 @@
#!/usr/bin/env bash
# ===Note for contributors========================================================================================================================
# This script interactively asks the user for the options to call AAXtoMP3 with. This first version does not include all options of AAXtoMP3
# since I tried to keep the dialog short, but I added an --advanced option, which is unused right now, but might be used in the future to add
# more options which only show up if explicitely wanted.
# If you want to add functionality please consider, whether the functionality you add might belong to the advanced options.
# ===Variables====================================================================================================================================
# Help message
help=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n
--advanced More options
--help Print this message\n'
summary="" # This will contain a summary of the options allready set.
call="./AAXtoMP3" # This will contain the call for AAXtoMP3.
advanced=0 # Toggles advanced options on or off.
# ===Options======================================================================================================================================
while true; do
case "$1" in
# Advanced options.
-a | --advanced ) advanced=1; shift ;;
# Command synopsis.
-h | --help ) echo -e "$help"; exit ;;
# Anything else stops command line processing.
* ) break ;;
esac
done
# ===Cross platform compatible use grep and sed===================================================================================================
# ===Detect which annoying version of grep we have===
GREP=$(grep --version | grep -q GNU && echo "grep" || echo "ggrep")
if ! [[ $(type -P "$GREP") ]]; then
echo "$GREP (GNU grep) is not in your PATH"
echo "Without it, this script will break."
echo "On macOS, you may want to try: brew install grep"
exit 1
fi
# ===Detect which annoying version of sed we have===
SED=$(sed --version 2>&1 | $GREP -q GNU && echo "sed" || echo "gsed")
if ! [[ $(type -P "$SED") ]]; then
echo "$SED (GNU sed) is not in your PATH"
echo "Without it, this script will break."
echo "On macOS, you may want to try: brew install gnu-sed"
exit 1
fi
# ===Get options from last time===================================================================================================================
# ===Set default values===
lastcodec="mp3"
lastcompression="4"
lastchapters="yes"
lastauthcode=""
lastloglevel="1"
# ===Get Values from last time===
if [ -f ".interactivesave" ]; then
for ((i=1;i<=$(wc -l .interactivesave | cut -d " " -f 1);i++)) do
line=$(head -$i .interactivesave | tail -1)
case $(echo $line | cut -d " " -f 1 | $SED 's/.$//') in
codec ) lastcodec="$(echo $line | cut -d " " -f 2)";;
compression ) lastcompression="$(echo $line | cut -d " " -f 2)";;
chapters ) lastchapters="$(echo $line | cut -d " " -f 2)";;
authcode ) lastauthcode="$(echo $line | cut -d " " -f 2)";;
loglevel ) lastloglevel="$(echo $line | cut -d " " -f 2)";;
* ) rm .interactivesave; exit 1;;
esac
done
fi
# ===Get options for AAXtoMP3=====================================================================================================================
# ===Codec===
while true; do
clear;
read -e -p "codec (mp3/m4a/m4b/flac/aac/opus): " -i "$lastcodec" codec
case "$codec" in
mp3 ) summary="$summary""codec: $codec"; call="$call -e:mp3"; break;;
m4a ) summary="$summary""codec: $codec"; call="$call -e:m4a"; break;;
m4b ) summary="$summary""codec: $codec"; call="$call -e:m4b"; break;;
flac ) summary="$summary""codec: $codec"; call="$call --flac"; break;;
aac ) summary="$summary""codec: $codec"; call="$call --aac"; break;;
opus ) summary="$summary""codec: $codec"; call="$call --opus"; break;;
esac
done
# ===Compression===
while true; do
clear; echo -e "$summary"
case "$codec" in
mp3 ) maxlevel=9;;
flac ) maxlevel=12;;
opus ) maxlevel=10;;
* ) break;;
esac
read -e -p "compression level (0-$maxlevel): " -i "$lastcompression" compression
if [[ $compression =~ ^[0-9]+$ ]] && [[ "$compression" -ge "0" ]] && [[ "$compression" -le "$maxlevel" ]]; then
summary="$summary""\ncompression level: $compression"
call="$call --level $compression"
break
fi
done
# ===Chapters===
while true; do
clear; echo -e "$summary"
read -e -p "chapters (yes/no/chapternumber to continue with): " -i "$lastchapters" chapters
case "$chapters" in
^[0-9]+$ ) summary="$summary""\nchapters: $chapters"; call="$call -c --continue ${chapters}"; break;;
yes ) summary="$summary""\nchapters: $chapters"; call="$call -c"; break;;
no ) summary="$summary""\nchapters: $chapters"; call="$call -s"; break;;
esac
done
# ===Authcode===
if ! [ -r .authcode ] || [ -r ~/.authcode ]; then
clear; echo -e "$summary"
read -e -p "Authcode: " -i "$lastauthcode" authcode
summary="$summary""\nauthcode: $authcode"
call="$call -A $authcode"
fi
# ===Loglevel===
while true; do
clear; echo -e "$summary"
read -e -p "loglevel (0/1/2/3): " -i "$lastloglevel" loglevel
if [[ $loglevel =~ ^[0-9]+$ ]] && [[ "$loglevel" -ge "0" ]] && [[ "$loglevel" -le "3" ]]; then
summary="$summary""\nloglevel: $loglevel"
call="$call -l $loglevel"
break
fi
done
# ===File===
clear; echo -e "$summary"
read -p "aax-file: " file
file="${file%\'}" #remove suffix ' if file is given via drag'n'drop
file="${file#\'}" #remove prefix ' if file is given via drag'n'drop
savefile="$summary"
summary="$summary""\naax-file: $file"
call="$call $(echo $file | $SED "s;~;$HOME;")"
# ===Summerize chosen options and call AAXtoMP3===================================================================================================
# ===Summary===
clear; echo -e "$summary\n"
echo -e "$call\n"
# ===Save chosen options===
echo -e $savefile | $SED "s;\ level:;:;" > .interactivesave
# ===Call AAXtoMP3===
$call