From 176c30c42c00f5410e7721c2118a0e4da2547804 Mon Sep 17 00:00:00 2001 From: Francis Chong Date: Fri, 3 Nov 2017 11:33:21 +0800 Subject: [PATCH 01/49] add m4a conversion script --- AAXtoM4A | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100755 AAXtoM4A diff --git a/AAXtoM4A b/AAXtoM4A new file mode 100755 index 0000000..7288d08 --- /dev/null +++ b/AAXtoM4A @@ -0,0 +1,108 @@ +#!/usr/bin/env bash + +set -o errexit -o noclobber -o nounset -o pipefail + +codec=copy +extension=m4a +mode=chaptered +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 + +if [ "$#" -eq 0 ]; then + echo "Usage: bash AAXtoM4A [--single] AUTHCODE {FILES}" + exit 1 +fi + +if [[ "$1" == '--single' ]] +then + mode=single + shift +fi + +if [ ! -f .authcode ]; then + auth_code=$1 + shift +else + auth_code=`head -1 .authcode` +fi + +debug() { + echo "$(date "+%F %T%z") ${1}" +} + +trap 'rm -r -f "${working_directory}"' EXIT +working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` +metadata_file="${working_directory}/metadata.txt" + +save_metadata() { + local media_file + media_file="$1" + ffprobe -i "$media_file" 2> "$metadata_file" +} + +get_metadata_value() { + local key + key="$1" + normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" +} + +get_bitrate() { + get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' +} + +normalize_whitespace() { + echo $* +} + +for path +do + debug "Decoding ${path} with auth code ${auth_code}..." + + save_metadata "${path}" + genre=$(get_metadata_value genre) + artist=$(get_metadata_value artist) + title=$(get_metadata_value title) + output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + mkdir -p "${output_directory}" + full_file_path="${output_directory}/${title}.${extension}" + + Date: Wed, 22 Nov 2017 16:31:42 +0800 Subject: [PATCH 02/49] Convert aax to m4b --- AAXtoM4B | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100755 AAXtoM4B diff --git a/AAXtoM4B b/AAXtoM4B new file mode 100755 index 0000000..4bc0992 --- /dev/null +++ b/AAXtoM4B @@ -0,0 +1,112 @@ +#!/usr/bin/env bash + +set -o errexit -o noclobber -o nounset -o pipefail + +codec=copy +extension=m4a +mode=chaptered +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 + +if [ "$#" -eq 0 ]; then + echo "Usage: bash AAXtoM4B [--single] AUTHCODE {FILES}" + exit 1 +fi + +if [[ "$1" == '--single' ]] +then + mode=single + shift +fi + +if [ ! -f .authcode ]; then + auth_code=$1 + shift +else + auth_code=`head -1 .authcode` +fi + +debug() { + echo "$(date "+%F %T%z") ${1}" +} + +trap 'rm -r -f "${working_directory}"' EXIT +working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` +metadata_file="${working_directory}/metadata.txt" + +save_metadata() { + local media_file + media_file="$1" + ffprobe -i "$media_file" 2> "$metadata_file" +} + +get_metadata_value() { + local key + key="$1" + normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" +} + +get_bitrate() { + get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' +} + +normalize_whitespace() { + echo $* +} + +for path +do + debug "Decoding ${path} with auth code ${auth_code}..." + + save_metadata "${path}" + genre=$(get_metadata_value genre) + artist=$(get_metadata_value artist) + title=$(get_metadata_value title) + output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + mkdir -p "${output_directory}" + full_file_path="${output_directory}/${title}.${extension}" + + Date: Sun, 18 Feb 2018 17:26:45 +1100 Subject: [PATCH 03/49] Added m3u playlist support --- AAXtoMP3 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index b53bec6..293de3f 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -84,10 +84,15 @@ do debug "Created ${full_file_path}." cover_path="${output_directory}/cover.jpg" + debug "Extracting cover into ${cover_path}..." - "${playlist_file}" + chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) debug "Extracting ${chaptercount} chapter files from ${full_file_path}..." @@ -103,6 +108,10 @@ do > "${playlist_file}" + echo "${chapter_title}.${extension}" >> "${playlist_file}" chapternum=$((chapternum + 1 )) fi done 9< "$metadata_file" From ab8db09eedf6ea6ca014aadbd4d62898ffbbbdfa Mon Sep 17 00:00:00 2001 From: Mark Daku Date: Tue, 20 Feb 2018 22:27:52 +1100 Subject: [PATCH 04/49] Updating README --- README.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index dd07450..5635ed5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# AAXtoMP3 -The purpose of this software is to convert AAX files to a more common MP3 format +# AAXtoMP3 AAXtoM4A AAxtoM4B +The purpose of this software is to convert AAX files to common MP3, M4A and M4B formats through a basic bash script frontend to FFMPEG. -Audible uses this file format to maintain DRM restrictions on their audio +Audible uses this file format, AAX to maintain DRM restrictions on their audio books and if you download your book through your library it will be stored in this format. @@ -29,29 +29,34 @@ conversions in OSX. It is recommended that you install GNU grep using 'brew inst ## 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 +## Usage(s) ``` -bash AAXtoMP3 {INPUT_FILES} +bash AAXtoMP3 [--flac] [--single] [AUTHCODE] +bash AAXtoM4A [AUTHCODE] +bash AAXtoM4B [AUTHCODE] + ``` * AUTHCODE: **your** Audible auth code (it won't correctly decode otherwise) (required) * Everything else is considered an input file, useful for batching! -You can also convert the output to FLAC encoding instead of MP3 by doing the following *in order*: ``` -bash AAXtoMP3 --flac {INPUT_FILES} +MP3 Encoding + - Produces 1 or more mp3 files for the AAX title. If you desire a single file use the --single option + - If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also + be created in this instance. + - If you desire flac encoding. use the --flac option. It's a bit faster but also a bit less compatible. + ``` -Note that FLAC encoding is typically a little faster, at the cost of compatibility with some players. +M4A Encoding -If you wish to convert to a single file you can add --single to the input. This will prevent chaptered content from being extracted. +``` +M4B Encoding -Additionally, if you have a .authcode file available in the current working directory, it will read the first line of +``` +Defaults + - If you have a .authcode file available in the current working directory, it will read the first line of that line and treat it like your auth_code. When you do this you do not need to specify an AUTHCODE input. -Here is the full usage (NOTE: Order matters!) -``` -bash AAXtoMP3 [--flac] [--single] AUTHCODE {FILES} -``` - ## 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 d0eb3540edd6a3ae264308fca812d10023ff5d23 Mon Sep 17 00:00:00 2001 From: Mark Daku Date: Tue, 20 Feb 2018 22:30:34 +1100 Subject: [PATCH 05/49] Updating README --- README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5635ed5..2a36ad1 100644 --- a/README.md +++ b/README.md @@ -31,29 +31,26 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [--flac] [--single] [AUTHCODE] +bash AAXtoMP3 [--flac] [--single] [AUTHCODE]* bash AAXtoM4A [AUTHCODE] bash AAXtoM4B [AUTHCODE] - ``` + * AUTHCODE: **your** Audible auth code (it won't correctly decode otherwise) (required) * Everything else is considered an input file, useful for batching! -``` -MP3 Encoding + +### MP3 Encoding - Produces 1 or more mp3 files for the AAX title. If you desire a single file use the --single option - If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. - If you desire flac encoding. use the --flac option. It's a bit faster but also a bit less compatible. -``` -M4A Encoding +### M4A Encoding -``` -M4B Encoding +### M4B Encoding -``` -Defaults +### Defaults - If you have a .authcode file available in the current working directory, it will read the first line of that line and treat it like your auth_code. When you do this you do not need to specify an AUTHCODE input. From 8b391a0bd07e691d76c3ee1d550edee630bc3ba0 Mon Sep 17 00:00:00 2001 From: Mark Daku Date: Tue, 20 Feb 2018 22:41:55 +1100 Subject: [PATCH 06/49] Updating README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2a36ad1..e784271 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ bash AAXtoM4A [AUTHCODE] bash AAXtoM4B [AUTHCODE] ``` -* AUTHCODE: **your** Audible auth code (it won't correctly decode otherwise) (required) +* AUTHCODE: **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. * Everything else is considered an input file, useful for batching! @@ -51,8 +51,11 @@ bash AAXtoM4B [AUTHCODE] ### M4B Encoding ### Defaults - - If you have a .authcode file available in the current working directory, it will read the first line of -that line and treat it like your auth_code. When you do this you do not need to specify an AUTHCODE input. +*Specifying the AUTHCODE. +In order of precidence. +**[AUTHCODE] +**.authcode +**~/.aaxto_config ## Anti-Piracy Notice Note that this project does NOT ‘crack’ the DRM. It simply allows the user to From c4eb954e115a09240b69dbc9d12f31184a18d249 Mon Sep 17 00:00:00 2001 From: Mark Daku Date: Tue, 20 Feb 2018 22:43:02 +1100 Subject: [PATCH 07/49] Updating README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e784271..687f16d 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ bash AAXtoM4B [AUTHCODE] ### Defaults *Specifying the AUTHCODE. In order of precidence. -**[AUTHCODE] -**.authcode -**~/.aaxto_config + [AUTHCODE] + .authcode + ~/.aaxto_config ## Anti-Piracy Notice Note that this project does NOT ‘crack’ the DRM. It simply allows the user to From 5a7078bc991ef0d63a922604b212cccbfb240445 Mon Sep 17 00:00:00 2001 From: Mark Daku Date: Tue, 20 Feb 2018 22:43:54 +1100 Subject: [PATCH 08/49] Updating README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 687f16d..dfd390c 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ bash AAXtoM4B [AUTHCODE] ### Defaults *Specifying the AUTHCODE. -In order of precidence. + In order of precidence. [AUTHCODE] .authcode ~/.aaxto_config From cfaa5b94ffcd5e3be687edc6e742665319923dd9 Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 22:50:34 +1100 Subject: [PATCH 09/49] Updating README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dfd390c..9d63443 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ bash AAXtoM4B [AUTHCODE] ### Defaults *Specifying the AUTHCODE. In order of precidence. - [AUTHCODE] - .authcode - ~/.aaxto_config + 1. [AUTHCODE] + 2. .authcode + 3. ~/.aaxto_config ## Anti-Piracy Notice Note that this project does NOT ‘crack’ the DRM. It simply allows the user to From e5c45ed119f11420c6673b8dd4e366cb7f516cac Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:03:52 +1100 Subject: [PATCH 10/49] Updating README --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9d63443..15712a4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ create a method for you to download and store your books just in case Audible fails for some reason. ## Setup -You will need your four byte authentication code that comes from Audible's +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). @@ -31,13 +31,13 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [--flac] [--single] [AUTHCODE]* -bash AAXtoM4A [AUTHCODE] -bash AAXtoM4B [AUTHCODE] +bash AAXtoMP3 [--flac] [--single] [AUTHCODE] ... +bash AAXtoM4A [AUTHCODE] ... +bash AAXtoM4B [AUTHCODE] ... ``` -* AUTHCODE: **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. -* Everything else is considered an input file, useful for batching! +* [AUTHCODE]: **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. +* is considered an input file, useful for batching! ### MP3 Encoding @@ -51,7 +51,7 @@ bash AAXtoM4B [AUTHCODE] ### M4B Encoding ### Defaults -*Specifying the AUTHCODE. +* Specifying the AUTHCODE. In order of precidence. 1. [AUTHCODE] 2. .authcode From cd0e5546f4593b8a0c6dd5af82e9f22ad1d431f2 Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:10:29 +1100 Subject: [PATCH 11/49] Updating README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 15712a4..23bd419 100644 --- a/README.md +++ b/README.md @@ -52,10 +52,11 @@ bash AAXtoM4B [AUTHCODE] ... ### Defaults * Specifying the AUTHCODE. - In order of precidence. - 1. [AUTHCODE] - 2. .authcode - 3. ~/.aaxto_config + In order of __precidence__. + 1. [AUTHCODE] The command line option. With the highest precidence. + 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. ~/.aaxto_config 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 specified. The code must also match the encoding for the user that owns the AAX file(s). ## Anti-Piracy Notice Note that this project does NOT ‘crack’ the DRM. It simply allows the user to From 30cbe5d0f0f4d9556d8dc058c48fa9f44e26f0be Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:12:00 +1100 Subject: [PATCH 12/49] Updating README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 23bd419..f6cdf70 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ bash AAXtoM4B [AUTHCODE] ... ### Defaults * Specifying the AUTHCODE. In order of __precidence__. - 1. [AUTHCODE] The command line option. With the highest precidence. - 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. ~/.aaxto_config a global config file for all the tools. And is used as the default if none of the above are specified. + 1. **[AUTHCODE]** The command line option. With the highest precidence. + 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. **~/.aaxto_config** 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 specified. The code must also match the encoding for the user that owns the AAX file(s). ## Anti-Piracy Notice From 004094f8428691083637f6332bda1d22f265600b Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:13:27 +1100 Subject: [PATCH 13/49] Updating README --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f6cdf70..f3f3d60 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,9 @@ bash AAXtoM4B [AUTHCODE] ... ### MP3 Encoding - - Produces 1 or more mp3 files for the AAX title. If you desire a single file use the --single option - - If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also - be created in this instance. - - If you desire flac encoding. use the --flac option. It's a bit faster but also a bit less compatible. +1. Produces 1 or more mp3 files for the AAX title. If you desire a single file use the --single option +2. If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. +3. If you desire flac encoding. use the --flac option. It's a bit faster but also a bit less compatible. ### M4A Encoding From 639940a4974d8f7d61ddc7577efc569933fdf15d Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:16:34 +1100 Subject: [PATCH 14/49] Updating README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f3f3d60..279b833 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ bash AAXtoM4B [AUTHCODE] ... ### MP3 Encoding -1. Produces 1 or more mp3 files for the AAX title. If you desire a single file use the --single option -2. If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. -3. If you desire flac encoding. use the --flac option. It's a bit faster but also a bit less compatible. +* Produces 1 or more mp3 files for the AAX title. If you desire a single file use the **--single** option +* If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. +* If you desire flac encoding. use the **--flac** option. It's a bit faster but also a bit less compatible. ### M4A Encoding From e5d15888254fb0e6fde0d6cc51d334df2e5e5136 Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:18:25 +1100 Subject: [PATCH 15/49] Updating README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 279b833..fddabbb 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ bash AAXtoM4A [AUTHCODE] ... bash AAXtoM4B [AUTHCODE] ... ``` -* [AUTHCODE]: **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. -* is considered an input file, useful for batching! +* __[AUTHCODE]__ **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. +* ____... are considered input file(s), useful for batching! ### MP3 Encoding From 76baaac18a0f224847f00a4ddc351106794176c4 Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:19:58 +1100 Subject: [PATCH 16/49] Updating README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fddabbb..8e2b547 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ bash AAXtoM4A [AUTHCODE] ... bash AAXtoM4B [AUTHCODE] ... ``` -* __[AUTHCODE]__ **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. -* ____... are considered input file(s), useful for batching! +* **[AUTHCODE]** **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. +* ****... are considered input file(s), useful for batching! ### MP3 Encoding From 214dd5a46c70f1e136a31cb1b04170540e6589e2 Mon Sep 17 00:00:00 2001 From: upuv Date: Tue, 20 Feb 2018 23:21:19 +1100 Subject: [PATCH 17/49] Updating README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8e2b547..f4a802b 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ bash AAXtoM4B [AUTHCODE] ... ### Defaults * Specifying the AUTHCODE. In order of __precidence__. - 1. **[AUTHCODE]** The command line option. With the highest precidence. - 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. **~/.aaxto_config** a global config file for all the tools. And is used as the default if none of the above are specified. + 1. __[AUTHCODE]__ The command line option. With the highest precidence. + 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. __~/.aaxto_config__ 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 specified. The code must also match the encoding for the user that owns the AAX file(s). ## Anti-Piracy Notice From f976940798fd8bef2ca995438c35d1ca4118f433 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 15:08:57 +1000 Subject: [PATCH 18/49] getopts update --- AAXtoMP3 | 100 +++++++++++++++++++++++++++++++++++++++--------------- README.md | 6 ++-- 2 files changed, 76 insertions(+), 30 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 293de3f..143a114 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -1,10 +1,38 @@ #!/usr/bin/env bash -set -o errexit -o noclobber -o nounset -o pipefail - +# ======================================================================== +# Command Line Options +usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [--authcode ]\n[--output_dir ] {FILES}\n' codec=libmp3lame extension=mp3 mode=chaptered +auth_code= +targetdir= + +while true; do + case "$1" in + -f | --flac ) codec=flac; extension=flac; shift ;; + -a | --aac ) codec=copy; extension=m4a; mode=single ;shift ;; + -o | --opus ) codec=libopus; extension=ogg; shift ;; + -s | --single ) mode=single; shift ;; + -t | --target_dir ) targetdir="$2"; shift 2 ;; + -A | --authcode ) auth_code="$2"; shift 2 ;; + -d | --debug ) DEBUG=1; shift ;; # Not so secret flag for debug output. to use in code [ $DEBUG == 1 ] && sample=2 + -h | --help ) printf "$usage" $0 ; exit ;; + -- ) shift; break ;; + * ) break ;; + esac +done + +if [ "$#" -eq 0 ]; then + printf "$usage" $0 + exit 1 +fi + +# ======================================================================== +# Variable validation +set -o errexit -o noclobber -o nounset -o pipefail + GREP=$(grep --version | grep -q GNU && echo "grep" || echo "ggrep") if ! [[ $(type -P "$GREP") ]]; then @@ -14,30 +42,29 @@ if ! [[ $(type -P "$GREP") ]]; then exit 1 fi -if [ "$#" -eq 0 ]; then - echo "Usage: bash AAXtoMP3.sh [--flac] [--single] AUTHCODE {FILES}" - exit 1 -fi - -if [[ "$1" = '--flac' ]] -then - codec=flac - extension=flac - shift -fi - -if [[ "$1" == '--single' ]] -then - mode=single - shift -fi - -if [ ! -f .authcode ]; then - auth_code=$1 - shift -else +# Obtain the authcode from either the command line, local directory or home directory. +if [ -z $auth_code ]; then + if [ -r .authcode ]; then auth_code=`head -1 .authcode` + elif [ -r ~/.authcode ]; then + auth_code=`head -1 ~/.authcode` + fi fi +if [ -z $auth_code ]; then + echo "ERROR Missing authcode" + echo "$usage" + exit 1 +fi + +# Check the target dir for if set if it is writable +if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then + echo "ERROR Target Directory is not writable: \"$targetdir\"" + echo "$usage" + exit 1 +fi + +# ======================================================================== +# Utility Functions debug() { echo "$(date "+%F %T%z") ${1}" @@ -67,6 +94,8 @@ normalize_whitespace() { echo $* } +# ======================================================================== +# Main Transcode Loop for path do debug "Decoding ${path} with auth code ${auth_code}..." @@ -74,21 +103,29 @@ do save_metadata "${path}" genre=$(get_metadata_value genre) artist=$(get_metadata_value artist) - title=$(get_metadata_value title) - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + title=$(get_metadata_value title | sed 's/'\:'/'-\ '/g' | xargs -0) + if [ ! -z targetdir ] ; then + output_directory="${targetdir}/${genre}/${artist}/${title}" + else + output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + fi mkdir -p "${output_directory}" full_file_path="${output_directory}/${title}.${extension}" + # This is the primary transcode. All the heavy lifting is here. "${playlist_file}" @@ -105,7 +142,16 @@ do read -r -u9 _ _ chapter chapter_title="${title} - $(printf %0${#chaptercount}d $chapternum) ${chapter}" chapter_file="${output_directory}/${chapter_title}.${extension}" - ... +bash AAXtoMP3 [-f|--flac] [-s|--single] [-a|--authcode ] [-o|--output_dir ] ... bash AAXtoM4A [AUTHCODE] ... bash AAXtoM4B [AUTHCODE] ... ``` @@ -52,9 +52,9 @@ bash AAXtoM4B [AUTHCODE] ... ### Defaults * Specifying the AUTHCODE. In order of __precidence__. - 1. __[AUTHCODE]__ The command line option. With the highest precidence. + 1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. 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. __~/.aaxto_config__ a global config file for all the tools. And is used as the default if none of the above are specified. + 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 specified. The code must also match the encoding for the user that owns the AAX file(s). ## Anti-Piracy Notice From 10ca1e53e3f0458a6444341a9124dbb9ed01d30d Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 15:41:23 +1000 Subject: [PATCH 19/49] some cleanup --- AAXtoMP3 | 4 ++++ README.md | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 143a114..7dd767b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -1,5 +1,6 @@ #!/usr/bin/env bash + # ======================================================================== # Command Line Options usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [--authcode ]\n[--output_dir ] {FILES}\n' @@ -100,6 +101,9 @@ for path do debug "Decoding ${path} with auth code ${auth_code}..." + # Check for Presense of Audiobook + [ ! -r "${path}" ] && echo "ERROR: Input file $path missing" ; exit 1 + save_metadata "${path}" genre=$(get_metadata_value genre) artist=$(get_metadata_value artist) diff --git a/README.md b/README.md index f52ad6c..eab30e6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The purpose of this software is to convert AAX files to common MP3, M4A and M4B formats through a basic bash script frontend to FFMPEG. -Audible uses this file format, AAX to maintain DRM restrictions on their audio +Audible uses this file format to maintain DRM restrictions on their audio books and if you download your book through your library it will be stored in this format. @@ -31,7 +31,7 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-s|--single] [-a|--authcode ] [-o|--output_dir ] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode ] [-o|--output_dir ] ... bash AAXtoM4A [AUTHCODE] ... bash AAXtoM4B [AUTHCODE] ... ``` @@ -41,11 +41,24 @@ bash AAXtoM4B [AUTHCODE] ... ### MP3 Encoding +* This is the default encoding * Produces 1 or more mp3 files for the AAX title. If you desire a single file use the **--single** option * If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. -* If you desire flac encoding. use the **--flac** option. It's a bit faster but also a bit less compatible. -### M4A Encoding +### Ogg/Opus Encoding +* Can be done by using the -o or --opus command line switches +* Is designed to efficiently code speech and general audio in a single format +* Opus coded files are stored in the ogg container format for better compatibilitt. + +### AAC Encoding +* Can be done by using the -a or --aac command line switches +* Designed to be the successor of the MP3 format +* Generally achieves better sound quality than MP3 at the same bit rate. +* This will only produce 1 audio file as output. + +### FLAC Encoding +* Can be done by using the -f or --flac command line switches +* FLAC is an open format with royalty-free licensing ### M4B Encoding From 41a2803e181fc197ca27dcfe2a952db36a9b01bd Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 15:48:08 +1000 Subject: [PATCH 20/49] some cleanup --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 7dd767b..bbb85d7 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -102,7 +102,7 @@ do debug "Decoding ${path} with auth code ${auth_code}..." # Check for Presense of Audiobook - [ ! -r "${path}" ] && echo "ERROR: Input file $path missing" ; exit 1 + # [[ ! -r "${path}" ]] && echo "ERROR: Input file $path missing" ; exit 1 save_metadata "${path}" genre=$(get_metadata_value genre) From dee0d7e9a0590e3cb9953bc9b8d0eb74a94f50d9 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 15:51:40 +1000 Subject: [PATCH 21/49] some cleanup --- AAXtoMP3 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index bbb85d7..862bb1c 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -102,7 +102,10 @@ do debug "Decoding ${path} with auth code ${auth_code}..." # Check for Presense of Audiobook - # [[ ! -r "${path}" ]] && echo "ERROR: Input file $path missing" ; exit 1 + if [[ ! -r "${path}" ]] ; then + echo "ERROR: Input Audiobook file $path missing" + exit 1 + fi save_metadata "${path}" genre=$(get_metadata_value genre) From ccfaf070210c53753941e697b7c32a4ea3a6f951 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 15:52:38 +1000 Subject: [PATCH 22/49] some cleanup --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 862bb1c..6fa2421 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -12,7 +12,7 @@ targetdir= while true; do case "$1" in - -f | --flac ) codec=flac; extension=flac; shift ;; + -f | --flac ) codec=flac; extension=flac; mode=single ; shift ;; -a | --aac ) codec=copy; extension=m4a; mode=single ;shift ;; -o | --opus ) codec=libopus; extension=ogg; shift ;; -s | --single ) mode=single; shift ;; From e69b2129823bdde64680c0a660967f84930f6bfc Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 21:29:20 +1000 Subject: [PATCH 23/49] diferentiated between a log and debug message --- AAXtoMP3 | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 6fa2421..0f0490f 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -9,7 +9,13 @@ extension=mp3 mode=chaptered auth_code= targetdir= +DEBUG=0 +# ----- +# Code tip Do not have any scritp above this point that calls a function or a binary. If you do +# the $1 will no longer be a ARGV element. So you should only do basic variable setting above here. +# +# Process the command line options. This allows for un-ordered options. Sorta like a getops style while true; do case "$1" in -f | --flac ) codec=flac; extension=flac; mode=single ; shift ;; @@ -18,13 +24,14 @@ while true; do -s | --single ) mode=single; shift ;; -t | --target_dir ) targetdir="$2"; shift 2 ;; -A | --authcode ) auth_code="$2"; shift 2 ;; - -d | --debug ) DEBUG=1; shift ;; # Not so secret flag for debug output. to use in code [ $DEBUG == 1 ] && sample=2 + -d | --debug ) DEBUG=1; shift ;; -h | --help ) printf "$usage" $0 ; exit ;; -- ) shift; break ;; * ) break ;; esac done +# Empty argv means we have nothing to do so lets bark some help. if [ "$#" -eq 0 ]; then printf "$usage" $0 exit 1 @@ -43,6 +50,7 @@ if ! [[ $(type -P "$GREP") ]]; then exit 1 fi +# ----- # Obtain the authcode from either the command line, local directory or home directory. if [ -z $auth_code ]; then if [ -r .authcode ]; then @@ -57,6 +65,7 @@ if [ -z $auth_code ]; then exit 1 fi +# ----- # Check the target dir for if set if it is writable if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then echo "ERROR Target Directory is not writable: \"$targetdir\"" @@ -67,7 +76,15 @@ fi # ======================================================================== # Utility Functions +# debug debug() { + if [ $DEBUG == 1 ] ; then + echo "$(date "+%F %T%z") DEBUG ${1}" + fi +} + +# log +log() { echo "$(date "+%F %T%z") ${1}" } @@ -99,7 +116,7 @@ normalize_whitespace() { # Main Transcode Loop for path do - debug "Decoding ${path} with auth code ${auth_code}..." + log "Decoding ${path} with auth code ${auth_code}..." # Check for Presense of Audiobook if [[ ! -r "${path}" ]] ; then @@ -122,23 +139,23 @@ do # This is the primary transcode. All the heavy lifting is here. "${playlist_file}" chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) - debug "Extracting ${chaptercount} chapter files from ${full_file_path}..." + log "Extracting ${chaptercount} chapter files from ${full_file_path}..." chapternum=1 while read -r -u9 first _ _ start _ end @@ -169,9 +186,9 @@ do fi done 9< "$metadata_file" rm "${full_file_path}" - debug "Done creating chapters. Chaptered files contained in ${output_directory}." + log "Done creating chapters. Chaptered files contained in ${output_directory}." fi - debug "Done." + log "Done. ${title}" rm "${metadata_file}" done From 66dc8953ad85a89dd8c2c7ba10a484e0225a5f4d Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 23:01:34 +1000 Subject: [PATCH 24/49] Enhanced debug flag. --- AAXtoMP3 | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 0f0490f..8699484 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -12,7 +12,7 @@ targetdir= DEBUG=0 # ----- -# Code tip Do not have any scritp above this point that calls a function or a binary. If you do +# Code tip Do not have any script above this point that calls a function or a binary. If you do # the $1 will no longer be a ARGV element. So you should only do basic variable setting above here. # # Process the command line options. This allows for un-ordered options. Sorta like a getops style @@ -135,9 +135,17 @@ do fi mkdir -p "${output_directory}" full_file_path="${output_directory}/${title}.${extension}" + bitrate="$(get_bitrate)k" + album_artist="$(get_metadata_value album_artist)" + album="$(get_metadata_value album)" + album_date="$(get_metadata_value date)" + copyright="$(get_metadata_value copyright)" + + # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. + debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" # This is the primary transcode. All the heavy lifting is here. - Date: Sat, 19 May 2018 23:04:08 +1000 Subject: [PATCH 25/49] Updated .gitignore Attempting to avoid any accidental uploading to github of copyright material that only the user owns. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 71a9d6a..bc3dd24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ ACTIVATION .authcode +*aax +Audiobook/* From 0efe3fa28e5b4cf95c2db1ed94dc892e0e2505c7 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 23:07:04 +1000 Subject: [PATCH 26/49] Redundant AAXtoMP3 now does this. --- AAXtoM4A | 108 ------------------------------------------------------- 1 file changed, 108 deletions(-) delete mode 100755 AAXtoM4A diff --git a/AAXtoM4A b/AAXtoM4A deleted file mode 100755 index 7288d08..0000000 --- a/AAXtoM4A +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o noclobber -o nounset -o pipefail - -codec=copy -extension=m4a -mode=chaptered -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 - -if [ "$#" -eq 0 ]; then - echo "Usage: bash AAXtoM4A [--single] AUTHCODE {FILES}" - exit 1 -fi - -if [[ "$1" == '--single' ]] -then - mode=single - shift -fi - -if [ ! -f .authcode ]; then - auth_code=$1 - shift -else - auth_code=`head -1 .authcode` -fi - -debug() { - echo "$(date "+%F %T%z") ${1}" -} - -trap 'rm -r -f "${working_directory}"' EXIT -working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` -metadata_file="${working_directory}/metadata.txt" - -save_metadata() { - local media_file - media_file="$1" - ffprobe -i "$media_file" 2> "$metadata_file" -} - -get_metadata_value() { - local key - key="$1" - normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" -} - -get_bitrate() { - get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' -} - -normalize_whitespace() { - echo $* -} - -for path -do - debug "Decoding ${path} with auth code ${auth_code}..." - - save_metadata "${path}" - genre=$(get_metadata_value genre) - artist=$(get_metadata_value artist) - title=$(get_metadata_value title) - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" - mkdir -p "${output_directory}" - full_file_path="${output_directory}/${title}.${extension}" - - Date: Sat, 19 May 2018 23:08:11 +1000 Subject: [PATCH 27/49] Nuked redundant m4a script --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index eab30e6..6fe3af4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# AAXtoMP3 AAXtoM4A AAxtoM4B +# AAXtoMP3 AAxtoM4B The purpose of this software is to convert AAX files to common MP3, M4A and M4B formats through a basic bash script frontend to FFMPEG. @@ -32,7 +32,6 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode ] [-o|--output_dir ] ... -bash AAXtoM4A [AUTHCODE] ... bash AAXtoM4B [AUTHCODE] ... ``` From 2ac1ba67ec892b377c37b085809f879cb13b38bb Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 23:09:38 +1000 Subject: [PATCH 28/49] remove redundant AAXtoM4A --- AAXtoM4A | 108 ------------------------------------------------------- 1 file changed, 108 deletions(-) delete mode 100755 AAXtoM4A diff --git a/AAXtoM4A b/AAXtoM4A deleted file mode 100755 index 7288d08..0000000 --- a/AAXtoM4A +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o noclobber -o nounset -o pipefail - -codec=copy -extension=m4a -mode=chaptered -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 - -if [ "$#" -eq 0 ]; then - echo "Usage: bash AAXtoM4A [--single] AUTHCODE {FILES}" - exit 1 -fi - -if [[ "$1" == '--single' ]] -then - mode=single - shift -fi - -if [ ! -f .authcode ]; then - auth_code=$1 - shift -else - auth_code=`head -1 .authcode` -fi - -debug() { - echo "$(date "+%F %T%z") ${1}" -} - -trap 'rm -r -f "${working_directory}"' EXIT -working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` -metadata_file="${working_directory}/metadata.txt" - -save_metadata() { - local media_file - media_file="$1" - ffprobe -i "$media_file" 2> "$metadata_file" -} - -get_metadata_value() { - local key - key="$1" - normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" -} - -get_bitrate() { - get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' -} - -normalize_whitespace() { - echo $* -} - -for path -do - debug "Decoding ${path} with auth code ${auth_code}..." - - save_metadata "${path}" - genre=$(get_metadata_value genre) - artist=$(get_metadata_value artist) - title=$(get_metadata_value title) - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" - mkdir -p "${output_directory}" - full_file_path="${output_directory}/${title}.${extension}" - - Date: Sat, 19 May 2018 23:35:11 +1000 Subject: [PATCH 29/49] Added big FAT metadata to DEBUG output. --- AAXtoMP3 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index 8699484..a09b107 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -83,6 +83,16 @@ debug() { fi } +# debug dump contents of a file to STDOUT +debug_file() { + if [ $DEBUG == 1 ] ; then + echo "$(date "+%F %T%z") DEBUG" + echo "================================================================================" + cat "${1}" + echo "================================================================================" + fi +} + # log log() { echo "$(date "+%F %T%z") ${1}" @@ -96,6 +106,8 @@ save_metadata() { local media_file media_file="$1" ffprobe -i "$media_file" 2> "$metadata_file" + debug "Metadata file $metadata_file" + debug_file "$metadata_file" } get_metadata_value() { From 73f8b3c1dae93966022fa8fb37d0d81842eceb9b Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 19 May 2018 23:53:32 +1000 Subject: [PATCH 30/49] Woops angle brackets in Readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6fe3af4..0465c5a 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,7 @@ bash AAXtoM4B [AUTHCODE] ... ``` * **[AUTHCODE]** **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. -* ****... are considered input file(s), useful for batching! - +* **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! ### MP3 Encoding * This is the default encoding From 5e8cffd0ae67b06dcc6d45232c55c99be95f781f Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 20 May 2018 00:22:14 +1000 Subject: [PATCH 31/49] Tweeking Readme.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0465c5a..d8d1232 100644 --- a/README.md +++ b/README.md @@ -39,35 +39,39 @@ bash AAXtoM4B [AUTHCODE] ... * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! ### MP3 Encoding -* This is the default encoding +* This is the **default** encoding * Produces 1 or more mp3 files for the AAX title. If you desire a single file use the **--single** option * If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. ### Ogg/Opus Encoding -* Can be done by using the -o or --opus command line switches -* Is designed to efficiently code speech and general audio in a single format -* Opus coded files are stored in the ogg container format for better compatibilitt. +* Can be done by using the **-o** or **--opus** command line switches +* Is designed to efficiently code speech and general audio in a **--single** format +* Opus coded files are stored in the ogg container format for better compatibility. ### AAC Encoding -* Can be done by using the -a or --aac command line switches +* Can be done by using the **-a** or **--aac** command line switches * Designed to be the successor of the MP3 format * Generally achieves better sound quality than MP3 at the same bit rate. * This will only produce 1 audio file as output. ### FLAC Encoding -* Can be done by using the -f or --flac command line switches +* Can be done by using the **-f** or **--flac** command line switches * FLAC is an open format with royalty-free licensing ### M4B Encoding + ### Defaults * Specifying the AUTHCODE. In order of __precidence__. 1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. 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 specified. The code must also match the encoding for the user that owns the AAX file(s). - + 4. 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 occure. +* Default out put directory is the base directoy of each file listed. Plus the genre, Artist and Title of the Audio Book. +* The default codec is mp3 +* The default output is by chapter, unless the codec does not support it. + ## 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 f2c78da132a977327128e646c27fb03239dce867 Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 20 May 2018 00:25:47 +1000 Subject: [PATCH 32/49] Tweeking Part 2 Readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8d1232..d95cc08 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode ] [-o|--output_dir ] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode ] [-o|--output_dir ] [-d|--debug] [-h|--help] ... bash AAXtoM4B [AUTHCODE] ... ``` From ac656f9723cbc917ee5a83da441fdeb84e0d8904 Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 20 May 2018 00:50:48 +1000 Subject: [PATCH 33/49] Inserting code comments for the next guy. --- AAXtoMP3 | 195 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 106 insertions(+), 89 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index a09b107..7a4a080 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -41,13 +41,14 @@ fi # Variable validation set -o errexit -o noclobber -o nounset -o pipefail +# ----- +# Detect which annoying version fo 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 + 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 # ----- @@ -95,124 +96,140 @@ debug_file() { # log log() { - echo "$(date "+%F %T%z") ${1}" + echo "$(date "+%F %T%z") ${1}" } +# Clean up if someone hits ^c trap 'rm -r -f "${working_directory}"' EXIT working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` metadata_file="${working_directory}/metadata.txt" +# ----- +# Inspect the AAX and extract the metadata associated with the file. save_metadata() { - local media_file - media_file="$1" - ffprobe -i "$media_file" 2> "$metadata_file" - debug "Metadata file $metadata_file" - debug_file "$metadata_file" + local media_file + media_file="$1" + ffprobe -i "$media_file" 2> "$metadata_file" + debug "Metadata file $metadata_file" + debug_file "$metadata_file" } +# ----- +# Reach into the meta data and extract a specific value. +# Note the white space clean up could be well cleaner. get_metadata_value() { - local key - key="$1" - normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" + local key + key="$1" + normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" } +# ----- +# specific varient of get_metadata_value bitrate is important for transcoding. get_bitrate() { - get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' + get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' } +# ----- +# simple function to turn tabs and multiple spaces into a single space. normalize_whitespace() { - echo $* + echo $* } # ======================================================================== # Main Transcode Loop for path do - log "Decoding ${path} with auth code ${auth_code}..." + log "Decoding ${path} with auth code ${auth_code}..." - # Check for Presense of Audiobook - if [[ ! -r "${path}" ]] ; then - echo "ERROR: Input Audiobook file $path missing" - exit 1 - fi + # Check for Presense of Audiobook + if [[ ! -r "${path}" ]] ; then + echo "ERROR: Input Audiobook file $path missing" + exit 1 + fi - save_metadata "${path}" - genre=$(get_metadata_value genre) - artist=$(get_metadata_value artist) - title=$(get_metadata_value title | sed 's/'\:'/'-\ '/g' | xargs -0) - if [ ! -z targetdir ] ; then - output_directory="${targetdir}/${genre}/${artist}/${title}" - else - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" - fi - mkdir -p "${output_directory}" - full_file_path="${output_directory}/${title}.${extension}" - bitrate="$(get_bitrate)k" - album_artist="$(get_metadata_value album_artist)" - album="$(get_metadata_value album)" - album_date="$(get_metadata_value date)" - copyright="$(get_metadata_value copyright)" + # ----- + # Make sure everything is a variable. Simplifying CMD interpretation + save_metadata "${path}" + genre=$(get_metadata_value genre) + artist=$(get_metadata_value artist) + title=$(get_metadata_value title | sed 's/'\:'/'-\ '/g' | xargs -0) + if [ ! -z targetdir ] ; then + output_directory="${targetdir}/${genre}/${artist}/${title}" + else + output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + fi + mkdir -p "${output_directory}" + full_file_path="${output_directory}/${title}.${extension}" + bitrate="$(get_bitrate)k" + album_artist="$(get_metadata_value album_artist)" + album="$(get_metadata_value album)" + album_date="$(get_metadata_value date)" + copyright="$(get_metadata_value copyright)" - # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. - debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" + # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. + debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" - # This is the primary transcode. All the heavy lifting is here. - "${playlist_file}" + # ----- + # OK now spit the file if that's what you want. + # If we want multiple file we take the big mp3 and split it by chapter. + if [ "${mode}" == "chaptered" ]; then + # Playlist m3u support + playlist_file="${output_directory}/${title}.m3u" + log "Creating PlayList ${title}.m3u" + echo '#EXTM3U' > "${playlist_file}" - chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) - log "Extracting ${chaptercount} chapter files from ${full_file_path}..." + chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) + log "Extracting ${chaptercount} chapter files from ${full_file_path}..." - chapternum=1 - while read -r -u9 first _ _ start _ end - do - if [[ "${first}" = "Chapter" ]] - then - read -r -u9 _ - read -r -u9 _ _ chapter - chapter_title="${title} - $(printf %0${#chaptercount}d $chapternum) ${chapter}" - chapter_file="${output_directory}/${chapter_title}.${extension}" + chapternum=1 + while read -r -u9 first _ _ start _ end + do + if [[ "${first}" = "Chapter" ]]; then + read -r -u9 _ + read -r -u9 _ _ chapter + chapter_title="${title} - $(printf %0${#chaptercount}d $chapternum) ${chapter}" + chapter_file="${output_directory}/${chapter_title}.${extension}" - # the ID3 tags must only be specified for *.mp3 files, - # the other container formats come with their own - # tagging mechanisms. - id3_version_param="" - if test "${extension}" = "mp3"; then - id3_version_param="-id3v2_version 3" - fi + # the ID3 tags must only be specified for *.mp3 files, + # the other container formats come with their own + # tagging mechanisms. + id3_version_param="" + if test "${extension}" = "mp3"; then + id3_version_param="-id3v2_version 3" + fi - # Big Long chapter debug I could probably do this better. - debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' cover_path "${cover_path}" start "${start%?}" end "${end}" id3_version_param "${id3_version_param}" chapternum "${chapternum}" chapter_title "${chapter_title}" chapter_file "${chapter_file}" )" + # Big Long chapter debug I could probably do this better. + debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' cover_path "${cover_path}" start "${start%?}" end "${end}" id3_version_param "${id3_version_param}" chapternum "${chapternum}" chapter_title "${chapter_title}" chapter_file "${chapter_file}" )" - # Extract chapter by time stamps start and finish of chapter. - > "${playlist_file}" - echo "${chapter_title}.${extension}" >> "${playlist_file}" - chapternum=$((chapternum + 1 )) - fi - done 9< "$metadata_file" - rm "${full_file_path}" - log "Done creating chapters. Chaptered files contained in ${output_directory}." - fi + # Extract chapter by time stamps start and finish of chapter. + > "${playlist_file}" + echo "${chapter_title}.${extension}" >> "${playlist_file}" + chapternum=$((chapternum + 1 )) + fi + done 9< "$metadata_file" + rm "${full_file_path}" + log "Done creating chapters. Chaptered files contained in ${output_directory}." + fi - log "Done. ${title}" - rm "${metadata_file}" + log "Done. ${title}" + rm "${metadata_file}" done From 67d4d05b5244ff76330d342e2e581ee5bd1802d1 Mon Sep 17 00:00:00 2001 From: upuv Date: Wed, 23 May 2018 23:18:23 +1000 Subject: [PATCH 34/49] Added in support for m4b, Removed old m4b script. --- AAXtoM4B | 112 ------------------------------------------------------ AAXtoMP3 | 97 ++++++++++++++++++++++++++++++++++------------ README.md | 16 ++++++-- 3 files changed, 84 insertions(+), 141 deletions(-) delete mode 100755 AAXtoM4B diff --git a/AAXtoM4B b/AAXtoM4B deleted file mode 100755 index 4bc0992..0000000 --- a/AAXtoM4B +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o noclobber -o nounset -o pipefail - -codec=copy -extension=m4a -mode=chaptered -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 - -if [ "$#" -eq 0 ]; then - echo "Usage: bash AAXtoM4B [--single] AUTHCODE {FILES}" - exit 1 -fi - -if [[ "$1" == '--single' ]] -then - mode=single - shift -fi - -if [ ! -f .authcode ]; then - auth_code=$1 - shift -else - auth_code=`head -1 .authcode` -fi - -debug() { - echo "$(date "+%F %T%z") ${1}" -} - -trap 'rm -r -f "${working_directory}"' EXIT -working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` -metadata_file="${working_directory}/metadata.txt" - -save_metadata() { - local media_file - media_file="$1" - ffprobe -i "$media_file" 2> "$metadata_file" -} - -get_metadata_value() { - local key - key="$1" - normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" -} - -get_bitrate() { - get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' -} - -normalize_whitespace() { - echo $* -} - -for path -do - debug "Decoding ${path} with auth code ${auth_code}..." - - save_metadata "${path}" - genre=$(get_metadata_value genre) - artist=$(get_metadata_value artist) - title=$(get_metadata_value title) - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" - mkdir -p "${output_directory}" - full_file_path="${output_directory}/${title}.${extension}" - - ]\n[--output_dir ] {FILES}\n' -codec=libmp3lame -extension=mp3 -mode=chaptered -auth_code= -targetdir= -DEBUG=0 + +# Usage Synopsis. +usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [-e:m4a] [-e:m4b]\n[--authcode ] [--output_dir ] {FILES}\n' +codec=libmp3lame # Default encoder. +extension=mp3 # Default encoder extention. +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. +DEBUG=0 # Default off, If set extremely verbose output. +container= # Just in case we need to change the container. Used for M4A to M4B # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -17,21 +20,38 @@ DEBUG=0 # # Process the command line options. This allows for un-ordered options. Sorta like a getops style while true; do - case "$1" in - -f | --flac ) codec=flac; extension=flac; mode=single ; shift ;; - -a | --aac ) codec=copy; extension=m4a; mode=single ;shift ;; - -o | --opus ) codec=libopus; extension=ogg; shift ;; - -s | --single ) mode=single; shift ;; - -t | --target_dir ) targetdir="$2"; shift 2 ;; - -A | --authcode ) auth_code="$2"; shift 2 ;; - -d | --debug ) DEBUG=1; shift ;; - -h | --help ) printf "$usage" $0 ; exit ;; - -- ) shift; break ;; - * ) break ;; + case "$1" in + # Flac encoding + -f | --flac ) codec=flac; extension=flac; mode=single ; shift ;; + # Apple m4a music format. + -a | --aac ) codec=copy; extension=m4a; mode=single ; shift ;; + # Ogg Format + -o | --opus ) codec=libopus; extension=ogg; shift ;; + # If appropriate use only a single file output. + -s | --single ) mode=single; shift ;; + # This is the same as --single option. + -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; shift ;; + # Identical to --acc option. + -e:m4a ) codec=copy; extension=m4a; mode=single; shift ;; + # Similiar to --aac but specific to audio books. + -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b shift ;; + # Change the working dir from AAX directory to what you choose. + -t | --target_dir ) targetdir="$2"; shift 2 ;; + # Authorization code associate with the AAX file(s) + -A | --authcode ) auth_code="$2"; shift 2 ;; + # Extremely verbose output. + -d | --debug ) DEBUG=1; shift ;; + # Command synopsis. + -h | --help ) printf "$usage" $0 ; exit ;; + # Standard flag signifying the end of command line processing. + -- ) shift; break ;; + # Anything else stops command line processing. + * ) break ;; + esac done - +# ----- # Empty argv means we have nothing to do so lets bark some help. if [ "$#" -eq 0 ]; then printf "$usage" $0 @@ -54,6 +74,8 @@ fi # ----- # Obtain the authcode from either the command line, local directory or home directory. +# See Readme.md for details on how to aquire your personal authcode for your personal +# audible AAX files. if [ -z $auth_code ]; then if [ -r .authcode ]; then auth_code=`head -1 .authcode` @@ -61,6 +83,7 @@ if [ -z $auth_code ]; then auth_code=`head -1 ~/.authcode` fi fi +# No point going on if no authcode found. if [ -z $auth_code ]; then echo "ERROR Missing authcode" echo "$usage" @@ -78,14 +101,15 @@ fi # ======================================================================== # Utility Functions +# ----- # debug - debug() { if [ $DEBUG == 1 ] ; then echo "$(date "+%F %T%z") DEBUG ${1}" fi } +# ----- # debug dump contents of a file to STDOUT debug_file() { if [ $DEBUG == 1 ] ; then @@ -96,11 +120,13 @@ debug_file() { fi } +# ----- # log log() { echo "$(date "+%F %T%z") ${1}" } +# ----- # Clean up if someone hits ^c trap 'rm -r -f "${working_directory}"' EXIT working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` @@ -143,18 +169,19 @@ for path do log "Decoding ${path} with auth code ${auth_code}..." - # Check for Presense of Audiobook + # Check for Presense of Audiobook. Note this break the processing of + # of a list of books once a single missing file is found. if [[ ! -r "${path}" ]] ; then echo "ERROR: Input Audiobook file $path missing" exit 1 fi # ----- - # Make sure everything is a variable. Simplifying CMD interpretation + # Make sure everything is a variable. Simplifying Command interpretation save_metadata "${path}" genre=$(get_metadata_value genre) artist=$(get_metadata_value artist) - title=$(get_metadata_value title | sed 's/'\:'/'-\ '/g' | xargs -0) + title=$(get_metadata_value title | sed 's/'\:'/'-'/g' | sed 's/ / /g' | sed 's/- /-/g' | xargs -0) if [ ! -z targetdir ] ; then output_directory="${targetdir}/${genre}/${artist}/${title}" else @@ -169,6 +196,8 @@ do copyright="$(get_metadata_value copyright)" # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. + # Not 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 "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" # ----- @@ -177,22 +206,25 @@ do "${playlist_file}" + # Determine the number of chapters. chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) log "Extracting ${chaptercount} chapter files from ${full_file_path}..." @@ -202,6 +234,9 @@ do if [[ "${first}" = "Chapter" ]]; then read -r -u9 _ read -r -u9 _ _ chapter + + # The formating of the chapters names and the file names. + # Chapter names are used in a few place. chapter_title="${title} - $(printf %0${#chaptercount}d $chapternum) ${chapter}" chapter_file="${output_directory}/${chapter_title}.${extension}" @@ -218,21 +253,33 @@ do debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' cover_path "${cover_path}" start "${start%?}" end "${end}" id3_version_param "${id3_version_param}" chapternum "${chapternum}" chapter_title "${chapter_title}" chapter_file "${chapter_file}" )" # Extract chapter by time stamps start and finish of chapter. + # This extracts based on time stamps start and end. > "${playlist_file}" echo "${chapter_title}.${extension}" >> "${playlist_file}" chapternum=$((chapternum + 1 )) fi done 9< "$metadata_file" + + # Clean up of working directoy stuff. rm "${full_file_path}" log "Done creating chapters. Chaptered files contained in ${output_directory}." fi + # Detect if we are actuall m4b instead of m4a + if [[ ${extension} == "m4a" && ${container}="m4b" ]]; then + mv "${full_file_path}" "${full_file_path/.m4a/.m4b}" + fi + + log "Done. ${title}" + # Lastly get rid of any extra stuff. rm "${metadata_file}" done diff --git a/README.md b/README.md index d95cc08..fc86834 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,24 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode ] [-o|--output_dir ] [-d|--debug] [-h|--help] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-d|--debug] [-h|--help] ... bash AAXtoM4B [AUTHCODE] ... ``` * **[AUTHCODE]** **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! +## Options ## +* -f or --flac Flac Encoding and Produces a single file. +* -o or --opus Ogg/Opus Encoding defaults to multiple file output by chapter. The extention is .ogg +* -a or --aac AAC Encoding and produce a m4a single files output. +* -s or --single Output a single file. If you only want a single ogg file for instance. +* -A or --authcode for this execution of the command use the provided AUTHCODE to decode the AAX file. +* -t or --target_dir change the default output location to the named PATH. Note the default location is ./Audiobook of the directory to which each AAX file resides. +* -e:mp3 Identical to defaults. +* -e:m4a Create a m4a audio file. This is identical to --aac +* -e:m4b Create a m4b aduio file. This is the book version of the m4a format. + ### MP3 Encoding * This is the **default** encoding * Produces 1 or more mp3 files for the AAX title. If you desire a single file use the **--single** option @@ -58,9 +69,6 @@ bash AAXtoM4B [AUTHCODE] ... * Can be done by using the **-f** or **--flac** command line switches * FLAC is an open format with royalty-free licensing -### M4B Encoding - - ### Defaults * Specifying the AUTHCODE. In order of __precidence__. From 1f2cd830d6c72da77a8386699e77a315dca33b07 Mon Sep 17 00:00:00 2001 From: upuv Date: Wed, 23 May 2018 23:19:36 +1000 Subject: [PATCH 35/49] Woops left reference to m4b script in readme. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc86834..bf20495 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# AAXtoMP3 AAxtoM4B -The purpose of this software is to convert AAX files to common MP3, M4A and M4B formats +# AAXtoMP3 +The purpose of this software is to convert AAX 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 From 6d1a751b81f0277281dadff5a7c24fee2f8acf20 Mon Sep 17 00:00:00 2001 From: upuv Date: Wed, 23 May 2018 23:23:40 +1000 Subject: [PATCH 36/49] Cleaned up some more Readme --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index bf20495..354eed8 100644 --- a/README.md +++ b/README.md @@ -39,15 +39,15 @@ bash AAXtoM4B [AUTHCODE] ... * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! ## Options ## -* -f or --flac Flac Encoding and Produces a single file. -* -o or --opus Ogg/Opus Encoding defaults to multiple file output by chapter. The extention is .ogg -* -a or --aac AAC Encoding and produce a m4a single files output. -* -s or --single Output a single file. If you only want a single ogg file for instance. -* -A or --authcode for this execution of the command use the provided AUTHCODE to decode the AAX file. -* -t or --target_dir change the default output location to the named PATH. Note the default location is ./Audiobook of the directory to which each AAX file resides. -* -e:mp3 Identical to defaults. -* -e:m4a Create a m4a audio file. This is identical to --aac -* -e:m4b Create a m4b aduio file. This is the book version of the m4a format. +* **-f** or **--flac** Flac Encoding and Produces a single file. +* **-o** or **--opus** Ogg/Opus Encoding defaults to multiple file output by chapter. The extention is .ogg +* **-a** or **--aac** AAC Encoding and produce a m4a single files output. +* **-s** or **--single** Output a single file. If you only want a single ogg file for instance. +* **-A** or **--authcode <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. +* **-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. +* **-e:mp3** Identical to defaults. +* **-e:m4a** Create a m4a audio file. This is identical to --aac +* **-e:m4b** Create a m4b aduio file. This is the book version of the m4a format. ### MP3 Encoding * This is the **default** encoding From 11292dc4c4a0d65485aba399c401104419eae20d Mon Sep 17 00:00:00 2001 From: upuv Date: Wed, 23 May 2018 23:49:34 +1000 Subject: [PATCH 37/49] Cleaned up some more Readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 354eed8..a27f20e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-d|--debug] [-h|--help] ... -bash AAXtoM4B [AUTHCODE] ... ``` * **[AUTHCODE]** **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. From eaf75eb2e231ce775ca28161c0b300b8006115f9 Mon Sep 17 00:00:00 2001 From: upuv Date: Thu, 24 May 2018 15:36:05 +1000 Subject: [PATCH 38/49] Fixed a regression. m4a and m4b now have coverart. --- AAXtoMP3 | 22 +++++++++++++++++++++- README.md | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 6021cfb..67417ae 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -72,6 +72,18 @@ if ! [[ $(type -P "$GREP") ]]; then exit 1 fi +# ----- +# Detect if we need mp4art for cover additions to m4a & m4b files. +if [[ "x${extension}" == "xm4a" && "x$(type -P mp4art)" == "x" ]]; then + echo "WARN mp4art was not found on your env PATH variable" + echo "Without it, this script will not be able to add cover art to" + echo "m4b files. Note if there are no other errors the AAXtoMP3 will" + echo "continue. However no cover art will be added to the output." + echo "INSTALL:" + echo "MacOS: brew install mp4v2" + echo "Ubuntu: sudo apt-get install mp4v2-utils" +fi + # ----- # Obtain the authcode from either the command line, local directory or home directory. # See Readme.md for details on how to aquire your personal authcode for your personal @@ -273,7 +285,15 @@ do log "Done creating chapters. Chaptered files contained in ${output_directory}." fi - # Detect if we are actuall m4b instead of m4a + # ---- + # Add the cover art to m4a and m4b file types. + if [[ ${extension} == "m4a" && $(type -P mp4art) ]]; then + mp4art --add "${cover_path}" "${full_file_path}" + log "Added cover art." + fi + + # ---- + # Detect if we are actuall m4b instead of m4a Then rename the file. if [[ ${extension} == "m4a" && ${container}="m4b" ]]; then mv "${full_file_path}" "${full_file_path/.m4a/.m4b}" fi diff --git a/README.md b/README.md index a27f20e..db91440 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ can obtain this string from a tool like [audible-activator](https://github.com/i * bash 4.3.42 or later tested * ffmpeg version 2.8.3 or later * libmp3lame (came from lame package on Arch, not sure where else this is stored) +* grep Some OS distributions do not have it installed. +* mp4art used to add cover art to m4a and m4b files. Optional ## OSX Thanks to thibaudcolas, this script has been tested on OSX 10.11.6 El Capitan. YMMV, but it should work for @@ -68,6 +70,13 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-e:mp3] [-e:m4a] * Can be done by using the **-f** or **--flac** command line switches * FLAC is an open format with royalty-free licensing +### M4A and M4B Containers ### +* These containers were created by Apple Inc. They were meant to be the successor to mp3. +* M4A is a container that is meant to hold music and is typically of a higher bitrate. +* M4B is a container that is meant to hold audiobooks and is typically has bitrates of 64k and 32k. +* Both formats are chaptered +* Both support coverart internall + ### Defaults * Specifying the AUTHCODE. In order of __precidence__. From 84335828d9c56739fcf04ef56e3c034f63b037bc Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 26 May 2018 15:27:39 +1000 Subject: [PATCH 39/49] Bug Fix, added --chaptered, Readme updates. --- AAXtoMP3 | 82 ++++++++++++++++++++++++++++++++++--------------------- README.md | 55 +++++++++++++++++++++++-------------- 2 files changed, 85 insertions(+), 52 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 67417ae..4a60e9d 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,14 +5,14 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [-e:m4a] [-e:m4b]\n[--authcode ] [--output_dir ] {FILES}\n' +usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ] {FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extention. 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. DEBUG=0 # Default off, If set extremely verbose output. -container= # Just in case we need to change the container. Used for M4A to M4B +container=mp3 # Just in case we need to change the container. Used for M4A to M4B # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -22,17 +22,19 @@ container= # Just in case we need to change the container. Use while true; do case "$1" in # Flac encoding - -f | --flac ) codec=flac; extension=flac; mode=single ; shift ;; + -f | --flac ) codec=flac; extension=flac; mode=single; container=flac; shift ;; # Apple m4a music format. - -a | --aac ) codec=copy; extension=m4a; mode=single ; shift ;; + -a | --aac ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; # Ogg Format - -o | --opus ) codec=libopus; extension=ogg; shift ;; + -o | --opus ) codec=libopus; extension=ogg; container=flac; shift ;; # If appropriate use only a single file output. -s | --single ) mode=single; shift ;; + # If appropriate use only a single file output. + -c | --chaptered ) mode=chaptered; shift ;; # This is the same as --single option. - -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; shift ;; + -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; container=mp3; shift ;; # Identical to --acc option. - -e:m4a ) codec=copy; extension=m4a; mode=single; shift ;; + -e:m4a ) codec=copy; extension=m4a; mode=single; container=m4a shift ;; # Similiar to --aac but specific to audio books. -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b shift ;; # Change the working dir from AAX directory to what you choose. @@ -104,10 +106,12 @@ fi # ----- # Check the target dir for if set if it is writable -if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then - echo "ERROR Target Directory is not writable: \"$targetdir\"" - echo "$usage" - exit 1 +if [[ "x${targetdir}" != "x" ]]; then + if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then + echo "ERROR Target Directory is not writable: \"$targetdir\"" + echo "$usage" + exit 1 + fi fi # ======================================================================== @@ -194,12 +198,11 @@ do genre=$(get_metadata_value genre) artist=$(get_metadata_value artist) title=$(get_metadata_value title | sed 's/'\:'/'-'/g' | sed 's/ / /g' | sed 's/- /-/g' | xargs -0) - if [ ! -z targetdir ] ; then + if [ "x${targetdir}" != "x" ] ; then output_directory="${targetdir}/${genre}/${artist}/${title}" else output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" fi - mkdir -p "${output_directory}" full_file_path="${output_directory}/${title}.${extension}" bitrate="$(get_bitrate)k" album_artist="$(get_metadata_value album_artist)" @@ -207,6 +210,8 @@ do album_date="$(get_metadata_value date)" copyright="$(get_metadata_value copyright)" + mkdir -p "${output_directory}" + # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. # Not 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. @@ -249,7 +254,7 @@ do # The formating of the chapters names and the file names. # Chapter names are used in a few place. - chapter_title="${title} - $(printf %0${#chaptercount}d $chapternum) ${chapter}" + chapter_title="${title}-$(printf %0${#chaptercount}d $chapternum) ${chapter}" chapter_file="${output_directory}/${chapter_title}.${extension}" @@ -266,7 +271,8 @@ do # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. - > "${playlist_file}" - echo "${chapter_title}.${extension}" >> "${playlist_file}" + echo "${chapter_title}.${container}" >> "${playlist_file}" chapternum=$((chapternum + 1 )) + + # ---- + # Add the cover art to m4a and m4b file types. + if [[ ${extension} == "m4a" && $(type -P mp4art) ]]; then + mp4art -q --add "${cover_path}" "${chapter_file}" + log "Added cover art to ${chapter_title}" + fi + + # ---- + # Detect if we are actuall m4b instead of m4a Then rename the file. + if [[ ${extension} == "m4a" && ${container}="m4b" ]]; then + mv "${chapter_file}" "${chapter_file/.m4a/.m4b}" + fi + fi done 9< "$metadata_file" # Clean up of working directoy stuff. rm "${full_file_path}" - log "Done creating chapters. Chaptered files contained in ${output_directory}." - fi - - # ---- - # Add the cover art to m4a and m4b file types. - if [[ ${extension} == "m4a" && $(type -P mp4art) ]]; then - mp4art --add "${cover_path}" "${full_file_path}" - log "Added cover art." - fi - - # ---- - # Detect if we are actuall m4b instead of m4a Then rename the file. - if [[ ${extension} == "m4a" && ${container}="m4b" ]]; then - mv "${full_file_path}" "${full_file_path/.m4a/.m4b}" + log "Done creating chapters for ${output_directory}." + else + # Perform file tasks on output file. + # ---- + # Add the cover art to m4a and m4b file types. + if [[ ${extension} == "m4a" && $(type -P mp4art) ]]; then + mp4art -q --add "${cover_path}" "${full_file_path}" + log "Added cover art to ${title}.${extension}" + fi + # ---- + # Detect if we are actuall m4b instead of m4a Then rename the file. + if [[ ${extension} == "m4a" && ${container}="m4b" ]]; then + mv "${full_file_path}" "${full_file_path/.m4a/.m4b}" + fi fi - log "Done. ${title}" + log "Done ${title}" # Lastly get rid of any extra stuff. rm "${metadata_file}" done diff --git a/README.md b/README.md index db91440..79f4b74 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,6 @@ your **personal** Audible account. The purpose of this software is to create a method for you to download and store your books just in case Audible fails for some reason. -## Setup -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). - ## Requirements * bash 4.3.42 or later tested * ffmpeg version 2.8.3 or later @@ -33,42 +28,65 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-d|--debug] [-h|--help] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-d|--debug] [-h|--help] ... ``` -* **[AUTHCODE]** **your** Audible auth code (it won't correctly decode otherwise) (required), See below for more information on setting the AUTHCODE. * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! -## Options ## +## Options * **-f** or **--flac** Flac Encoding and Produces a single file. * **-o** or **--opus** Ogg/Opus Encoding defaults to multiple file output by chapter. The extention is .ogg * **-a** or **--aac** AAC Encoding and produce a m4a single files output. -* **-s** or **--single** Output a single file. If you only want a single ogg file for instance. * **-A** or **--authcode <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. * **-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. * **-e:mp3** Identical to defaults. * **-e:m4a** Create a m4a audio file. This is identical to --aac * **-e:m4b** Create a m4b aduio file. This is the book version of the m4a format. +* **-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 -em4b options. + + +### [AUTHCODE] +**Your** Audible auth code (it won't correctly decode otherwise) (required). + +#### 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). + +#### Specifying the AUTHCODE. + In order of __precidence__. + 1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. + 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 occure. + ### MP3 Encoding * This is the **default** encoding -* Produces 1 or more mp3 files for the AAX title. If you desire a single file use the **--single** option -* If you want a mp3 file per chapter do not use the -single option. Note a m3u playlist file will also be created in this instance. +* Produces 1 or more mp3 files for the AAX title. +* The default mode is **chaptered** +* If you want a mp3 file per chapter do not use the -single option. +* A m3u playlist file will also be created in this instance in the case of **default** chaptered ouput. ### Ogg/Opus Encoding * Can be done by using the **-o** or **--opus** command line switches -* Is designed to efficiently code speech and general audio in a **--single** format +* The default mode is **chaptered** * Opus coded files are stored in the ogg container format for better compatibility. ### AAC Encoding * Can be done by using the **-a** or **--aac** command line switches +* The default mode is **single** * Designed to be the successor of the MP3 format * Generally achieves better sound quality than MP3 at the same bit rate. * This will only produce 1 audio file as output. ### FLAC Encoding * Can be done by using the **-f** or **--flac** command line switches -* FLAC is an open format with royalty-free licensing +* The default mode is **single** +* FLAC is an open format with royalty-free licensing +* Note: There is an bug with the ffmpeg software that prevents the splitting of flac files. Chaptered output of flac files will fail. ### M4A and M4B Containers ### * These containers were created by Apple Inc. They were meant to be the successor to mp3. @@ -76,20 +94,15 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-e:mp3] [-e:m4a] * M4B is a container that is meant to hold audiobooks and is typically has bitrates of 64k and 32k. * Both formats are chaptered * Both support coverart internall +* The default mode is **single** ### Defaults -* Specifying the AUTHCODE. - In order of __precidence__. - 1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. - 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. - 4. 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 occure. * Default out put directory is the base directoy of each file listed. Plus the genre, Artist and Title of the Audio Book. * The default codec is mp3 -* The default output is by chapter, unless the codec does not support it. +* The default output is by chapter. ## Anti-Piracy Notice -Note that this project does NOT ‘crack’ the DRM. It simply allows the user to +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 audiobook in the same manner that the official audiobook playing software does. From 09145b4df2aced0b09221328dbefd908ed08c4f6 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 26 May 2018 16:16:00 +1000 Subject: [PATCH 40/49] Fixed an issue with container setting. --- AAXtoMP3 | 9 +++++---- README.md | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 4a60e9d..ed965ae 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -34,9 +34,9 @@ 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=m4a shift ;; - # Similiar to --aac but specific to audio books. - -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b shift ;; + -e:m4a ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; + # Similiar to --aac but specific to audio books + -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b; shift ;; # Change the working dir from AAX directory to what you choose. -t | --target_dir ) targetdir="$2"; shift 2 ;; # Authorization code associate with the AAX file(s) @@ -215,7 +215,7 @@ do # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. # Not 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 "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" + debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" container ${container} codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" # ----- # This is the main work horse command. This is the primary transcoder. @@ -282,6 +282,7 @@ do duration=$(echo "${end} - ${start%?}" | bc) echo "#EXTINF:${duration%.*},${title} - ${chapter}" >> "${playlist_file}" echo "${chapter_title}.${container}" >> "${playlist_file}" + echo "${container} ${chapter_title}.${container}" chapternum=$((chapternum + 1 )) # ---- diff --git a/README.md b/README.md index 79f4b74..bc468c1 100644 --- a/README.md +++ b/README.md @@ -56,10 +56,10 @@ this string from a tool like [audible-activator](https://github.com/inAudible-NG/audible-activator). #### Specifying the AUTHCODE. - In order of __precidence__. - 1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. - 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. +In order of __precidence__. +1. __--authcode [AUTHCODE]__ The command line option. With the highest precidence. +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 occure. From 1727d10be388f2f5eec1caa631e6890042f5aa53 Mon Sep 17 00:00:00 2001 From: upuv Date: Sat, 26 May 2018 16:23:12 +1000 Subject: [PATCH 41/49] Fixed usage string --- AAXtoMP3 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index ed965ae..26bf58b 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,7 +5,7 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3.sh [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ] {FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ] {FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extention. mode=chaptered # Multi file output @@ -282,7 +282,6 @@ do duration=$(echo "${end} - ${start%?}" | bc) echo "#EXTINF:${duration%.*},${title} - ${chapter}" >> "${playlist_file}" echo "${chapter_title}.${container}" >> "${playlist_file}" - echo "${container} ${chapter_title}.${container}" chapternum=$((chapternum + 1 )) # ---- From 8327f15ac2d0acee562a8f1c68241cbf71a88b56 Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 3 Jun 2018 15:34:56 +1000 Subject: [PATCH 42/49] Adding --complete_dir option and documentation --- AAXtoMP3 | 56 +++++++++++++++++++++++++++++++++++++------------------ README.md | 3 ++- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 26bf58b..6410059 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,14 +5,15 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ] {FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ]\n[--complete_dir ] {FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extention. 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. -DEBUG=0 # Default off, If set extremely verbose output. +completedir= # Optional location to move aax files once the decoding is complete. container=mp3 # Just in case we need to change the container. Used for M4A to M4B +DEBUG=0 # Default off, If set extremely verbose output. # ----- # Code tip Do not have any script above this point that calls a function or a binary. If you do @@ -22,33 +23,35 @@ container=mp3 # Just in case we need to change the container. Use while true; do case "$1" in # Flac encoding - -f | --flac ) codec=flac; extension=flac; mode=single; container=flac; shift ;; + -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 ;; + -a | --aac ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; # Ogg Format - -o | --opus ) codec=libopus; extension=ogg; container=flac; shift ;; + -o | --opus ) codec=libopus; extension=ogg; container=flac; shift ;; # If appropriate use only a single file output. - -s | --single ) mode=single; shift ;; + -s | --single ) mode=single; shift ;; # If appropriate use only a single file output. - -c | --chaptered ) mode=chaptered; shift ;; + -c | --chaptered ) mode=chaptered; shift ;; # This is the same as --single option. - -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; container=mp3; shift ;; + -e:mp3 ) codec=libmp3lame; extension=mp3; mode=single; container=mp3; shift ;; # Identical to --acc option. - -e:m4a ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; + -e:m4a ) codec=copy; extension=m4a; mode=single; container=m4a; shift ;; # Similiar to --aac but specific to audio books - -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b; shift ;; + -e:m4b ) codec=copy; extension=m4a; mode=single; container=m4b; shift ;; # Change the working dir from AAX directory to what you choose. - -t | --target_dir ) targetdir="$2"; shift 2 ;; + -t | --target_dir ) targetdir="$2"; shift 2 ;; + # Move the AAX file to a new directory when decoding is complete. + -C | --complete_dir ) completedir="$2"; shift 2 ;; # Authorization code associate with the AAX file(s) - -A | --authcode ) auth_code="$2"; shift 2 ;; + -A | --authcode ) auth_code="$2"; shift 2 ;; # Extremely verbose output. - -d | --debug ) DEBUG=1; shift ;; + -d | --debug ) DEBUG=1; shift ;; # Command synopsis. - -h | --help ) printf "$usage" $0 ; exit ;; + -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. - -- ) shift; break ;; + -- ) shift; break ;; # Anything else stops command line processing. - * ) break ;; + * ) break ;; esac done @@ -108,7 +111,17 @@ fi # Check the target dir for if set if it is writable if [[ "x${targetdir}" != "x" ]]; then if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then - echo "ERROR Target Directory is not writable: \"$targetdir\"" + echo "ERROR Target Directory does not exist or is not writable: \"$targetdir\"" + echo "$usage" + exit 1 + fi +fi + +# ----- +# Check the target dir for if set if it is writable +if [[ "x${completedir}" != "x" ]]; then + if [[ ! -w "${completedir}" || ! -d "${completedir}" ]] ; then + echo "ERROR Complete Directory does not exist or is not writable: \"$completedir\"" echo "$usage" exit 1 fi @@ -256,7 +269,6 @@ do # Chapter names are used in a few place. chapter_title="${title}-$(printf %0${#chaptercount}d $chapternum) ${chapter}" chapter_file="${output_directory}/${chapter_title}.${extension}" - # the ID3 tags must only be specified for *.mp3 files, # the other container formats come with their own @@ -322,4 +334,12 @@ do log "Done ${title}" # Lastly get rid of any extra stuff. rm "${metadata_file}" + + # Move the aax file if the decode is completed and the --complete_dir is set to a valid location. + # Check the target dir for if set if it is writable + if [[ "x${completedir}" != "x" ]]; then + log "Moving Transcoded ${path} to ${completedir}" + mv "${path}" "${completedir}" + fi + done diff --git a/README.md b/README.md index bc468c1..f53661f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. ## Usage(s) ``` -bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-d|--debug] [-h|--help] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-C|--complete_dir ] [-d|--debug] [-h|--help] ... ``` * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! @@ -39,6 +39,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [ * **-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. * **-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. * **-e:mp3** Identical to defaults. * **-e:m4a** Create a m4a audio file. This is identical to --aac * **-e:m4b** Create a m4b aduio file. This is the book version of the m4a format. From de6d5db3f2e9955a3493b4ea85d50da8452fa653 Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 3 Jun 2018 15:49:19 +1000 Subject: [PATCH 43/49] Enhanced DEBUG output for command line options --- AAXtoMP3 | 64 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 6410059..da909fb 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -63,9 +63,43 @@ if [ "$#" -eq 0 ]; then exit 1 fi +set -o errexit -o noclobber -o nounset -o pipefail + +# ======================================================================== +# Utility Functions + +# ----- +# debug +debug() { + if [ $DEBUG == 1 ] ; then + echo "$(date "+%F %T%z") DEBUG ${1}" + fi +} + +# ----- +# debug dump contents of a file to STDOUT +debug_file() { + if [ $DEBUG == 1 ] ; then + echo "$(date "+%F %T%z") DEBUG" + echo "================================================================================" + cat "${1}" + echo "================================================================================" + fi +} + +# ----- +# log +log() { + echo "$(date "+%F %T%z") ${1}" +} + +# ----- +# Print out what we have already after command line processing. +debug "Command line options as set:$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' codec "${codec}" extension "${extension}" mode "${mode}" container "${container}" targetdir "${targetdir}" completedir "${completedir}" auth_code "${auth_code}")" + # ======================================================================== # Variable validation -set -o errexit -o noclobber -o nounset -o pipefail + # ----- # Detect which annoying version fo grep we have @@ -127,34 +161,6 @@ if [[ "x${completedir}" != "x" ]]; then fi fi -# ======================================================================== -# Utility Functions - -# ----- -# debug -debug() { - if [ $DEBUG == 1 ] ; then - echo "$(date "+%F %T%z") DEBUG ${1}" - fi -} - -# ----- -# debug dump contents of a file to STDOUT -debug_file() { - if [ $DEBUG == 1 ] ; then - echo "$(date "+%F %T%z") DEBUG" - echo "================================================================================" - cat "${1}" - echo "================================================================================" - fi -} - -# ----- -# log -log() { - echo "$(date "+%F %T%z") ${1}" -} - # ----- # Clean up if someone hits ^c trap 'rm -r -f "${working_directory}"' EXIT From c2082ccfc0d8f71d5b092ea523294b50060969dd Mon Sep 17 00:00:00 2001 From: upuv Date: Sun, 3 Jun 2018 23:15:31 +1000 Subject: [PATCH 44/49] Big change to DEBUG Output. It now handles lists of vars to dump. Makes the code a little cleaner. --- AAXtoMP3 | 54 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index da909fb..12b1bd2 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -70,6 +70,7 @@ set -o errexit -o noclobber -o nounset -o pipefail # ----- # debug +# debug "Some longish message" debug() { if [ $DEBUG == 1 ] ; then echo "$(date "+%F %T%z") DEBUG ${1}" @@ -78,15 +79,46 @@ debug() { # ----- # debug dump contents of a file to STDOUT +# debug "" debug_file() { if [ $DEBUG == 1 ] ; then echo "$(date "+%F %T%z") DEBUG" - echo "================================================================================" + echo "=Start==========================================================================" cat "${1}" - echo "================================================================================" + echo "=End============================================================================" fi } +# ----- +# debug dump a list of internal script variables to STDOUT +# debug_vars "Some Message" var1 var2 var3 var4 var5 +debug_vars() { + if [ $DEBUG == 1 ] ; then + msg="$1"; shift ; # Grab the message + args=("$@") # Grab the rest of the args + + # determine the length of the longest key + l=0 + for (( n=0; n<${#args[@]}; n++ )) ; do + (( "${#args[$n]}" > "$l" )) && l=${#args[$n]} + done + + # Print the Debug Message + echo "$(date "+%F %T%z") DEBUG ${msg}" + echo "=Start==========================================================================" + + # Using the max length of a var name we dynamically create the format. + fmt="%-"${l}"s = %s\n" + + for (( n=0; n<${#args[@]}; n++ )) ; do + eval val="\$${args[$n]}" ; # We save off the value of the var in question for ease of coding. + + echo "$(printf "${fmt}" ${args[$n]} "${val}" )" + done + echo "=End============================================================================" + fi +} + # ----- # log log() { @@ -95,12 +127,11 @@ log() { # ----- # Print out what we have already after command line processing. -debug "Command line options as set:$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' codec "${codec}" extension "${extension}" mode "${mode}" container "${container}" targetdir "${targetdir}" completedir "${completedir}" auth_code "${auth_code}")" +debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code # ======================================================================== # Variable validation - # ----- # Detect which annoying version fo grep we have GREP=$(grep --version | grep -q GNU && echo "grep" || echo "ggrep") @@ -202,7 +233,6 @@ normalize_whitespace() { # Main Transcode Loop for path do - log "Decoding ${path} with auth code ${auth_code}..." # Check for Presense of Audiobook. Note this break the processing of # of a list of books once a single missing file is found. @@ -231,10 +261,16 @@ do mkdir -p "${output_directory}" - # Big long DEBUG output. Fully describes the settings used for transcoding. I could probably do this better. + # Fancy declartion of which book we are decoding. Including the AUTHCODE. + dashline="----------------------------------------------------" + log "$(printf '\n----Decoding---%s%s--%s--' "${title}" "${dashline:${#title}}" "${auth_code}")" + log "Decoding ${path}" + + + # Big long DEBUG output. Fully describes the settings used for transcoding. # Not 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 "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %sn%-18s: %s' title "${title}" auth_code "${auth_code}" mode "${mode}" path "${path}" container ${container} codec "${codec}" bitrate "${bitrate}" artist "${artist}" album_artist "${album_artist}" album "${album}" album_date "${album_date}" genre "${genre}" copyright "${copyright}" full_file_path "${full_file_path}" metadata_file "${metadata_file}" working_directory "${working_directory}" )" + debug_vars "Book and Variable values" title auth_code mode path container codec bitrate artist album_artist album album_date genre copyright full_file_path metadata_file working_directory # ----- # This is the main work horse command. This is the primary transcoder. @@ -284,8 +320,8 @@ do id3_version_param="-id3v2_version 3" fi - # Big Long chapter debug I could probably do this better. - debug "$(printf '\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s\n%-18s: %s' cover_path "${cover_path}" start "${start%?}" end "${end}" id3_version_param "${id3_version_param}" chapternum "${chapternum}" chapter_title "${chapter_title}" chapter_file "${chapter_file}" )" + # Big Long chapter debug + debug_vars "Chapter Variables:" cover_path start end id3_version_param chapternum chapter_title chapter_file # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. From 71e140259be803f69447737e5b3a15eb7cd85775 Mon Sep 17 00:00:00 2001 From: upuv Date: Mon, 4 Jun 2018 16:10:00 +1000 Subject: [PATCH 45/49] Refactor some variables for readability. --- AAXtoMP3 | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 12b1bd2..a6f9ff3 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -63,6 +63,7 @@ if [ "$#" -eq 0 ]; then exit 1 fi +# Setup safer bash script defaults. set -o errexit -o noclobber -o nounset -o pipefail # ======================================================================== @@ -231,28 +232,28 @@ normalize_whitespace() { # ======================================================================== # Main Transcode Loop -for path +for aax_file do # Check for Presense of Audiobook. Note this break the processing of # of a list of books once a single missing file is found. - if [[ ! -r "${path}" ]] ; then - echo "ERROR: Input Audiobook file $path missing" + if [[ ! -r "${aax_file}" ]] ; then + echo "ERROR: Input Audiobook file $aax_file missing" exit 1 fi # ----- # Make sure everything is a variable. Simplifying Command interpretation - save_metadata "${path}" + 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' | sed 's/- /-/g' | xargs -0) if [ "x${targetdir}" != "x" ] ; then output_directory="${targetdir}/${genre}/${artist}/${title}" else - output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" + output_directory="$(dirname "${aax_file}")/${genre}/${artist}/${title}" fi - full_file_path="${output_directory}/${title}.${extension}" + output_file="${output_directory}/${title}.${extension}" bitrate="$(get_bitrate)k" album_artist="$(get_metadata_value album_artist)" album="$(get_metadata_value album)" @@ -264,26 +265,26 @@ do # Fancy declartion of which book we are decoding. Including the AUTHCODE. dashline="----------------------------------------------------" log "$(printf '\n----Decoding---%s%s--%s--' "${title}" "${dashline:${#title}}" "${auth_code}")" - log "Decoding ${path}" + log "Source ${aax_file}" # Big long DEBUG output. Fully describes the settings used for transcoding. # Not 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 path container codec bitrate artist album_artist album album_date genre copyright full_file_path 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 output_file metadata_file working_directory # ----- # This is the main work horse command. This is the primary transcoder. # This is the primary transcode. All the heavy lifting is here. - Date: Mon, 4 Jun 2018 17:11:12 +1000 Subject: [PATCH 46/49] More Refactor, Setting up for user defined file naming using variable names. --- AAXtoMP3 | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index a6f9ff3..f8a4774 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -211,11 +211,13 @@ save_metadata() { # ----- # Reach into the meta data and extract a specific value. -# Note the white space clean up could be well cleaner. +# This is a long pipe of transforms. +# This finds the first occurance of the key : value pair. get_metadata_value() { local key key="$1" - normalize_whitespace "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//' | tr -s '[:blank:]' ' ')" + # Find the key in the meta data file # Extract field value # Remove the following /'s "(Unabridged) at start end and multiples. + echo "$($GREP --max-count=1 --only-matching "${key} *: .*" "$metadata_file" | cut -d : -f 2- | sed -e 's#/##g;s/ (Unabridged)//;s/^[[:blank:]]\+//g;s/[[:blank:]]\+$//g' | sed 's/[[:blank:]]\+/ /g')" } # ----- @@ -224,12 +226,6 @@ get_bitrate() { get_metadata_value bitrate | $GREP --only-matching '[0-9]\+' } -# ----- -# simple function to turn tabs and multiple spaces into a single space. -normalize_whitespace() { - echo $* -} - # ======================================================================== # Main Transcode Loop for aax_file @@ -247,7 +243,7 @@ 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' | sed 's/- /-/g' | xargs -0) + title=$(get_metadata_value title | sed 's/'\:'/'-'/g' | sed 's/- /-/g' | xargs -0) if [ "x${targetdir}" != "x" ] ; then output_directory="${targetdir}/${genre}/${artist}/${title}" else @@ -302,7 +298,7 @@ do log "Extracting ${chaptercount} chapter files from ${output_file}..." chapternum=1 - while read -r -u9 first _ _ start _ end + while read -r -u9 first _ _ chapter_start _ chapter_end do if [[ "${first}" = "Chapter" ]]; then read -r -u9 _ @@ -322,19 +318,19 @@ do fi # Big Long chapter debug - debug_vars "Chapter Variables:" cover_file start 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 # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. - log "Spliting chapter ${chapternum} start:${start%?}(s) end:${end}(s)" - > "${playlist_file}" echo "${chapter_title}.${container}" >> "${playlist_file}" chapternum=$((chapternum + 1 )) @@ -373,8 +369,9 @@ do fi fi - - log "Done ${title}" + # ----- + # Announce that we have completed the transcode + log "Complete ${title}" # Lastly get rid of any extra stuff. rm "${metadata_file}" From 03f1a58638daf8018bf50dde2795e4a11d0687d0 Mon Sep 17 00:00:00 2001 From: upuv Date: Wed, 6 Jun 2018 00:39:33 +1000 Subject: [PATCH 47/49] Verify aax files options Improvements --- AAXtoMP3 | 77 +++++++++++++++++++++++++++++++++++++++++++++++-------- README.md | 15 ++++++++--- 2 files changed, 79 insertions(+), 13 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index f8a4774..9761f38 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,7 +5,7 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:m4a] [-e:m4b] [--authcode ] [--output_dir ]\n[--complete_dir ] {FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--chaptered]\n[-e:mp3] [-e:m4a] [-e:m4b] [--authcode ]\n[--output_dir ] [--complete_dir ] [--validate]\n{FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extention. mode=chaptered # Multi file output @@ -13,6 +13,7 @@ auth_code= # Required to be set via file or option. targetdir= # Optional output location. Note default is basedir of AAX file. completedir= # Optional location to move aax files once the decoding is complete. container=mp3 # Just in case we need to change the container. Used for M4A to M4B +VALIDATE=0 # Validate the input aax file(s) only. No Transcoding of files will occur DEBUG=0 # Default off, If set extremely verbose output. # ----- @@ -45,7 +46,9 @@ while true; do # Authorization code associate with the AAX file(s) -A | --authcode ) auth_code="$2"; shift 2 ;; # Extremely verbose output. - -d | --debug ) DEBUG=1; shift ;; + -d | --debug ) DEBUG=1; shift ;; + # Validate ONLY the aax file(s) No transcoding occures + -V | --validate ) VALIDATE=1; shift ;; # Command synopsis. -h | --help ) printf "$usage" $0 ; exit ;; # Standard flag signifying the end of command line processing. @@ -194,11 +197,62 @@ if [[ "x${completedir}" != "x" ]]; then fi # ----- -# Clean up if someone hits ^c +# Clean up if someone hits ^c or the script exits for any reason. 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" +# ----- +# Validate the AAX and extract the metadata associated with the file. +validate_aax() { + local media_file + media_file="$1" + + # Test for existance + if [[ ! -r "${media_file}" ]] ; then + log "ERROR File NOT Found: ${media_file}" + return + else + if [[ "${VALIDATE}" == "1" ]]; then + log "Test 1 SUCCESS: ${media_file}" + fi + fi + + # 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)" + + # If invalid then say something. + if [[ $? != "0" ]] ; then + # No matter what lets bark that something is wrong. + log "ERROR: Invalid File: ${media_file}" + elif [[ "${VALIDATE}" == "1" ]]; then + # If the validate option is present then lets at least state what is valid. + log "Test 2 SUCCESS: ${media_file}" + fi + + # This is a big test only performed when the --validate swicth is passed. + if [[ "${VALIDATE}" == "1" ]]; then + output="$(ffmpeg -hide_banner -activation_bytes ${auth_code} -i "${media_file}" -vn -f null - 2>&1)" + if [[ $? != "0" ]] ; then + log "ERROR: Invalid File: ${media_file}" + else + log "Test 3 SUCCESS: ${media_file}" + fi + fi + + # Dump the output of the ffprobe command. + debug "$output" + + # Turn it back on. ffprobe is done. + set -e errexit +} + # ----- # Inspect the AAX and extract the metadata associated with the file. save_metadata() { @@ -231,11 +285,14 @@ get_bitrate() { for aax_file do - # Check for Presense of Audiobook. Note this break the processing of - # of a list of books once a single missing file is found. - if [[ ! -r "${aax_file}" ]] ; then - echo "ERROR: Input Audiobook file $aax_file missing" - exit 1 + # Validate the input aax file. Note this happens no matter what. + # It's just that if the validate option is set then we skip to next file. + # If however vlaidate is not set and we proceed with the script any errors will + # case the script to stop. + validate_aax "${aax_file}" + if [[ ${VALIDATE} == "1" ]] ; then + # Don't bother doing anything else with this file. + continue fi # ----- @@ -263,7 +320,6 @@ do log "$(printf '\n----Decoding---%s%s--%s--' "${title}" "${dashline:${#title}}" "${auth_code}")" log "Source ${aax_file}" - # Big long DEBUG output. Fully describes the settings used for transcoding. # Not 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. @@ -272,6 +328,7 @@ do # ----- # 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}"' ] [-t|--target_dir ] [-C|--complete_dir ] [-d|--debug] [-h|--help] ... +bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [-A|--authcode ] [-t|--target_dir ] [-C|--complete_dir ] [-V|--validate] [-d|--debug] [-h|--help] ... ``` * **<AAX INPUT_FILES>**... are considered input file(s), useful for batching! @@ -40,6 +40,7 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-c|--chaptered] [ * **-A** or **--authcode <AUTHCODE>** for this execution of the command use the provided <AUTHCODE> to decode the AAX file. * **-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. +* **-V** or **--validate** Perform 2 validation tests on the supplied aax files. This is more extensive than the normal validation as we attempt to transcode the aax file to a null file. This can take a long period of time. However it is usefull when inspecting a large set of aax files prior to transcoding. As download errors are common with Audible servers. * **-e:mp3** Identical to defaults. * **-e:m4a** Create a m4a audio file. This is identical to --aac * **-e:m4b** Create a m4b aduio file. This is the book version of the m4a format. @@ -63,7 +64,6 @@ In order of __precidence__. 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 occure. - ### MP3 Encoding * This is the **default** encoding * Produces 1 or more mp3 files for the AAX title. @@ -89,7 +89,7 @@ __Note:__ At least one of the above must be exist. The code must also match the * FLAC is an open format with royalty-free licensing * Note: There is an bug with the ffmpeg software that prevents the splitting of flac files. Chaptered output of flac files will fail. -### M4A and M4B Containers ### +### M4A and M4B Containers * These containers were created by Apple Inc. They were meant to be the successor to mp3. * M4A is a container that is meant to hold music and is typically of a higher bitrate. * M4B is a container that is meant to hold audiobooks and is typically has bitrates of 64k and 32k. @@ -97,6 +97,15 @@ __Note:__ At least one of the above must be exist. The code must also match the * Both support coverart internall * The default mode is **single** +### Validating AAX files +* The **--validate** option will result in only a validation pass over the supplied aax file(s). No transcoding will occure. This is usefull when you wish to ensure you have a proper download of your personal Audible audio books. With this option all supplied books are validated. +* If you do NOT supply the **--validate** option all audio books are still validated when they are processed. However if there is an invalid audio book in the supplied list of books the processing will stop at that point. +* A third test is performed on the file where the entire file is inspected to see if it is valid. This is a lengthy process. However it will not break the script when an invalid file is found. +* The 3 test current are: + 1. aax present + 1. meta data header in file is valid and complete + 1. entire file is valid and complete. _only executed with the **--validate** option._ + ### Defaults * Default out put directory is the base directoy of each file listed. Plus the genre, Artist and Title of the Audio Book. * The default codec is mp3 From 1af3f0ebcc42494334d92f503d52aa7ca7b502fd Mon Sep 17 00:00:00 2001 From: upuv Date: Thu, 21 Jun 2018 17:07:47 +1000 Subject: [PATCH 48/49] Added checks for ffmpeg and ffprobe. --- AAXtoMP3 | 25 +++++++++++++++++++++++++ README.md | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/AAXtoMP3 b/AAXtoMP3 index 9761f38..177368a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -146,6 +146,31 @@ if ! [[ $(type -P "$GREP") ]]; then exit 1 fi +# ----- +# Detect ffmpeg and ffprobe +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:" + echo "MacOS: brew install ffmpeg" + echo "Ubuntu: sudo apt-get update; sudo apt-get install ffmpeg libav-tools x264 x265" + echo "RHEL: yum install ffmpeg" + exit 1 +fi + +# ----- +# Detect ffmpeg and ffprobe +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:" + echo "MacOS: brew install ffmpeg" + echo "Ubuntu: sudo apt-get update; sudo apt-get install ffmpeg libav-tools x264 x265" + echo "RHEL: yum install ffmpeg" + exit 1 +fi + + # ----- # Detect if we need mp4art for cover additions to m4a & m4b files. if [[ "x${extension}" == "xm4a" && "x$(type -P mp4art)" == "x" ]]; then diff --git a/README.md b/README.md index b31a6f0..2776bea 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,43 @@ __Note:__ At least one of the above must be exist. The code must also match the * Default out put directory is the base directoy of each file listed. Plus the genre, Artist and Title of the Audio Book. * The default codec is mp3 * The default output is by chapter. + +### Installing Dependencies. +#### FFMPEG,FFPROBE +__Ubuntu, Linux Mint, Debian__ +``` +sudo apt-get update +sudo apt-get install ffmpeg libav-tools x264 x265 +``` +__CentOS, RHEL & Fedora__ +``` +# CentOS/RHEL and Fedora users make sure that you have enabled atrpms repository in system. Let’s begin installing FFmpeg as per your operating system. +yum install ffmpeg + +``` +__MacOS__ +``` +brew install ffmpeg +``` + +#### mp4art +_Note: This is an optional dependency._ + +__Ubuntu, Linux Mint, Debian__ +``` +sudo apt-get update +sudo apt-get install mp4v2-utils +``` +__CentOS, RHEL & Fedora__ +``` +# CentOS/RHEL and Fedora users make sure that you have enabled atrpms repository in system. Let’s begin installing FFmpeg as per your operating system. +yum install mp4v2-utils + +``` +__MacOS__ +``` +brew install mp4v2 +``` ## Anti-Piracy Notice Note that this project **does NOT ‘crack’** the DRM. It simply allows the user to From 101861f41cdc862a1122371b507be39f219d5911 Mon Sep 17 00:00:00 2001 From: upuv Date: Thu, 21 Jun 2018 17:21:18 +1000 Subject: [PATCH 49/49] Fix for chapter length. --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 177368a..af7e8db 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -405,7 +405,7 @@ do # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. log "Spliting chapter ${chapternum} start:${chapter_start%?}(s) end:${chapter_end}(s)" -