From 4080018295081d304682138dac4071520699c7c6 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Wed, 3 Feb 2021 16:44:47 +0100 Subject: [PATCH 01/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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/77] 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 a68353f4eb2f1235c090f2591d5c3354c4a2b6ed Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Thu, 25 Feb 2021 23:21:29 +0100 Subject: [PATCH 22/77] Fix for issue KrumpetPirate#155 --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e729761..e9f4eeb 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -684,7 +684,7 @@ 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}" From 2aa1d0504028554658d03a571448ded5abcc1970 Mon Sep 17 00:00:00 2001 From: Katya Vera <79790837+katyavera@users.noreply.github.com> Date: Sun, 28 Feb 2021 15:25:40 +0100 Subject: [PATCH 23/77] 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 `.chapters.txt`. --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e9f4eeb..db1769e 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -743,7 +743,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 From f9b855ea1dbb29ef1348792cab7d246be29d1cf1 Mon Sep 17 00:00:00 2001 From: Katya Vera <79790837+katyavera@users.noreply.github.com> Date: Sun, 28 Feb 2021 15:29:02 +0100 Subject: [PATCH 24/77] Allow spaces in the .aax filename --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e9f4eeb..6c24d2f 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -550,7 +550,7 @@ do # 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 -activation_bytes "${auth_code}" -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))" From 951146022f76b71f7ebbd3566b86b78df926f0be Mon Sep 17 00:00:00 2001 From: Katya Vera <79790837+katyavera@users.noreply.github.com> Date: Sun, 28 Feb 2021 18:36:01 +0100 Subject: [PATCH 25/77] Fix typo, reword --- AAXtoMP3 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e9f4eeb..8aefbee 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -605,11 +605,10 @@ do fi Date: Mon, 1 Mar 2021 04:31:39 +0100 Subject: [PATCH 26/77] Call AAXtoMP3 Interactively This script interactively asks you for the options to call AAXtoMP3 with. --- interactiveAAXtoMP3 | 110 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 interactiveAAXtoMP3 diff --git a/interactiveAAXtoMP3 b/interactiveAAXtoMP3 new file mode 100644 index 0000000..e5a44a9 --- /dev/null +++ b/interactiveAAXtoMP3 @@ -0,0 +1,110 @@ +#!/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==================================================================================================================================== + +# Usage synopsis +usage=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n' +# Help mesaage +help=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n +--advanced More options +--help Print this message\n' +summery="" # This will contain a summery of the options allready set. +call="./AAXtoMP3" # This will contain the call for AAXtoMP3. +isnum='^[0-9]+$' # This is needed to check whether a variable is a number. +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. + * ) echo -e "$usage"; exit ;; + esac +done + +# ===Get options for AAXtoMP3===================================================================================================================== + +# ===Codec=== +while true; do + clear; + read -p "codec (mp3/m4a/m4b/flac/aac/opus): " codec + if [[ "$codec" = "mp3" ]]; then summery="$summery""codec: $codec"; call="$call -e:mp3"; break + elif [[ "$codec" = "m4a" ]]; then summery="$summery""codec: $codec"; call="$call -e:m4a"; break + elif [[ "$codec" = "m4b" ]]; then summery="$summery""codec: $codec"; call="$call -e:m4b"; break + elif [[ "$codec" = "flac" ]]; then summery="$summery""codec: $codec"; call="$call --flac"; break + elif [[ "$codec" = "aac" ]]; then summery="$summery""codec: $codec"; call="$call --aac"; break + elif [[ "$codec" = "opus" ]]; then summery="$summery""codec: $codec"; call="$call --opus"; break + fi +done + +# ===Compression=== +while true; do + clear; echo -e "$summery" + if [[ "$codec" = "mp3" ]]; then maxlevel=9 + elif [[ "$codec" = "flac" ]]; then maxlevel=12 + elif [[ "$codec" = "opus" ]]; then maxlevel=10 + else break + fi + read -p "compression level (0-$maxlevel): " compression + if [[ ${compression} =~ $isnum ]] && [[ "$((${compression} > -1))" == "1" ]] && [[ "$((${compression} < ${maxlevel}+1))" == "1" ]]; then + summery="$summery""\ncompression level: $compression" + call="$call --level $compression" + break + fi +done + +# ===Chapters=== +while true; do + clear; echo -e "$summery" + read -p "chapters (yes/no/chapternumber to continue with): " chapters + if [[ ${chapters} =~ $isnum ]]; then summery="$summery""\nchapters: $chapters"; call="$call -c --continue ${chapters}"; break + elif [[ "$chapters" = "yes" ]] ; then summery="$summery""\nchapters: $chapters"; call="$call -c"; break + elif [[ "$chapters" = "no" ]] ; then summery="$summery""\nchapters: $chapters"; call="$call -s"; break + fi +done + +# ===Authcode=== +if ! [ -r .authcode ] || [ -r ~/.authcode ]; then + clear; echo -e "$summery" + read -p "Authcode: " authcode + summery="$summery""\nauthcode: $authcode" + call="$call -A $authcode" +fi + +# ===Loglevel=== +while true; do + clear; echo -e "$summery" + read -p "loglevel (0/1/2/3): " loglevel + if [[ ${loglevel} =~ $isnum ]] && [[ "$((${loglevel} > -1))" == "1" ]] && [[ "$((${loglevel} < 4))" == "1" ]]; then + summery="$summery""\nloglevel: $loglevel" + call="$call -l $loglevel" + break + fi +done + +# ===File=== +clear; echo -e "$summery" +read -p "aax-file: " file +summery="$summery""\naax-file: $file" +call="$call $(echo $file | sed "s;~;$HOME;")" + +# ===Summerize chosen options and call AAXtoMP3=================================================================================================== + +# ===Summery=== +clear; echo -e "$summery\n" +echo -e "$call\n" +# ----- + +# ===Call AAXtoMP3=== +$call From 7f2309248f5cdf132b0a7653d28ca58cdeb7f3b6 Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 2 Mar 2021 01:06:45 +0100 Subject: [PATCH 27/77] Some little improvements --- interactiveAAXtoMP3 | 103 ++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/interactiveAAXtoMP3 b/interactiveAAXtoMP3 index e5a44a9..2a3b233 100644 --- a/interactiveAAXtoMP3 +++ b/interactiveAAXtoMP3 @@ -9,56 +9,75 @@ # ===Variables==================================================================================================================================== -# Usage synopsis -usage=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n' # Help mesaage help=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n --advanced More options --help Print this message\n' -summery="" # This will contain a summery of the options allready set. +summary="" # This will contain a summary of the options allready set. call="./AAXtoMP3" # This will contain the call for AAXtoMP3. -isnum='^[0-9]+$' # This is needed to check whether a variable is a number. -advanced=0 # Toggles Advanced options on or off. +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. - * ) echo -e "$usage"; exit ;; + # 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 for AAXtoMP3===================================================================================================================== # ===Codec=== while true; do clear; read -p "codec (mp3/m4a/m4b/flac/aac/opus): " codec - if [[ "$codec" = "mp3" ]]; then summery="$summery""codec: $codec"; call="$call -e:mp3"; break - elif [[ "$codec" = "m4a" ]]; then summery="$summery""codec: $codec"; call="$call -e:m4a"; break - elif [[ "$codec" = "m4b" ]]; then summery="$summery""codec: $codec"; call="$call -e:m4b"; break - elif [[ "$codec" = "flac" ]]; then summery="$summery""codec: $codec"; call="$call --flac"; break - elif [[ "$codec" = "aac" ]]; then summery="$summery""codec: $codec"; call="$call --aac"; break - elif [[ "$codec" = "opus" ]]; then summery="$summery""codec: $codec"; call="$call --opus"; break - fi + 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 "$summery" - if [[ "$codec" = "mp3" ]]; then maxlevel=9 - elif [[ "$codec" = "flac" ]]; then maxlevel=12 - elif [[ "$codec" = "opus" ]]; then maxlevel=10 - else break - fi + clear; echo -e "$summary" + case "$codec" in + mp3 ) maxlevel=9;; + flac ) maxlevel=12;; + opus ) maxlevel=10;; + * ) break;; + esac read -p "compression level (0-$maxlevel): " compression - if [[ ${compression} =~ $isnum ]] && [[ "$((${compression} > -1))" == "1" ]] && [[ "$((${compression} < ${maxlevel}+1))" == "1" ]]; then - summery="$summery""\ncompression level: $compression" + if [[ $compression =~ ^[0-9]+$ ]] && [[ "$compression" -ge "0" ]] && [[ "$compression" -le "$maxlevel" ]]; then + summary="$summary""\ncompression level: $compression" call="$call --level $compression" break fi @@ -66,45 +85,45 @@ done # ===Chapters=== while true; do - clear; echo -e "$summery" + clear; echo -e "$summary" read -p "chapters (yes/no/chapternumber to continue with): " chapters - if [[ ${chapters} =~ $isnum ]]; then summery="$summery""\nchapters: $chapters"; call="$call -c --continue ${chapters}"; break - elif [[ "$chapters" = "yes" ]] ; then summery="$summery""\nchapters: $chapters"; call="$call -c"; break - elif [[ "$chapters" = "no" ]] ; then summery="$summery""\nchapters: $chapters"; call="$call -s"; break - fi + 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 "$summery" + clear; echo -e "$summary" read -p "Authcode: " authcode - summery="$summery""\nauthcode: $authcode" + summary="$summary""\nauthcode: $authcode" call="$call -A $authcode" fi # ===Loglevel=== while true; do - clear; echo -e "$summery" + clear; echo -e "$summary" read -p "loglevel (0/1/2/3): " loglevel - if [[ ${loglevel} =~ $isnum ]] && [[ "$((${loglevel} > -1))" == "1" ]] && [[ "$((${loglevel} < 4))" == "1" ]]; then - summery="$summery""\nloglevel: $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 "$summery" +clear; echo -e "$summary" read -p "aax-file: " file -summery="$summery""\naax-file: $file" -call="$call $(echo $file | sed "s;~;$HOME;")" +summary="$summary""\naax-file: $file" +call="$call $(echo $file | $SED "s;~;$HOME;")" # ===Summerize chosen options and call AAXtoMP3=================================================================================================== -# ===Summery=== -clear; echo -e "$summery\n" +# ===Summary=== +clear; echo -e "$summary\n" echo -e "$call\n" -# ----- # ===Call AAXtoMP3=== $call From 4dfb59e09157619015345c1d946aec93a51b5bea Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 2 Mar 2021 01:28:47 +0100 Subject: [PATCH 28/77] Updated README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3c319a4..52595b1 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,10 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ``` bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level ] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-n|--no-clobber] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [-d|--debug] [-h|--help] [--continue ] ... ``` +or if you want to get guided through the options +``` +bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] +``` * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! From 4537c7d01d93d411ba30924714f9d8f59b2b144b Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 2 Mar 2021 01:51:12 +0100 Subject: [PATCH 29/77] Just a little correction regarding sed --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e9f4eeb..3838c98 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -684,7 +684,7 @@ do #ffmpeg version 4+ and on the output for all older versions. split_input="" split_output="" - if [ "$(($(ffmpeg -version | sed -E 's/[^0-9]*([0-9]).*/\1/g;1q') > 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}" From 88c9b1701fd233574bfcf5a2d8daa0ee851107ee Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 9 Mar 2021 22:26:48 +0100 Subject: [PATCH 30/77] 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. --- interactiveAAXtoMP3 | 48 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/interactiveAAXtoMP3 b/interactiveAAXtoMP3 index 2a3b233..a9495d9 100644 --- a/interactiveAAXtoMP3 +++ b/interactiveAAXtoMP3 @@ -9,7 +9,7 @@ # ===Variables==================================================================================================================================== -# Help mesaage +# Help message help=$'\nUsage: interactiveAAXtoMP3 [--advanced] [--help]\n --advanced More options --help Print this message\n' @@ -22,11 +22,11 @@ advanced=0 # Toggles advanced options on or off. while true; do case "$1" in # Advanced options. - -a | --advanced ) advanced=1; shift ;; + -a | --advanced ) advanced=1; shift ;; # Command synopsis. - -h | --help ) echo -e "$help"; exit ;; + -h | --help ) echo -e "$help"; exit ;; # Anything else stops command line processing. - * ) break ;; + * ) break ;; esac done @@ -50,12 +50,36 @@ if ! [[ $(type -P "$SED") ]]; then 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 "interactive.txt" ]; then + for ((i=1;i<=$(wc -l interactive.txt | cut -d " " -f 1);i++)) do + line=$(head -$i interactive.txt | 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 interactive.txt; exit 1;; + esac + done +fi + # ===Get options for AAXtoMP3===================================================================================================================== # ===Codec=== while true; do clear; - read -p "codec (mp3/m4a/m4b/flac/aac/opus): " codec + 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;; @@ -75,7 +99,7 @@ while true; do opus ) maxlevel=10;; * ) break;; esac - read -p "compression level (0-$maxlevel): " compression + 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" @@ -86,7 +110,7 @@ done # ===Chapters=== while true; do clear; echo -e "$summary" - read -p "chapters (yes/no/chapternumber to continue with): " chapters + 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;; @@ -97,7 +121,7 @@ done # ===Authcode=== if ! [ -r .authcode ] || [ -r ~/.authcode ]; then clear; echo -e "$summary" - read -p "Authcode: " authcode + read -e -p "Authcode: " -i "$lastauthcode" authcode summary="$summary""\nauthcode: $authcode" call="$call -A $authcode" fi @@ -105,7 +129,7 @@ fi # ===Loglevel=== while true; do clear; echo -e "$summary" - read -p "loglevel (0/1/2/3): " loglevel + 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" @@ -116,6 +140,9 @@ 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;")" @@ -125,5 +152,8 @@ call="$call $(echo $file | $SED "s;~;$HOME;")" clear; echo -e "$summary\n" echo -e "$call\n" +# ===Save chosen options=== +echo -e $savefile | $SED "s;\ level:;:;" > interactive.txt + # ===Call AAXtoMP3=== $call From 2206cf9dd8f8c7b2f827a19bcbb6732b4cb958f0 Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 9 Mar 2021 22:44:26 +0100 Subject: [PATCH 31/77] Updated Readme.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 52595b1..00a45b0 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **<AAX INPUT_FILES>**... 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. @@ -62,6 +62,11 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--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. +## 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). From 051f37b3ffa87e90013a7ca70723e7da0093a37e Mon Sep 17 00:00:00 2001 From: Nicko98 <39709875+Nicko98@users.noreply.github.com> Date: Tue, 9 Mar 2021 22:49:54 +0100 Subject: [PATCH 32/77] Made savefile invisible --- interactiveAAXtoMP3 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interactiveAAXtoMP3 b/interactiveAAXtoMP3 index a9495d9..f3e4223 100644 --- a/interactiveAAXtoMP3 +++ b/interactiveAAXtoMP3 @@ -60,16 +60,16 @@ lastauthcode="" lastloglevel="1" # ===Get Values from last time=== -if [ -f "interactive.txt" ]; then - for ((i=1;i<=$(wc -l interactive.txt | cut -d " " -f 1);i++)) do - line=$(head -$i interactive.txt | tail -1) +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 interactive.txt; exit 1;; + * ) rm .interactivesave; exit 1;; esac done fi @@ -153,7 +153,7 @@ clear; echo -e "$summary\n" echo -e "$call\n" # ===Save chosen options=== -echo -e $savefile | $SED "s;\ level:;:;" > interactive.txt +echo -e $savefile | $SED "s;\ level:;:;" > .interactivesave # ===Call AAXtoMP3=== $call From eff626ee95d5c2c261bfda1e4612f3db047066eb Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 10 Jul 2021 21:20:43 +0200 Subject: [PATCH 33/77] 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 34/77] --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 35/77] 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 36/77] 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 37/77] 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 38/77] 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 39/77] 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 40/77] 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 41/77] 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 42/77] 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 From 5ea4bd10a412baab6d9d055601d2926bd1fe87a4 Mon Sep 17 00:00:00 2001 From: KrumpetPirate Date: Fri, 3 Sep 2021 13:25:30 -0400 Subject: [PATCH 43/77] Update for GNU find, README cleanup --- AAXtoMP3 | 24 +++++++++++++++++++++--- README.md | 27 +++++++++++---------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index e5f6a96..adc91ef 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -202,9 +202,19 @@ debug_vars "Command line options as set" codec extension mode container targetdi # ======================================================================== # 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." @@ -212,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." @@ -429,7 +447,7 @@ 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})" diff --git a/README.md b/README.md index 29d6430..48be47c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ 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,25 +13,19 @@ 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 +* 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 (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 +* 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 ] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-n|--no-clobber] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [-d|--debug] [-h|--help] [--continue ] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level ] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-n|--no-clobber] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [--use-audible-cli-data]] [-d|--debug] [-h|--help] [--continue ] ... ``` or if you want to get guided through the options ``` @@ -62,7 +56,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 for the files in the `aaxc` format. +* **--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. @@ -70,7 +64,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] 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] +### AUTHCODE **Your** Audible auth code (it won't correctly decode otherwise) (not required to decode the `aaxc` format). #### Determining your own AUTHCODE @@ -200,6 +194,7 @@ __MacOS__ brew install ffmpeg brew install gnu-sed brew install grep +brew install findutils ``` #### mp4art/mp4chaps From 56ca165063517ac9f25301235ff9378f865a4bda Mon Sep 17 00:00:00 2001 From: Stefan Weiberg <2744377+suntorytimed@users.noreply.github.com> Date: Thu, 16 Sep 2021 07:10:49 +0200 Subject: [PATCH 44/77] Fix #172 by adding parsing step to save_metadata * creates a correctly formatted chapter.txt file with titles from audible-cli .json * uses this chapter.txt instead of ffprobe output in case audible-cli data should be used --- AAXtoMP3 | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index adc91ef..150db65 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -381,6 +381,13 @@ trap 'rm -r -f "${working_directory}"' EXIT # Set up some basic working files ASAP. Note the trap will clean this up no matter what. working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` metadata_file="${working_directory}/metadata.txt" +# Creating a temp file to store the chapter data collected in save_metadata, as the output +# folder will only be defined after save_metadata has been executed. +# This file is only required when using audible-cli data and executing in single mode to +# get proper chapter titles in single file m4b output. +if [[ "${audibleCli}" == "1" && "${mode}" == "single" ]] ; then + tmp_chapter_file="${working_directory}/chapter.txt" +fi # ----- # Validate the AAX and extract the metadata associated with the file. @@ -510,6 +517,18 @@ save_metadata() { # 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" + # In case we want to use a single file m4b we need to extract the + # chapter titles from the .json generated by audible–cli and store + # them correctly formatted for mp4chaps in a chapter.txt + if [ "${mode}" == "single" ]; then + jq -r \ + 'def pad(n): tostring | if (n > length) then ((n - length) * "0") + . else . end; + .content_metadata.chapter_info.chapters | + to_entries | + .[] | + "CHAPTER\((.key | pad(2)))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) +CHAPTER\((.key | pad(2)))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" + fi fi debug "Metadata file $metadata_file" debug_file "$metadata_file" @@ -882,8 +901,14 @@ do # Perform file tasks on output file. # ---- # ffmpeg seems to copy only chapter position, not chapter names. + # use already created chapter.txt from save_metadata() in case + # audible-cli data is used else use ffprobe to extract from m4b 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}/${currentFileNameScheme}.chapters.txt" + if [ "${audibleCli}" == "1" ]; then + mv "${tmp_chapter_file}" "${output_directory}/${currentFileNameScheme}.chapters.txt" + else + 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" + fi mp4chaps -i "${output_file}" fi fi From aab2045959466ee70c47ee9cae07d0f8dc210092 Mon Sep 17 00:00:00 2001 From: Stefan Weiberg <2744377+suntorytimed@users.noreply.github.com> Date: Thu, 16 Sep 2021 11:46:43 +0200 Subject: [PATCH 45/77] Remove padding for chapter number Co-authored-by: fabh2o --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 150db65..690a796 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -526,7 +526,7 @@ save_metadata() { .content_metadata.chapter_info.chapters | to_entries | .[] | - "CHAPTER\((.key | pad(2)))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) + "CHAPTER\((.key))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) CHAPTER\((.key | pad(2)))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" fi fi From e76b5442c13a776e54ec1c5473a01c7446fb6593 Mon Sep 17 00:00:00 2001 From: Stefan Weiberg <2744377+suntorytimed@users.noreply.github.com> Date: Thu, 16 Sep 2021 11:47:20 +0200 Subject: [PATCH 46/77] Apply suggestions from code review Remove padding for chapter number Co-authored-by: fabh2o --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 690a796..a77242a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -527,7 +527,7 @@ save_metadata() { to_entries | .[] | "CHAPTER\((.key))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) -CHAPTER\((.key | pad(2)))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" +CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" fi fi debug "Metadata file $metadata_file" @@ -907,7 +907,7 @@ do if [ "${audibleCli}" == "1" ]; then mv "${tmp_chapter_file}" "${output_directory}/${currentFileNameScheme}.chapters.txt" else - 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" + ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt" fi mp4chaps -i "${output_file}" fi From fb86d4291cdf2e2b31531d501fac3718975b0d5b Mon Sep 17 00:00:00 2001 From: fabh2o Date: Mon, 20 Sep 2021 23:05:15 +0200 Subject: [PATCH 47/77] instruction to update ffmpeg --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 48be47c..ba288b3 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,11 @@ sudo apt-get update sudo apt-get install ffmpeg libav-tools x264 x265 bc ``` +In Debian-based system's repositories the ffmpeg version is often outdated. If you want +to convert .aaxc files, you need at least ffmpeg 4.4. So if your installed version +needs to be updated, you can either install a custom repository that has the newer version, +compile ffmpeg from source or download pre-compiled binaries. + __Fedora__ Fedora users need to enable the rpm fusion repository to install ffmpeg. Version 22 and upwards are currently supported. The following command works independent of your current version: From 58ecfbc72b4dc1df753ec1233e4f006e2fb418a5 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 26 Sep 2021 18:28:59 +0200 Subject: [PATCH 48/77] remove useless / in output_folder definition --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index a77242a..be49717 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -658,9 +658,9 @@ do # If we defined a target directory, use it. Otherwise use the location of the AAX file if [ "x${targetdir}" != "x" ] ; then - output_directory="${targetdir}/${currentDirNameScheme}/" + output_directory="${targetdir}/${currentDirNameScheme}" else - output_directory="$(dirname "${aax_file}")/${currentDirNameScheme}/" + output_directory="$(dirname "${aax_file}")/${currentDirNameScheme}" fi # Define the output_file From 68a91bbbbbaf3df3b78c9637f7f003e25f3bd458 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 26 Sep 2021 18:30:44 +0200 Subject: [PATCH 49/77] --aac is identical to -e:m4a --- AAXtoMP3 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index be49717..1713aea 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -44,8 +44,6 @@ while true; do case "$1" in # Flac encoding -f | --flac ) codec=flac; extension=flac; mode=single; container=flac; shift ;; - # Apple m4a music format. - -a | --aac ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; # Ogg Format -o | --opus ) codec=libopus; extension=opus; container=ogg; shift ;; # If appropriate use only a single file output. @@ -55,7 +53,7 @@ while true; do # This is the same as --single option. -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; container=mp3; shift ;; # Identical to --acc option. - -e:m4a ) codec=copy; extension=m4a; mode=single; container=mp4; shift ;; + -e:m4a | -a | --aac ) codec=copy; extension=m4a; mode=single; container=mp4; shift ;; # Similar to --aac but specific to audio books -e:m4b ) codec=copy; extension=m4b; mode=single; container=mp4; shift ;; # Change the working dir from AAX directory to what you choose. From f1c4b97bc10129dc44ae845f2ddc4b82adddad64 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 28 Sep 2021 19:55:16 +0200 Subject: [PATCH 50/77] use custom path for ffmpeg/ffprobe binaries --- AAXtoMP3 | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index a77242a..67a5088 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -34,6 +34,7 @@ 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 +ffmpegPath= # Set a custom path, useful for using the updated version that supports aaxc # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -88,6 +89,8 @@ while true; do --keep-author ) keepArtist="$2"; shift 2 ;; # Author override --author ) authorOverride="$2"; shift 2 ;; + # Ffmpeg path override + --ffmpeg-path ) ffmpegPath="$2"; shift 2 ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -212,6 +215,16 @@ else SED="gsed" fi +# Use custom ffmpeg (and ffprobe) binary ( --ffmpeg-path flag) +if [ -n "$ffmpegPath" ]; then + FFMPEG="$ffmpegPath/ffmpeg" + FFPROBE="$ffmpegPath/ffprobe" +else + FFMPEG="ffmpeg" + FFPROBE="ffprobe" +fi + +debug_vars "ffmpeg/ffprobe paths" FFMPEG FFPROBE # ----- # Detect which annoying version of grep we have @@ -242,7 +255,7 @@ fi # ----- # Detect ffmpeg and ffprobe -if [[ "x$(type -P ffmpeg)" == "x" ]]; then +if [[ "x$(type -P "$FFMPEG")" == "x" ]]; then echo "ERROR ffmpeg was not found on your env PATH variable" echo "Without it, this script will break." echo "INSTALL:" @@ -255,7 +268,7 @@ fi # ----- # Detect ffmpeg and ffprobe -if [[ "x$(type -P ffprobe)" == "x" ]]; then +if [[ "x$(type -P "$FFPROBE")" == "x" ]]; then echo "ERROR ffprobe was not found on your env PATH variable" echo "Without it, this script will break." echo "INSTALL:" @@ -409,7 +422,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 - output="$(ffprobe -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)" + output="$("$FFPROBE" -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)" # If invalid then say something. if [[ $? != "0" ]] ; then @@ -422,7 +435,7 @@ validate_aax() { # This is a big test only performed when the --validate switch is passed. if [[ "${VALIDATE}" == "1" ]]; then - output="$(ffmpeg -hide_banner ${decrypt_param} -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 @@ -492,7 +505,7 @@ validate_extra_files() { save_metadata() { local media_file media_file="$1" - ffprobe -i "$media_file" 2> "$metadata_file" + "$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() @@ -693,7 +706,7 @@ do # 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 ${decrypt_param} -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))" @@ -712,8 +725,8 @@ 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 ${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}"' - 1))" == "1" ]; then log "Extracting cover into ${cover_file}..." fi - 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}" @@ -856,7 +869,7 @@ do if [ "$((${loglevel} > 1))" == "1" ]; then log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)" fi - /dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt" + "$FFPROBE" -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt" fi mp4chaps -i "${output_file}" fi From bf1f38434135feb427a66ba8f5697b27c28f4a92 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 28 Sep 2021 19:56:14 +0200 Subject: [PATCH 51/77] fix tmp_chapter_file: unbound variable --- AAXtoMP3 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 67a5088..70d5b84 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -394,13 +394,6 @@ trap 'rm -r -f "${working_directory}"' EXIT # Set up some basic working files ASAP. Note the trap will clean this up no matter what. working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` metadata_file="${working_directory}/metadata.txt" -# Creating a temp file to store the chapter data collected in save_metadata, as the output -# folder will only be defined after save_metadata has been executed. -# This file is only required when using audible-cli data and executing in single mode to -# get proper chapter titles in single file m4b output. -if [[ "${audibleCli}" == "1" && "${mode}" == "single" ]] ; then - tmp_chapter_file="${working_directory}/chapter.txt" -fi # ----- # Validate the AAX and extract the metadata associated with the file. @@ -534,6 +527,11 @@ save_metadata() { # chapter titles from the .json generated by audible–cli and store # them correctly formatted for mp4chaps in a chapter.txt if [ "${mode}" == "single" ]; then + # Creating a temp file to store the chapter data collected in save_metadata, as the output + # folder will only be defined after save_metadata has been executed. + # This file is only required when using audible-cli data and executing in single mode to + # get proper chapter titles in single file m4b output. + tmp_chapter_file="${working_directory}/chapter.txt" jq -r \ 'def pad(n): tostring | if (n > length) then ((n - length) * "0") + . else . end; .content_metadata.chapter_info.chapters | From d645e616fe65e5d2505b019f0987dc28b38c827e Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 28 Sep 2021 20:16:52 +0200 Subject: [PATCH 52/77] updated readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index ba288b3..66a72d5 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--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 info. Needed for the files in the `aaxc` format. +* **--ffmpeg-path** Set the ffmpeg/ffprobe binaries folder. Both of them must be executable and in the same folder. ## Options for interactiveAAXtoMP3 * **-a** or **--advanced** Get more options to choose. Not used right now. @@ -164,6 +165,9 @@ In Debian-based system's repositories the ffmpeg version is often outdated. If y to convert .aaxc files, you need at least ffmpeg 4.4. So if your installed version needs to be updated, you can either install a custom repository that has the newer version, compile ffmpeg from source or download pre-compiled binaries. +You can then tell AAXtoMP3 to use the compiled binaries with the `--ffmpeg-path` flag. +You need to specify the folder where the ffmpeg and ffprobe binaries are. Make sure +they are both executable. __Fedora__ @@ -244,6 +248,7 @@ 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. +Note that you need at least [ffmpeg 4.4](#FFMPEG,FFPROBE). ## Audible-cli integration Some information are not present in the AAX file. For example the chapters's From ce62e832ee4f131e8d628823b92985d312e9f858 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 28 Sep 2021 22:06:33 +0200 Subject: [PATCH 53/77] fix anchor link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66a72d5..a7d8903 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,7 @@ 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. -Note that you need at least [ffmpeg 4.4](#FFMPEG,FFPROBE). +Note that you need at least [ffmpeg 4.4](#ffmpegffprobe). ## Audible-cli integration Some information are not present in the AAX file. For example the chapters's From a45c6245fec2af62f99f1663c620956c829944d6 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Mon, 8 Nov 2021 10:50:52 +0100 Subject: [PATCH 54/77] delete '/' and ':' from chapter names --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index f567698..d5a80a1 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -518,9 +518,9 @@ save_metadata() { # 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. + # Then we delete all ':' and '/' 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" + | $SED 's@[:/]@@g' >> "$metadata_file" # In case we want to use a single file m4b we need to extract the # chapter titles from the .json generated by audible–cli and store # them correctly formatted for mp4chaps in a chapter.txt From ab91343dd56dbca8ce26fb49e66b3fd470692bc8 Mon Sep 17 00:00:00 2001 From: Nate Bohman Date: Tue, 9 Nov 2021 11:36:23 -0700 Subject: [PATCH 55/77] Add extra_crop_cover to All Odd Cover Widths When attempting to convert https://www.audible.com/pd/Stephen-Fry-Presents-a-Selection-of-Anton-Chekhovs-Short-Stories-Audiobook/B0036GPPWS using this tool and chaptered mode, ffmpeg fails out with [libx264 @ 0x5588ef28d780] width not divisible by 2 (483x500) Error initializing output stream 0:1 -- Error while opening encoder for output stream #0:1 - maybe incorrect parameters such as bit_rate, rate, width or height Conversion failed! This is because the cover file embedded in the downloaded mp4 file from Audible has the dimensions 483x500. Found the extra_crop_cover that's currently being used only for covers from the Audible CLI tool and extended the script to instead check the dimensions of the cover file and include the extra_crop_cover anytime the cover has an odd width. --- AAXtoMP3 | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index d5a80a1..028ccfc 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -751,7 +751,6 @@ do fi # Grab the cover art if available. cover_file="${output_directory}/cover.jpg" - extra_crop_cover='' if [ "${continue}" == "0" ]; then if [ "${audibleCli}" == "1" ]; then # We have a better quality cover file, copy it. @@ -759,12 +758,6 @@ do 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 @@ -774,6 +767,18 @@ do fi fi + extra_crop_cover='' + cover_width=$(ffprobe -i "${cover_file}" 2>&1 | grep -Po "[0-9]+(?=x[0-9]+)") + if [ "$(( ${cover_width} % 2 ))" == "1" ]; then + if [ "$((${loglevel} > 1))" == "1" ]; then + log "Cover ${cover_file} has odd width ${cover_width}, setting extra_crop_cover to make even." + fi + # 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. + # Set the flag only if we use a cover art with an odd width. + extra_crop_cover='-vf crop=trunc(iw/2)*2:trunc(ih/2)*2' + fi + # ----- # 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) From 12435d3e24eab18a00a21d9e917b0b0a26e952b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerome=20K=C3=BCttner?= <12213711+jkuettner@users.noreply.github.com> Date: Fri, 7 Jan 2022 17:48:04 +0100 Subject: [PATCH 56/77] Continue if target directory already exists --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index d5a80a1..d767858 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -682,8 +682,8 @@ do output_file="${output_directory}/${currentFileNameScheme}.${extension}" if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then - log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" - exit 0 + log "Noclobber enabled but directory '${output_directory}' exists. Skipping to avoid overwriting" + continue fi mkdir -p "${output_directory}" From 45fd0d4852644343f854e453359db234d33533a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerome=20K=C3=BCttner?= <12213711+jkuettner@users.noreply.github.com> Date: Fri, 7 Jan 2022 20:58:54 +0100 Subject: [PATCH 57/77] remove temp metadata_file on continue --- AAXtoMP3 | 1 + 1 file changed, 1 insertion(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index d767858..9c0b8a8 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -683,6 +683,7 @@ do if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Skipping to avoid overwriting" + rm -f "${metadata_file}" continue fi mkdir -p "${output_directory}" From 7f1f3df0206e057d30a18251ce600c08f4334f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerome=20K=C3=BCttner?= <12213711+jkuettner@users.noreply.github.com> Date: Sat, 8 Jan 2022 16:38:29 +0100 Subject: [PATCH 58/77] Add possibility to read the series from the audible library --- AAXtoMP3 | 33 ++++++++++++++++++++++++++++++++- README.md | 5 +++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 1fcbc58..5139adb 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] [--audible-cli-library-file ] [--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. @@ -35,6 +35,7 @@ audibleCli=0 # Default off, Use additional data gathered from mkb aaxc_key= # Initialize variables, in case we need them in debug_vars aaxc_iv= # Initialize variables, in case we need them in debug_vars ffmpegPath= # Set a custom path, useful for using the updated version that supports aaxc +library_file= # Libraryfile generated by mkb79/audible-cli # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -81,6 +82,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 ;; + # Path of the library-file, generated by mkb79/audible-cli (audible library export -o ./library.tsv) + -L | --audible-cli-library-file ) library_file="$2"; shift 2 ;; # Compression level --level ) level="$2"; shift 2 ;; # Keep author number n @@ -488,6 +491,15 @@ validate_extra_files() { return 1 fi + # Test for library file + if [[ ! -r "${library_file}" ]] ; then + library_file_exists=0 + debug "library file not found" + else + library_file_exists=1 + debug "library file found" + fi + debug "All expected audible-cli related file are here" } @@ -538,6 +550,21 @@ save_metadata() { "CHAPTER\((.key))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" fi + + # get extra meta data from library.tsv + if [[ "${library_file_exists}" == 1 ]]; then + asin=$(jq -r '.content_metadata.content_reference.asin' "${extra_chapter_file}") + if [[ ! -z "${asin}" ]]; then + lib_entry=$(grep "^${asin}" "${library_file}") + if [[ ! -z "${lib_entry}" ]]; then + series_title=$(echo "${lib_entry}" | awk -F '\t' '{print $6}') + series_sequence=$(echo "${lib_entry}" | awk -F '\t' '{print $7}') + sed -i "/^ Metadata:/a\\ + series : ${series_title}\\ + series_sequence : ${series_sequence}" "${metadata_file}" + fi + fi + fi fi debug "Metadata file $metadata_file" debug_file "$metadata_file" @@ -645,6 +672,8 @@ do album="$(get_metadata_value album)" album_date="$(get_metadata_value date)" copyright="$(get_metadata_value copyright)" + series="$(get_metadata_value series)" + series_sequence="$(get_metadata_value series_sequence)" # Get more tags with mediainfo if [[ $(type -P mediainfo) ]]; then @@ -743,6 +772,8 @@ do -metadata description="${description}" \ -metadata composer="${narrator}" \ -metadata publisher="${publisher}" \ + -metadata series="${series}" \ + -metadata series_sequence="${series_sequence}" \ -f ${container} \ "${output_file}" if [ "$((${loglevel} > 0))" == "1" ]; then diff --git a/README.md b/README.md index a7d8903..c26d84e 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--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 info. Needed for the files in the `aaxc` format. +* **--audible-cli-library-file** or **-L** Path of the library-file, generated by mkb79/audible-cli (`audible library export -o ./library.tsv`). Only available if `--use-audible-cli-data` is set. This file is required to parse additional metadata such as `$series` or `$series_sequence`. * **--ffmpeg-path** Set the ffmpeg/ffprobe binaries folder. Both of them must be executable and in the same folder. ## Options for interactiveAAXtoMP3 @@ -151,6 +152,10 @@ So you can use `--dir-naming-scheme '$(date +%Y)/$artist'`, but using `--file-na * If you want shorter chapter names, use `--chapter-naming-scheme '$(printf %0${#chaptercount}d $chapternum) $chapter'`: only chapter number and chapter name * If you want to append the narrator name to the title, use `--dir-naming-scheme '$genre/$artist/$title-$narrator' --file-naming-scheme '$title-$narrator'` * If you don't want to have the books separated by author, use `--dir-naming-scheme '$genre/$title'` +* To be able to use `$series` or `$series_sequence` in the schemes the following is required: + * `--use-audible-cli-data` is set + * you have pre-generated the library-file via `audible library export -o ./library.tsv` + * you have set the path to the generated library-file via `--audible-cli-library-file ./library.tsv` ### Installing Dependencies. In general, take a look at [command-not-found.com](https://command-not-found.com/) From b87b08ee6af8432d5c3658e24d8a2efd813352af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerome=20K=C3=BCttner?= <12213711+jkuettner@users.noreply.github.com> Date: Sat, 8 Jan 2022 21:13:28 +0100 Subject: [PATCH 59/77] fix continuing for existing files --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 5139adb..3b8cb9f 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -712,7 +712,7 @@ do if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Skipping to avoid overwriting" - rm -f "${metadata_file}" + rm -f "${metadata_file}" "${tmp_chapter_file}" continue fi mkdir -p "${output_directory}" From 5010927559bccb7b4ea5f387b8d49052967970ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerome=20K=C3=BCttner?= <12213711+jkuettner@users.noreply.github.com> Date: Sat, 8 Jan 2022 21:45:03 +0100 Subject: [PATCH 60/77] fix "syntax error in expression" --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 3b8cb9f..2a88bd1 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -801,7 +801,7 @@ do extra_crop_cover='' cover_width=$(ffprobe -i "${cover_file}" 2>&1 | grep -Po "[0-9]+(?=x[0-9]+)") - if [ "$(( ${cover_width} % 2 ))" == "1" ]; then + if (( ${cover_width} % 2 == 1 )); then if [ "$((${loglevel} > 1))" == "1" ]; then log "Cover ${cover_file} has odd width ${cover_width}, setting extra_crop_cover to make even." fi From 048e15a476c81479be85671283e7ee77be568ab1 Mon Sep 17 00:00:00 2001 From: Ben Saufley Date: Wed, 12 Jan 2022 00:12:20 -0500 Subject: [PATCH 61/77] Use GREP variable everywhere --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 2a88bd1..bd2c94b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -555,7 +555,7 @@ CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_ if [[ "${library_file_exists}" == 1 ]]; then asin=$(jq -r '.content_metadata.content_reference.asin' "${extra_chapter_file}") if [[ ! -z "${asin}" ]]; then - lib_entry=$(grep "^${asin}" "${library_file}") + lib_entry=$($GREP "^${asin}" "${library_file}") if [[ ! -z "${lib_entry}" ]]; then series_title=$(echo "${lib_entry}" | awk -F '\t' '{print $6}') series_sequence=$(echo "${lib_entry}" | awk -F '\t' '{print $7}') @@ -800,7 +800,7 @@ do fi extra_crop_cover='' - cover_width=$(ffprobe -i "${cover_file}" 2>&1 | grep -Po "[0-9]+(?=x[0-9]+)") + cover_width=$(ffprobe -i "${cover_file}" 2>&1 | $GREP -Po "[0-9]+(?=x[0-9]+)") if (( ${cover_width} % 2 == 1 )); then if [ "$((${loglevel} > 1))" == "1" ]; then log "Cover ${cover_file} has odd width ${cover_width}, setting extra_crop_cover to make even." From 20289a17741d6eebe73be8eda73424d1516bb0c0 Mon Sep 17 00:00:00 2001 From: Ben Saufley Date: Wed, 12 Jan 2022 00:28:52 -0500 Subject: [PATCH 62/77] One sed/gsed as well --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index bd2c94b..7e0f55c 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -559,7 +559,7 @@ CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_ if [[ ! -z "${lib_entry}" ]]; then series_title=$(echo "${lib_entry}" | awk -F '\t' '{print $6}') series_sequence=$(echo "${lib_entry}" | awk -F '\t' '{print $7}') - sed -i "/^ Metadata:/a\\ + $SED -i "/^ Metadata:/a\\ series : ${series_title}\\ series_sequence : ${series_sequence}" "${metadata_file}" fi From 4dd095da2a663e7c79f538c4ec22acbb804b5bc7 Mon Sep 17 00:00:00 2001 From: Ben Saufley Date: Wed, 12 Jan 2022 09:34:59 -0500 Subject: [PATCH 63/77] Attempt to fix missing cover art for single output Solves #191 for me anecdotaly, but I don't know if there's a better solution or a different way to go about it. --- AAXtoMP3 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index 2a88bd1..eba3821 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -959,6 +959,11 @@ do fi fi + if [ -f "${cover_file}" ]; then + if [ "$loglevel" -gt 1 ]; then log "Adding cover art"; fi + mp4art --add "${cover_file}" "${output_file}" + fi + # ----- # Announce that we have completed the transcode if [ "$((${loglevel} > 0))" == "1" ]; then From e4f92461d3f07c305f460c5bc7369e9a8b5e7964 Mon Sep 17 00:00:00 2001 From: Max Zangs Date: Thu, 20 Jan 2022 11:45:49 +0100 Subject: [PATCH 64/77] Changing uses of `grep` to `$GREP` for non-linux --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 2a88bd1..bd2c94b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -555,7 +555,7 @@ CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_ if [[ "${library_file_exists}" == 1 ]]; then asin=$(jq -r '.content_metadata.content_reference.asin' "${extra_chapter_file}") if [[ ! -z "${asin}" ]]; then - lib_entry=$(grep "^${asin}" "${library_file}") + lib_entry=$($GREP "^${asin}" "${library_file}") if [[ ! -z "${lib_entry}" ]]; then series_title=$(echo "${lib_entry}" | awk -F '\t' '{print $6}') series_sequence=$(echo "${lib_entry}" | awk -F '\t' '{print $7}') @@ -800,7 +800,7 @@ do fi extra_crop_cover='' - cover_width=$(ffprobe -i "${cover_file}" 2>&1 | grep -Po "[0-9]+(?=x[0-9]+)") + cover_width=$(ffprobe -i "${cover_file}" 2>&1 | $GREP -Po "[0-9]+(?=x[0-9]+)") if (( ${cover_width} % 2 == 1 )); then if [ "$((${loglevel} > 1))" == "1" ]; then log "Cover ${cover_file} has odd width ${cover_width}, setting extra_crop_cover to make even." From 2272d9ce99787a3b92cc79916c2aa0ccffea0afb Mon Sep 17 00:00:00 2001 From: Max Zangs Date: Thu, 20 Jan 2022 11:59:10 +0100 Subject: [PATCH 65/77] Fixing `,000` issue with mp4chaps Replaces the `,000` in the chapters.txt file with `.000` to allow processing with `mp4chaps` --- AAXtoMP3 | 1 + 1 file changed, 1 insertion(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index 2a88bd1..e943cd1 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -955,6 +955,7 @@ do else "$FFPROBE" -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt" fi + $SED -i 's/\,000/\.000/' "${output_directory}/${currentFileNameScheme}.chapters.txt" mp4chaps -i "${output_file}" fi fi From aa702cb97a6f4125d1fee1112bbd3676fc814587 Mon Sep 17 00:00:00 2001 From: Ben Saufley Date: Fri, 21 Jan 2022 17:09:43 -0500 Subject: [PATCH 66/77] Remove redundant loglevel check --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index eba3821..bb55dc0 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -960,7 +960,7 @@ do fi if [ -f "${cover_file}" ]; then - if [ "$loglevel" -gt 1 ]; then log "Adding cover art"; fi + log "Adding cover art" mp4art --add "${cover_file}" "${output_file}" fi From 72794b678545faf37e083ee5975bf986ef9a6a88 Mon Sep 17 00:00:00 2001 From: jcat Date: Sat, 5 Feb 2022 23:30:14 +0000 Subject: [PATCH 67/77] feat: Use ffmpeg to cover add instead of mp4art from deprecated mp4v2-utils package closes: https://github.com/KrumpetPirate/AAXtoMP3/issues/198 --- AAXtoMP3 | 18 +++++++++++++++++- README.md | 19 ------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 8eff27b..25feb46 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -962,7 +962,23 @@ do if [ -f "${cover_file}" ]; then log "Adding cover art" - mp4art --add "${cover_file}" "${output_file}" + # Create temporary output file name - ensure extention matches previous appropriate output file to keep ffmpeg happy + cover_output_file="${output_file%.*}.cover.${output_file##*.}" + # Copy audio stream from current output, and video stream from cover file, setting appropriate metadata + Date: Sun, 6 Feb 2022 00:03:57 +0000 Subject: [PATCH 68/77] feat: Add support for ffmpeg via snap package, requires ability to specify custom ffmpeg binary names if required closes: https://github.com/KrumpetPirate/AAXtoMP3/issues/200 --- AAXtoMP3 | 14 ++++++++++---- README.md | 8 ++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 8eff27b..9b7b07b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -35,6 +35,8 @@ audibleCli=0 # Default off, Use additional data gathered from mkb aaxc_key= # Initialize variables, in case we need them in debug_vars aaxc_iv= # Initialize variables, in case we need them in debug_vars ffmpegPath= # Set a custom path, useful for using the updated version that supports aaxc +ffmpegName=ffmpeg # Set a custom ffmpeg binary name, useful tailoring to local setup +ffprobeName=ffprobe # Set a custom ffprobe binary name, useful tailoring to local setup library_file= # Libraryfile generated by mkb79/audible-cli # ----- @@ -92,6 +94,10 @@ while true; do --author ) authorOverride="$2"; shift 2 ;; # Ffmpeg path override --ffmpeg-path ) ffmpegPath="$2"; shift 2 ;; + # Ffmpeg name override + --ffmpeg-name ) ffmpegName="$2"; shift 2 ;; + # Ffprobe name override + --ffprobe-name ) ffprobeName="$2"; shift 2 ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -218,11 +224,11 @@ fi # Use custom ffmpeg (and ffprobe) binary ( --ffmpeg-path flag) if [ -n "$ffmpegPath" ]; then - FFMPEG="$ffmpegPath/ffmpeg" - FFPROBE="$ffmpegPath/ffprobe" + FFMPEG="$ffmpegPath/${ffmpegName}" + FFPROBE="$ffmpegPath/${ffprobeName}" else - FFMPEG="ffmpeg" - FFPROBE="ffprobe" + FFMPEG="${ffmpegName}" + FFPROBE="${ffprobeName}" fi debug_vars "ffmpeg/ffprobe paths" FFMPEG FFPROBE diff --git a/README.md b/README.md index c26d84e..36e6d5e 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help] * **--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. * **--audible-cli-library-file** or **-L** Path of the library-file, generated by mkb79/audible-cli (`audible library export -o ./library.tsv`). Only available if `--use-audible-cli-data` is set. This file is required to parse additional metadata such as `$series` or `$series_sequence`. * **--ffmpeg-path** Set the ffmpeg/ffprobe binaries folder. Both of them must be executable and in the same folder. +* **--ffmpeg-name** Set a custom name for the ffmpeg binary. Must be executable and in path, or in custom path specified by --ffmpeg-path. +* **--ffprobe-name** Set a custom name for the ffprobe binary. Must be executable and in path, or in custom path specified by --ffmpeg-path. ## Options for interactiveAAXtoMP3 * **-a** or **--advanced** Get more options to choose. Not used right now. @@ -174,6 +176,12 @@ You can then tell AAXtoMP3 to use the compiled binaries with the `--ffmpeg-path` You need to specify the folder where the ffmpeg and ffprobe binaries are. Make sure they are both executable. +If you have snapd installed, you can also install a recent version of 4.4 from the edge channel: +``` +snap install ffmpeg --edge +``` +In this case you will need to confiure a custom path _and_ binary name for ffprobe, `--ffmpeg-path /snap/bin/ --ffprobe-name ffmpeg.ffprobe`. + __Fedora__ Fedora users need to enable the rpm fusion repository to install ffmpeg. Version 22 and upwards are currently supported. The following command works independent of your current version: From b07737f5c40c6da0ea76a3b2af47e892f608f56d Mon Sep 17 00:00:00 2001 From: jcat Date: Sun, 6 Feb 2022 20:29:20 +0000 Subject: [PATCH 69/77] fix: video stream metadata for front cover comment should be lower case _front_ --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 8eff27b..bbc9927 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -913,7 +913,7 @@ do -map 1:0 \ -acodec ${chapter_codec} \ -metadata:s:v title="Album cover" \ - -metadata:s:v comment="Cover (Front)" \ + -metadata:s:v comment="Cover (front)" \ -metadata track="${chapternum}" \ -metadata title="${chapter}" \ -metadata:s:a title="${chapter}" \ From be8473ffbaa6df5ad7100f68884e75968446c3a0 Mon Sep 17 00:00:00 2001 From: jcat Date: Wed, 9 Feb 2022 21:01:29 +0000 Subject: [PATCH 70/77] Revert "feat: Use ffmpeg to cover add instead of mp4art from deprecated mp4v2-utils package" This reverts commit 72794b678545faf37e083ee5975bf986ef9a6a88. This broke cover art addition for MPEG-4 containers --- AAXtoMP3 | 18 +----------------- README.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 9b16c09..c03be5c 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -968,23 +968,7 @@ do if [ -f "${cover_file}" ]; then log "Adding cover art" - # Create temporary output file name - ensure extention matches previous appropriate output file to keep ffmpeg happy - cover_output_file="${output_file%.*}.cover.${output_file##*.}" - # Copy audio stream from current output, and video stream from cover file, setting appropriate metadata - Date: Wed, 9 Feb 2022 21:24:14 +0000 Subject: [PATCH 71/77] feat: Use ffmpeg for cover art on non mpeg-4 containers instead of mp4art from deprecated mp4v2-utils package Closes: https://github.com/KrumpetPirate/AAXtoMP3/issues/203 --- AAXtoMP3 | 24 +++++++++++++++++++++++- README.md | 6 +++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index c03be5c..2a10ccb 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -968,7 +968,29 @@ do if [ -f "${cover_file}" ]; then log "Adding cover art" - mp4art --add "${cover_file}" "${output_file}" + # FFMGEP does not support MPEG-4 containers fully # + if [ "${container}" == "mp4" ] ; then + mp4art --add "${cover_file}" "${output_file}" + # FFMPEG for everything else # + else + # Create temporary output file name - ensure extention matches previous appropriate output file to keep ffmpeg happy + cover_output_file="${output_file%.*}.cover.${output_file##*.}" + # Copy audio stream from current output, and video stream from cover file, setting appropriate metadata + Date: Tue, 1 Mar 2022 21:38:17 -0800 Subject: [PATCH 72/77] Fixes for jq command generating chapters.txt Fixes #184 Adds a reduce + flatten step to generate a flat list of chapters. Fixes #206 Support for emitting timestamps greater than 24 hours. --- AAXtoMP3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 2a10ccb..670f2e5 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -551,9 +551,10 @@ save_metadata() { jq -r \ 'def pad(n): tostring | if (n > length) then ((n - length) * "0") + . else . end; .content_metadata.chapter_info.chapters | + reduce .[] as $c ([]; if $c.chapters? then .+[$c | del(.chapters)]+[$c.chapters] else .+[$c] end) | flatten | to_entries | .[] | - "CHAPTER\((.key))=\(((.value.start_offset_ms / (1000*60*60)) %24 | floor | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) + "CHAPTER\((.key))=\((((((.value.start_offset_ms / (1000*60*60)) /24 | floor) *24 ) + ((.value.start_offset_ms / (1000*60*60)) %24 | floor)) | pad(2))):\(((.value.start_offset_ms / (1000*60)) %60 | floor | pad(2))):\(((.value.start_offset_ms / 1000) %60 | floor | pad(2))).\((.value.start_offset_ms % 1000 | pad(3))) CHAPTER\((.key))NAME=\(.value.title)"' "${extra_chapter_file}" > "${tmp_chapter_file}" fi From 1ac69798857ccf6e510c40c2537157c0144907ea Mon Sep 17 00:00:00 2001 From: utf8please Date: Sun, 27 Mar 2022 20:04:49 -0700 Subject: [PATCH 73/77] Limit result to one line when parsing cover size. --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 670f2e5..25999be 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -807,7 +807,7 @@ do fi extra_crop_cover='' - cover_width=$(ffprobe -i "${cover_file}" 2>&1 | $GREP -Po "[0-9]+(?=x[0-9]+)") + cover_width=$(ffprobe -i "${cover_file}" 2>&1 | $GREP -Po "[0-9]+(?=x[0-9]+)" | tail -n 1) if (( ${cover_width} % 2 == 1 )); then if [ "$((${loglevel} > 1))" == "1" ]; then log "Cover ${cover_file} has odd width ${cover_width}, setting extra_crop_cover to make even." From c289c10cd73bc57e44ebbdb71d3c6ef2fc2af931 Mon Sep 17 00:00:00 2001 From: Benjamin Porter Date: Fri, 10 Jun 2022 18:03:29 -0600 Subject: [PATCH 74/77] Fix typo in comment: FFMGEP -> FFMPEG --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 670f2e5..90566ad 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -969,7 +969,7 @@ do if [ -f "${cover_file}" ]; then log "Adding cover art" - # FFMGEP does not support MPEG-4 containers fully # + # FFMPEG does not support MPEG-4 containers fully # if [ "${container}" == "mp4" ] ; then mp4art --add "${cover_file}" "${output_file}" # FFMPEG for everything else # From 8fc5e360d34ff17a41fedda0e507f12013a03470 Mon Sep 17 00:00:00 2001 From: JarrodCColburn Date: Thu, 7 Jul 2022 17:49:45 -0500 Subject: [PATCH 75/77] fix: typo '--aac' not '-aac' usage example has 'aac' prefixed with single dash '-' (but should be double dashes '--') --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2df29d0..ee45eda 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Audible fails for some reason. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level ] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-n|--no-clobber] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [--use-audible-cli-data]] [-d|--debug] [-h|--help] [--continue ] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|--aac] [-s|--single] [--level ] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-n|--no-clobber] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [--use-audible-cli-data]] [-d|--debug] [-h|--help] [--continue ] ... ``` or if you want to get guided through the options ``` From 2a5a208a2d8245528a0d162ed4b945b404ebff7b Mon Sep 17 00:00:00 2001 From: -_- Date: Mon, 17 Oct 2022 16:54:21 +0200 Subject: [PATCH 76/77] Change cover.jpg to $currentFileNameScheme.jpg This change allow multiple covers of different audiobooks in the same target directory. --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 90566ad..5a1796b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -789,7 +789,7 @@ do # ----- fi # Grab the cover art if available. - cover_file="${output_directory}/cover.jpg" + cover_file="${output_directory}/${currentFileNameScheme}.jpg" if [ "${continue}" == "0" ]; then if [ "${audibleCli}" == "1" ]; then # We have a better quality cover file, copy it. From 1338f1e5c1a168ac150a0794a13eaaba2d3d2e08 Mon Sep 17 00:00:00 2001 From: Benjamin Porter Date: Mon, 2 Jan 2023 15:42:08 -0700 Subject: [PATCH 77/77] Fix incorrect variable name bug Fix misleading variable name. `$author` -> `$artist` This took 30 mins of head pounding to figure out what was wrong :-) --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 90566ad..2a27413 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -16,7 +16,7 @@ level=-1 # Compression level. Can be given for mp3, flac and mode=chaptered # Multi file output auth_code= # Required to be set via file or option. targetdir= # Optional output location. Note default is basedir of AAX file. -dirNameScheme= # Custom directory naming scheme, default is $genre/$author/$title +dirNameScheme= # Custom directory naming scheme, default is $genre/$artist/$title customDNS=0 fileNameScheme= # Custom file naming scheme, default is $title customFNS=0