From 4080018295081d304682138dac4071520699c7c6 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Wed, 3 Feb 2021 16:44:47 +0100 Subject: [PATCH 01/31] Info about audible.cli integration --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 55e1631..3fb1746 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,21 @@ __MacOS__ ``` brew install mp4v2 ``` + +## 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-publicly audible API. This [repo](https://github.com/mkb79/Audible) +provides a python API, and the [audible-cli](https://github.com/mkb79/audible-cli) +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. + +To make AAXtoMP3 use them, specify the **--use-audible-cli-data** flag: it will look +for the cover and the chapter files in the same location of the AAX file. +If you didn't move them around they are already there. For now they must have +the name set by audible-cli. + ## Anti-Piracy Notice Note that this project **does NOT ‘crack’** the DRM. It simply allows the user to From eceb4e2f09e4dd4ab9df240c2494bc085f9152d5 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Wed, 3 Feb 2021 16:47:19 +0100 Subject: [PATCH 02/31] flag --- AAXtoMP3 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index 7a4368f..55151a7 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -18,6 +18,7 @@ DEBUG=0 # Default off, If set extremely verbose output. noclobber=0 # Default off, clobber only if flag is enabled continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt. continueAt=1 # Optional chapter to continue splitting the chapters. +audibleCli=0 # Default off, Use additional data gathered from mkb79/audible-cli # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -56,6 +57,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 ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. From 02e113230165a9d0edc0b19402d71595d5c35839 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 4 Feb 2021 09:59:19 +0100 Subject: [PATCH 03/31] validate files --- AAXtoMP3 | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 55151a7..3fcc16a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -284,7 +284,7 @@ validate_aax() { # Test for existence if [[ ! -r "${media_file}" ]] ; then log "ERROR File NOT Found: ${media_file}" - return + return 1 else if [[ "${VALIDATE}" == "1" ]]; then log "Test 1 SUCCESS: ${media_file}" @@ -323,6 +323,36 @@ validate_aax() { set -e errexit } +validate_extra_files() { + local extra_media_file extra_title extra_chapter_file + 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 + extra_chapter_file="${extra_title}-chapters.json" + + debug_vars "Audible-cli files" extra_media_file extra_title extra_chapter_file + + # Test for chapter file existence + if [[ ! -r "${extra_chapter_file}" ]] ; then + log "ERROR File NOT Found: ${extra_chapter_file}" + return 1 + fi + + # Test for cover art existence (any resolution) + if [[ ! $(find -maxdepth 1 -regex ".*/${extra_title}_([0-9]+)\\.jpg") ]]; 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() { @@ -368,6 +398,12 @@ do # Don't bother doing anything else with this file. continue fi + + 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 # ----- # Make sure everything is a variable. Simplifying Command interpretation From bcfdf0ac062aa28c9c833839b69f1167e9ab24cf Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 4 Feb 2021 10:21:58 +0100 Subject: [PATCH 04/31] ignore jpg (cover) and json (chapters) files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bc3dd24..ec72114 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ ACTIVATION .authcode *aax +*jpg +*json Audiobook/* From 6171eab4f15f6fe968820e563cd8bbad6b18812c Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 4 Feb 2021 13:36:40 +0100 Subject: [PATCH 05/31] description of flag in options --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fb1746..220c7a0 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [ * **-s** or **--single** Output a single file for the entire book. If you only want a single ogg file for instance. * **-c** or **--chaptered** Output a single file per chapter. The `--chaptered` will only work if it follows the `--aac -e:m4a -e:m4b --flac` options. * **--continue <CHAPTERNUMBER>** If the splitting into chapters gets interrupted (e.g. by a weak battery on your laptop) you can go on where the process got interrupted. Just delete the last chapter (which was incompletely generated) and redo the task with "--continue <CHAPTERNUMBER>" where CHAPTERNUMBER is the chapter that got interrupted. - +* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](## Audible-cli integration) for more infos. ### [AUTHCODE] **Your** Audible auth code (it won't correctly decode otherwise) (required). From d0b5bda46d84960f2970bca603af8414477988e9 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 4 Feb 2021 13:39:20 +0100 Subject: [PATCH 06/31] fixed anchor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 220c7a0..1840e04 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [ * **-s** or **--single** Output a single file for the entire book. If you only want a single ogg file for instance. * **-c** or **--chaptered** Output a single file per chapter. The `--chaptered` will only work if it follows the `--aac -e:m4a -e:m4b --flac` options. * **--continue <CHAPTERNUMBER>** If the splitting into chapters gets interrupted (e.g. by a weak battery on your laptop) you can go on where the process got interrupted. Just delete the last chapter (which was incompletely generated) and redo the task with "--continue <CHAPTERNUMBER>" where CHAPTERNUMBER is the chapter that got interrupted. -* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](## Audible-cli integration) for more infos. +* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more infos. ### [AUTHCODE] **Your** Audible auth code (it won't correctly decode otherwise) (required). From b7e978c8bbc7f23ae00c0370576cd1c8a382e23e Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 4 Feb 2021 13:45:42 +0100 Subject: [PATCH 07/31] better HQ cover processing --- AAXtoMP3 | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 3fcc16a..4577c86 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -324,7 +324,7 @@ validate_aax() { } validate_extra_files() { - local extra_media_file extra_title extra_chapter_file + local extra_media_file # extra_title extra_chapter_file extra_media_file="$1" # Bash trick to delete, non greedy, from the end up until the first '-' extra_title="${extra_media_file%-*}" @@ -336,16 +336,23 @@ validate_extra_files() { # Chapter file: BookTitle-chapters.json extra_chapter_file="${extra_title}-chapters.json" - debug_vars "Audible-cli files" extra_media_file extra_title extra_chapter_file # Test for chapter file existence if [[ ! -r "${extra_chapter_file}" ]] ; then log "ERROR File NOT Found: ${extra_chapter_file}" return 1 fi + + extra_find_command='find -maxdepth 1 -regex ".*/${extra_title}_([0-9]+)\.jpg"' + # extra_cover_file="$(find -maxdepth 1 -regex \".*/${extra_title}_\(\[\0\-\9\]\+\)\\.jpg\")" - # Test for cover art existence (any resolution) - if [[ ! $(find -maxdepth 1 -regex ".*/${extra_title}_([0-9]+)\\.jpg") ]]; then + # We want the output of the find command, we will turn errexit on later + set +e errexit + extra_cover_file="$(eval ${extra_find_command})" + set -e errexit + + debug_vars "Audible-cli files" extra_media_file extra_title extra_chapter_file extra_cover_file + if [[ "x${extra_cover_file}" == "x" ]] ; then log "ERROR Cover File NOT Found" return 1 fi @@ -479,9 +486,20 @@ do fi # Grab the cover art if available. cover_file="${output_directory}/cover.jpg" + extra_crop_cover='' if [ "${continue}" == "0" ]; then - log "Extracting cover into ${cover_file}..." - ${chapternum}))" = "0" ]; then # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)" - Date: Fri, 5 Feb 2021 10:22:12 +0100 Subject: [PATCH 08/31] validate_extra_files final touchs, mediainfo get only useful infos, save chapter infos from audible-cli json, publisher tag, cover crop, real track title --- AAXtoMP3 | 60 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 4577c86..53b5676 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -324,7 +324,7 @@ validate_aax() { } validate_extra_files() { - local extra_media_file # extra_title extra_chapter_file + 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%-*}" @@ -334,24 +334,25 @@ validate_extra_files() { # 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})" + set -e errexit + + debug_vars "Audible-cli variables" extra_media_file extra_title extra_chapter_file extra_cover_file extra_find_command extra_dirname # Test for chapter file existence if [[ ! -r "${extra_chapter_file}" ]] ; then log "ERROR File NOT Found: ${extra_chapter_file}" return 1 fi - - extra_find_command='find -maxdepth 1 -regex ".*/${extra_title}_([0-9]+)\.jpg"' - # extra_cover_file="$(find -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})" - set -e errexit - - debug_vars "Audible-cli files" extra_media_file extra_title extra_chapter_file extra_cover_file if [[ "x${extra_cover_file}" == "x" ]] ; then log "ERROR Cover File NOT Found" return 1 @@ -367,8 +368,29 @@ save_metadata() { media_file="$1" ffprobe -i "$media_file" 2> "$metadata_file" if [[ $(type -P mediainfo) ]]; then + echo "Mediainfo data START" >> "$metadata_file" # Mediainfo output is structured like ffprobe, so we append it to the metadata file and then parse it with get_metadata_value() - mediainfo "$media_file" >> "$metadata_file" + # mediainfo "$media_file" >> "$metadata_file" + # Or we only get the data we are intrested in: + # Description + echo "Track_More :" "$(mediainfo --Inform="General;%Track_More%" "$media_file")" >> "$metadata_file" + # Narrator + echo "nrt :" "$(mediainfo --Inform="General;%nrt%" "$media_file")" >> "$metadata_file" + # Publisher + 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)\n\n"' "${extra_chapter_file}" \ + | tr -d ':' >> "$metadata_file" fi debug "Metadata file $metadata_file" debug_file "$metadata_file" @@ -434,6 +456,7 @@ do if [[ $(type -P mediainfo) ]]; then narrator="$(get_metadata_value nrt)" description="$(get_metadata_value Track_More)" + publisher="$(get_metadata_value pub)" else narrator="" description="" @@ -453,7 +476,7 @@ 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 output_file metadata_file working_directory + 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 output_file metadata_file working_directory # ----- if [ "${continue}" == "0" ]; then @@ -478,6 +501,7 @@ do -metadata copyright="${copyright}" \ -metadata description="${description}" \ -metadata composer="${narrator}" \ + -metadata publisher="${publisher}" \ -f ${container} \ "${output_file}" @@ -495,6 +519,8 @@ do # 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 log "Extracting cover into ${cover_file}..." @@ -558,7 +584,7 @@ do fi # Big Long chapter debug - debug_vars "Chapter Variables:" cover_file extra_crop_cover chapter_start chapter_end id3_version_param chapternum chapter_title chapter_file + debug_vars "Chapter Variables:" cover_file chapter_start chapter_end id3_version_param chapternum 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. @@ -576,9 +602,9 @@ 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:s:a track="${chapternum}" \ + -metadata title="${chapter}" \ + -metadata:s:a title="${chapter}" \ + -metadata:s:a track="${chapternum}/${chaptercount}" \ -map_chapters -1 \ -f ${container} \ "${chapter_file}" From 9ea5bf0899e1cd83f47946f9075559876991cf76 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Fri, 5 Feb 2021 15:33:07 +0100 Subject: [PATCH 09/31] restore ffmpeg to be silent --- AAXtoMP3 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 53b5676..f5fbb6c 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -460,6 +460,7 @@ do else narrator="" description="" + publisher="" fi if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then @@ -589,7 +590,8 @@ do # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)" - ffmpeg \ + Date: Fri, 5 Feb 2021 16:10:38 +0100 Subject: [PATCH 10/31] textwidth 80, note about dev stage of the a-cli package, rewrote file requirement --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f3f284e..40e439f 100644 --- a/README.md +++ b/README.md @@ -185,19 +185,23 @@ brew install mp4v2 ## 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-publicly audible API. This [repo](https://github.com/mkb79/Audible) -provides a python API, and the [audible-cli](https://github.com/mkb79/audible-cli) -makes easy to get more info. In particular the flags **--cover --cover-size 1215 --chapter** +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. -To make AAXtoMP3 use them, specify the **--use-audible-cli-data** flag: it will look -for the cover and the chapter files in the same location of the AAX file. -If you didn't move them around they are already there. For now they must have -the name set by audible-cli. +To make AAXtoMP3 use the additional data, specify the **--use-audible-cli-data** +flag: it expects the cover and the chapter files to be in the same location of +the AAX file. The naming of these files must be the one set by 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 Note that this project **does NOT ‘crack’** the DRM. It simply allows the user to use their own encryption key (fetched from Audible servers) to decrypt the From f94cf1baa77746c18e32ec28d06094f33b04abe5 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Fri, 5 Feb 2021 16:53:43 +0100 Subject: [PATCH 11/31] fix for find command: use basename --- AAXtoMP3 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 20ebe6d..9193b26 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -371,13 +371,14 @@ validate_extra_files() { # Cover extra_dirname="$(dirname "${extra_media_file}")" - extra_find_command='find "${extra_dirname}" -maxdepth 1 -regex ".*/${extra_title}_([0-9]+)\.jpg"' + 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 - debug_vars "Audible-cli variables" extra_media_file extra_title extra_chapter_file extra_cover_file extra_find_command extra_dirname + debug_vars "Audible-cli variables" extra_media_file extra_title extra_chapter_file extra_cover_file extra_find_command extra_eval_comm extra_dirname # Test for chapter file existence if [[ ! -r "${extra_chapter_file}" ]] ; then From f74ec2e75ac736b05b0346ad4883e36b5f8ea34e Mon Sep 17 00:00:00 2001 From: fabh2o Date: Fri, 5 Feb 2021 21:00:39 +0100 Subject: [PATCH 12/31] removed Audiobook (genre) dir from the output --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 9193b26..8f5144e 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -474,9 +474,9 @@ do title=$(get_metadata_value title | $SED 's/'\:'/'-'/g' | $SED 's/- /-/g' | xargs -0) title=${title:0:100} if [ "x${targetdir}" != "x" ] ; then - output_directory="${targetdir}/${genre}/${artist}/${title}" + output_directory="${targetdir}/${artist}/${title}" else - output_directory="$(dirname "${aax_file}")/${genre}/${artist}/${title}" + output_directory="$(dirname "${aax_file}")/${artist}/${title}" fi output_file="${output_directory}/${title}.${extension}" bitrate="$(get_bitrate)k" From 60b762bb2928f9e6d8d4d7bda1c36b4adbe88c10 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 6 Feb 2021 18:26:14 +0100 Subject: [PATCH 13/31] append narrator name to the output folder --- AAXtoMP3 | 18 ++++++++++++++++-- README.md | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index ec2ce38..5d7deb3 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -19,6 +19,7 @@ DEBUG=0 # Default off, If set extremely verbose output. noclobber=0 # Default off, clobber only if flag is enabled continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt. continueAt=1 # Optional chapter to continue splitting the chapters. +appendNarrator=0 # Default off, Append the narrator name to the Folder name. Needs mediainfo # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -59,6 +60,8 @@ while true; do --continue ) continueAt="$2"; continue=1; shift 2 ;; # Compression level --level ) level="$2"; shift 2 ;; + # Append Narrator + --append-narrator ) appendNarrator=1; shift ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -141,7 +144,7 @@ log() { # ----- # 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 +debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code appendNarrator # ======================================================================== # Variable validation @@ -294,6 +297,13 @@ if [ "${level}" != "-1" ]; then fi fi +# ----- +# Check for presence of mediainfo in case the flag --append-narrator is used +if [[ "${appendNarrator}" == 1 && "x$(type -P mediainfo)" == "x" ]]; then + echo "ERROR --append-narator specified, but mediainfo is not in PATH" + exit 1 +fi + # ----- # Clean up if someone hits ^c or the script exits for any reason. trap 'rm -r -f "${working_directory}"' EXIT @@ -434,7 +444,11 @@ do description="" publisher="" fi - + # If the flag --append-narrator is used, we append the narrator name to the output dir + if [[ "${appendNarrator}" == 1 ]]; then + output_directory="${output_directory}"-"${narrator}" + output_file="${output_directory}/${title}.${extension}" + fi if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" exit 0 diff --git a/README.md b/README.md index ab3dd87..a197885 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level Date: Sat, 6 Feb 2021 18:27:13 +0100 Subject: [PATCH 14/31] debugvar audibleCli --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 8f5144e..f2b0e0a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -144,7 +144,7 @@ log() { # ----- # 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 +debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code audibleCli # ======================================================================== # Variable validation From b8bef5812244f6c4d7f929459b5f6ac5d415da3d Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 6 Feb 2021 18:34:09 +0100 Subject: [PATCH 15/31] fix indentation --- AAXtoMP3 | 18 +++++++++--------- README.md | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 5d7deb3..375e8b9 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -19,7 +19,7 @@ DEBUG=0 # Default off, If set extremely verbose output. noclobber=0 # Default off, clobber only if flag is enabled continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt. continueAt=1 # Optional chapter to continue splitting the chapters. -appendNarrator=0 # Default off, Append the narrator name to the Folder name. Needs mediainfo +appendNarrator=0 # Default off, Append the narrator name to the Folder name. Needs mediainfo # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -60,8 +60,8 @@ while true; do --continue ) continueAt="$2"; continue=1; shift 2 ;; # Compression level --level ) level="$2"; shift 2 ;; - # Append Narrator - --append-narrator ) appendNarrator=1; shift ;; + # Append Narrator + --append-narrator ) appendNarrator=1; shift ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -300,7 +300,7 @@ fi # ----- # Check for presence of mediainfo in case the flag --append-narrator is used if [[ "${appendNarrator}" == 1 && "x$(type -P mediainfo)" == "x" ]]; then - echo "ERROR --append-narator specified, but mediainfo is not in PATH" + echo "ERROR --append-narator specified, but mediainfo is not in PATH" exit 1 fi @@ -444,11 +444,11 @@ do description="" publisher="" fi - # If the flag --append-narrator is used, we append the narrator name to the output dir - if [[ "${appendNarrator}" == 1 ]]; then - output_directory="${output_directory}"-"${narrator}" - output_file="${output_directory}/${title}.${extension}" - fi + # If the flag --append-narrator is used, we append the narrator name to the output dir + if [[ "${appendNarrator}" == 1 ]]; then + output_directory="${output_directory}"-"${narrator}" + output_file="${output_directory}/${title}.${extension}" + fi if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" exit 0 diff --git a/README.md b/README.md index a197885..3e1d6e0 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level Date: Sat, 6 Feb 2021 18:38:03 +0100 Subject: [PATCH 16/31] forgot to update help message --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 375e8b9..7e95c40 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,7 +5,7 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber]\n[--target_dir ] [--complete_dir ] [--validate]\n[--continue ]{FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber]\n[--target_dir ] [--complete_dir ] [--validate] [--append-narrator]\n[--continue ]{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. From c45a4ac61014ea978caa2dd9308d669b4fb2abcb Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 6 Feb 2021 19:06:56 +0100 Subject: [PATCH 17/31] reformat usage + auduble-cli flag --- AAXtoMP3 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index b2e0bbc..88e70ac 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,7 +5,10 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber]\n[--target_dir ] [--complete_dir ] [--validate] [--append-narrator]\n[--continue ]{FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ] + [--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber] + [--target_dir ] [--complete_dir ] [--validate] [--append-narrator] + [--use-audible-cli-data] [--continue ] {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. @@ -431,7 +434,7 @@ save_metadata() { # 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)\n\n"' "${extra_chapter_file}" \ + 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" From 45bd9e666f2952bcda46e08b3f34033357d35841 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 10:15:34 +0100 Subject: [PATCH 18/31] remove all apprnd-narrator traces --- AAXtoMP3 | 19 ++----------------- README.md | 1 - 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 88e70ac..98b5e9d 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -7,7 +7,7 @@ # Usage Synopsis. usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ] [--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber] - [--target_dir ] [--complete_dir ] [--validate] [--append-narrator] + [--target_dir ] [--complete_dir ] [--validate] [--use-audible-cli-data] [--continue ] {FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extension. @@ -23,7 +23,6 @@ noclobber=0 # Default off, clobber only if flag is enabled continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt. continueAt=1 # Optional chapter to continue splitting the chapters. audibleCli=0 # Default off, Use additional data gathered from mkb79/audible-cli -appendNarrator=0 # Default off, Append the narrator name to the Folder name. Needs mediainfo # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -66,8 +65,6 @@ while true; do --use-audible-cli-data ) audibleCli=1; shift ;; # Compression level --level ) level="$2"; shift 2 ;; - # Append Narrator - --append-narrator ) appendNarrator=1; shift ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -150,7 +147,7 @@ log() { # ----- # 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 appendNarrator audibleCli +debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code audibleCli # ======================================================================== # Variable validation @@ -303,13 +300,6 @@ if [ "${level}" != "-1" ]; then fi fi -# ----- -# Check for presence of mediainfo in case the flag --append-narrator is used -if [[ "${appendNarrator}" == 1 && "x$(type -P mediainfo)" == "x" ]]; then - echo "ERROR --append-narator specified, but mediainfo is not in PATH" - exit 1 -fi - # ----- # Clean up if someone hits ^c or the script exits for any reason. trap 'rm -r -f "${working_directory}"' EXIT @@ -507,11 +497,6 @@ do description="" publisher="" fi - # If the flag --append-narrator is used, we append the narrator name to the output dir - if [[ "${appendNarrator}" == 1 ]]; then - output_directory="${output_directory}"-"${narrator}" - output_file="${output_directory}/${title}.${extension}" - fi if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" exit 0 diff --git a/README.md b/README.md index a1910d8..7e75183 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,6 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level Date: Sun, 7 Feb 2021 10:20:06 +0100 Subject: [PATCH 19/31] restored default output dir struct --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 98b5e9d..de1971a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -477,9 +477,9 @@ do title=$(get_metadata_value title | $SED 's/'\:'/'-'/g' | $SED 's/- /-/g' | xargs -0) title=${title:0:100} if [ "x${targetdir}" != "x" ] ; then - output_directory="${targetdir}/${artist}/${title}" + output_directory="${targetdir}/${genre}/${artist}/${title}" else - output_directory="$(dirname "${aax_file}")/${artist}/${title}" + output_directory="$(dirname "${aax_file}")/${genre}/${artist}/${title}" fi output_file="${output_directory}/${title}.${extension}" bitrate="$(get_bitrate)k" From d199d875bb99e8cace7a482ac3ac48346e40df4d Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 10:26:29 +0100 Subject: [PATCH 20/31] Debugvar chapter, restored chapter number format --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index de1971a..e32f0c1 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -626,7 +626,7 @@ do fi # Big Long chapter debug - debug_vars "Chapter Variables:" cover_file chapter_start chapter_end id3_version_param chapternum chapter_title chapter_file + debug_vars "Chapter Variables:" cover_file chapter_start chapter_end id3_version_param chapternum chapter 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. @@ -648,7 +648,7 @@ do -metadata track="${chapternum}" \ -metadata title="${chapter}" \ -metadata:s:a title="${chapter}" \ - -metadata:s:a track="${chapternum}/${chaptercount}" \ + -metadata:s:a track="${chapternum}" \ -map_chapters -1 \ -f ${container} \ "${chapter_file}" From afb852fdf165c2aeb6f08d7583225e77adb940ab Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 16:51:51 +0100 Subject: [PATCH 21/31] cut title to 128 char + no - or : subsitution --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index ec2ce38..b47e29f 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -411,8 +411,8 @@ do save_metadata "${aax_file}" genre=$(get_metadata_value genre) artist=$(get_metadata_value artist) - 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} if [ "x${targetdir}" != "x" ] ; then output_directory="${targetdir}/${genre}/${artist}/${title}" else From eff626ee95d5c2c261bfda1e4612f3db047066eb Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 10 Jul 2021 21:20:43 +0200 Subject: [PATCH 22/31] move info after req --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e6ffbd9..1e58bb2 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,23 @@ __MacOS__ brew install mp4v2 ``` +#### mediainfo +_Note: This is an optional dependency._ + +__Ubuntu, Linux Mint, Debian__ +``` +sudo apt-get update +sudo apt-get install mediainfo +``` +__CentOS, RHEL & Fedora__ +``` +yum install mediainfo +``` +__MacOS__ +``` +brew install mediainfo +``` + ## 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 @@ -236,23 +253,6 @@ 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. -#### mediainfo -_Note: This is an optional dependency._ - -__Ubuntu, Linux Mint, Debian__ -``` -sudo apt-get update -sudo apt-get install mediainfo -``` -__CentOS, RHEL & Fedora__ -``` -yum install mediainfo -``` -__MacOS__ -``` -brew install mediainfo -``` - ## Anti-Piracy Notice Note that this project **does NOT ‘crack’** the DRM. It simply allows the user to From 3d062fdba71978a8c7596a261482fe256fbc0e39 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 16:16:14 +0200 Subject: [PATCH 23/31] --aaxc flag, validate voucher and get key and id --- AAXtoMP3 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e5840fd..11836bf 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -9,7 +9,7 @@ usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ] [--no-clobber] [--target_dir ] [--complete_dir ] [--validate] [--loglevel ] [--keep-author ] [--author ] [--{dir,file,chapter}-naming-scheme ] -[--use-audible-cli-data] [--continue ] {FILES}\n' +[--use-audible-cli-data] [--aaxc] [--continue ] {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. @@ -32,6 +32,7 @@ continueAt=1 # Optional chapter to continue splitting the chapter 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=0 # Use aaxc input file format, the default is the old aax. # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -80,6 +81,8 @@ while true; do --continue ) continueAt="$2"; continue=1; shift 2 ;; # Use additional data got with mkb79/audible-cli --use-audible-cli-data ) audibleCli=1; shift ;; + # Use aaxc input file format. Implies --use-audible-cli-data + --aaxc ) aaxc=1; audibleCli=1; shift ;; # Compression level --level ) level="$2"; shift 2 ;; # Keep author number n @@ -440,7 +443,17 @@ validate_extra_files() { extra_eval_comm="$(eval echo ${extra_find_command})" set -e errexit - debug_vars "Audible-cli variables" extra_media_file extra_title extra_chapter_file extra_cover_file extra_find_command extra_eval_comm extra_dirname + if [[ "${aaxc}" == "1" ]]; then + 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 From e9b111aa8ac689086f811e6c1b73f49f5eddecdb Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 17:49:36 +0200 Subject: [PATCH 24/31] fully support aaxc --- AAXtoMP3 | 55 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 11836bf..359e2cb 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -297,7 +297,8 @@ if [ -z $auth_code ]; then fi fi # No point going on if no authcode found. -if [ -z $auth_code ]; then +# If we use aaxc as input, we do not need it +if [ -z $auth_code ] || [ "${aaxc}" = "0" ]; then echo "ERROR Missing authcode" echo "$usage" exit 1 @@ -390,8 +391,12 @@ 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 + if [[ "${aaxc}" == "1" ]]; then + output="$(ffprobe -loglevel warning -audible_key "${aaxc_key}" -audible_iv "${aaxc_iv}" -i "${media_file}" 2>&1)" + else + output="$(ffprobe -loglevel warning -activation_bytes ${auth_code} -i "${media_file}" 2>&1)" + fi # If invalid then say something. if [[ $? != "0" ]] ; then @@ -404,7 +409,11 @@ 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)" + if [[ "${aaxc}" == "1" ]]; then + output="$(ffmpeg -hide_banner -audible_key ${aaxc_key} -audible_iv ${aaxc_iv} -i "${media_file}" -vn -f null - 2>&1)" + else + output="$(ffmpeg -hide_banner -activation_bytes ${auth_code} -i "${media_file}" -vn -f null - 2>&1)" + fi if [[ $? != "0" ]] ; then log "ERROR: Invalid File: ${media_file}" else @@ -444,13 +453,14 @@ validate_extra_files() { set -e errexit if [[ "${aaxc}" == "1" ]]; then - extra_voucher="${extra_media_file}.voucher" + # 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) + 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 @@ -529,17 +539,22 @@ do # 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 + validate_aax "${aax_file}" if [[ ${VALIDATE} == "1" ]] ; then # Don't bother doing anything else with this file. continue fi - 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 # ----- # Make sure everything is a variable. Simplifying Command interpretation @@ -619,11 +634,19 @@ 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 + + # Set the needed params to decrypt the file. Needed in the main command as + # well as in the variable total_lenght + if [[ ${aaxc} == "1" ]] ; then + decrypt_param="-audible_key ${aaxc_key} -audible_iv ${aaxc_iv}" + else + decrypt_params="-activation_bytes ${auth_code}" + fi # 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))" @@ -642,10 +665,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}"' Date: Thu, 2 Sep 2021 18:24:57 +0200 Subject: [PATCH 25/31] docs --- README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1e58bb2..acb6008 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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 @@ -14,7 +14,7 @@ Audible fails for some reason. ## Requirements * bash 4.3.42 or later tested -* ffmpeg version 2.8.3 or later +* ffmpeg version 2.8.3 or later (4.4 or later if the input file is `.aaxc`) * 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. @@ -43,7 +43,8 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **-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 <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. +* **-A** or **--authcode <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. Not needed if the source file is .aaxc. +* --aaxc Set the input file type to be `aaxc` instead of the default `aax`. * **-n** or **--no-clobber** If set and the target directory already exists, AAXtoMP3 will exit without overwriting anything. * **-t** or **--target_dir <PATH>** change the default output location to the named <PATH>. Note the default location is ./Audiobook of the directory to which each AAX file resides. * **-C** or **--complete_dir <PATH>** 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. @@ -61,7 +62,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--dir-naming-scheme <STRING>** or **-D** Use a custom directory naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--file-naming-scheme <STRING>** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--chapter-naming-scheme <STRING>** 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 infos. +* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more infos. Needed if the input file is in the `aaxc` format. ## Options for interactiveAAXtoMP3 * **-a** or **--advanced** Get more options to choose. Not used right now. @@ -70,20 +71,20 @@ 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). +**Your** Audible auth code (it won't correctly decode otherwise) (required to decode the `aax` 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 @@ -157,6 +158,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__ ``` @@ -245,10 +247,17 @@ 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 to be in the same location of the AAX file. The naming of these files must be the one set by audible-cli. +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. From b78e4b59b9e5b7c79818bd1f00338cc213a3e1e5 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 19:13:02 +0200 Subject: [PATCH 26/31] auto format selection, fix typo --- AAXtoMP3 | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 359e2cb..a1b0c2b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -9,7 +9,7 @@ usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ] [--no-clobber] [--target_dir ] [--complete_dir ] [--validate] [--loglevel ] [--keep-author ] [--author ] [--{dir,file,chapter}-naming-scheme ] -[--use-audible-cli-data] [--aaxc] [--continue ] {FILES}\n' +[--use-audible-cli-data] [--continue ] {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. @@ -32,7 +32,8 @@ continueAt=1 # Optional chapter to continue splitting the chapter 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=0 # Use aaxc input file format, the default is the old aax. +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 @@ -81,8 +82,6 @@ while true; do --continue ) continueAt="$2"; continue=1; shift 2 ;; # Use additional data got with mkb79/audible-cli --use-audible-cli-data ) audibleCli=1; shift ;; - # Use aaxc input file format. Implies --use-audible-cli-data - --aaxc ) aaxc=1; audibleCli=1; shift ;; # Compression level --level ) level="$2"; shift 2 ;; # Keep author number n @@ -296,13 +295,6 @@ if [ -z $auth_code ]; then auth_code=`head -1 ~/.authcode` fi fi -# No point going on if no authcode found. -# If we use aaxc as input, we do not need it -if [ -z $auth_code ] || [ "${aaxc}" = "0" ]; then - echo "ERROR Missing authcode" - echo "$usage" - exit 1 -fi # ----- # Check the target dir for if set if it is writable @@ -530,10 +522,35 @@ 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. @@ -641,7 +658,7 @@ do if [[ ${aaxc} == "1" ]] ; then decrypt_param="-audible_key ${aaxc_key} -audible_iv ${aaxc_iv}" else - decrypt_params="-activation_bytes ${auth_code}" + decrypt_param="-activation_bytes ${auth_code}" fi # Display the total length of the audiobook in format hh:mm:ss From 9e2d84cb253f8f5ade316439592b36c566b6c25b Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 19:21:41 +0200 Subject: [PATCH 27/31] updated docs to automatic source file format switch --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index acb6008..08423d0 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **-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 <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. Not needed if the source file is .aaxc. -* --aaxc Set the input file type to be `aaxc` instead of the default `aax`. * **-n** or **--no-clobber** If set and the target directory already exists, AAXtoMP3 will exit without overwriting anything. * **-t** or **--target_dir <PATH>** change the default output location to the named <PATH>. Note the default location is ./Audiobook of the directory to which each AAX file resides. * **-C** or **--complete_dir <PATH>** 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. @@ -62,7 +61,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--dir-naming-scheme <STRING>** or **-D** Use a custom directory naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--file-naming-scheme <STRING>** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--chapter-naming-scheme <STRING>** 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 infos. Needed if the input file is in the `aaxc` format. +* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more infos. Needed for the files in the `aaxc` format. ## Options for interactiveAAXtoMP3 * **-a** or **--advanced** Get more options to choose. Not used right now. @@ -253,8 +252,9 @@ to download them. For example, to download all the books in your library in the 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 to be in the same location of -the AAX file. The naming of these files must be the one set by audible-cli. +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. For more information on how to use the `audible-cli` package, check out the git page [audible-cli](https://github.com/mkb79/audible-cli). From 78d6e931ff855a7dee2aee02cb14e210f4d77cf3 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 19:35:14 +0200 Subject: [PATCH 28/31] docs about aaxc --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 08423d0..0427913 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,14 @@ __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 @@ -254,7 +262,8 @@ chapters's title and an HQ cover: `audible download --all --aaxc --cover --cover 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. +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). From 1663daebdcbbd608979e4cae356293a96be27748 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 19:57:54 +0200 Subject: [PATCH 29/31] add jq as dependency --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0427913..7522bf8 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Audible fails for some reason. * 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. +* jq Command-line JSON processor * mp4art used to add cover art to m4a and m4b files. Optional * mediainfo used to add additional media tags like narrator. Optional From b7fbe831c7a034076d48727a1cd728ed06d40522 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 19:59:37 +0200 Subject: [PATCH 30/31] invert authcode required --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7522bf8..29d6430 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ 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 to decode the `aax` format). +**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 From 63ffc47aa5121a4c61da8dd234bbf8d0f6fcbbd7 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Thu, 2 Sep 2021 20:11:12 +0200 Subject: [PATCH 31/31] use the var $decrypt_param with all ffmpeg and ffprobe call --- AAXtoMP3 | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index a1b0c2b..e5f6a96 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -384,11 +384,7 @@ validate_aax() { set +e errexit # Take a look at the aax file and see if it is valid. If the source file is aaxc, we give ffprobe additional flags - if [[ "${aaxc}" == "1" ]]; then - output="$(ffprobe -loglevel warning -audible_key "${aaxc_key}" -audible_iv "${aaxc_iv}" -i "${media_file}" 2>&1)" - else - output="$(ffprobe -loglevel warning -activation_bytes ${auth_code} -i "${media_file}" 2>&1)" - fi + output="$(ffprobe -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)" # If invalid then say something. if [[ $? != "0" ]] ; then @@ -401,11 +397,7 @@ validate_aax() { # This is a big test only performed when the --validate switch is passed. if [[ "${VALIDATE}" == "1" ]]; then - if [[ "${aaxc}" == "1" ]]; then - output="$(ffmpeg -hide_banner -audible_key ${aaxc_key} -audible_iv ${aaxc_iv} -i "${media_file}" -vn -f null - 2>&1)" - else - output="$(ffmpeg -hide_banner -activation_bytes ${auth_code} -i "${media_file}" -vn -f null - 2>&1)" - fi + output="$(ffmpeg -hide_banner ${decrypt_param} -i "${media_file}" -vn -f null - 2>&1)" if [[ $? != "0" ]] ; then log "ERROR: Invalid File: ${media_file}" else @@ -541,6 +533,7 @@ do # 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. @@ -566,12 +559,19 @@ do 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. continue fi - # ----- # Make sure everything is a variable. Simplifying Command interpretation @@ -653,13 +653,6 @@ do # and coders wanting to extend the script. 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 - # Set the needed params to decrypt the file. Needed in the main command as - # well as in the variable total_lenght - if [[ ${aaxc} == "1" ]] ; then - decrypt_param="-audible_key ${aaxc_key} -audible_iv ${aaxc_iv}" - else - decrypt_param="-activation_bytes ${auth_code}" - fi # 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