Merge branch 'master' of github.com:KrumpetPirate/AAXtoMP3 into custom-output-folder

This commit is contained in:
fabh2o 2021-02-10 20:59:48 +01:00
commit 3c909baf5e
2 changed files with 101 additions and 22 deletions

121
AAXtoMP3
View File

@ -5,7 +5,7 @@
# Command Line Options # Command Line Options
# Usage Synopsis. # Usage Synopsis.
usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level <COMPRESSIONLEVEL>]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode <AUTHCODE>] [--no-clobber]\n[--target_dir <PATH>] [--complete_dir <PATH>] [--validate]\n[--{dir,file,chapter}-naming-scheme <STRING>]\n[--continue <CHAPTERNUMBER>]{FILES}\n' usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level <COMPRESSIONLEVEL>]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode <AUTHCODE>] [--no-clobber]\n[--target_dir <PATH>] [--complete_dir <PATH>] [--validate]\n[--{dir,file,chapter}-naming-scheme <STRING>] [--loglevel <LOGLEVEL>]\n[--continue <CHAPTERNUMBER>] {FILES}\n'
codec=libmp3lame # Default encoder. codec=libmp3lame # Default encoder.
extension=mp3 # Default encoder extension. extension=mp3 # Default encoder extension.
level=-1 # Compression level. Can be given for mp3, flac and opus. -1 = default/not specified. level=-1 # Compression level. Can be given for mp3, flac and opus. -1 = default/not specified.
@ -21,7 +21,7 @@ customCNS=0
completedir= # Optional location to move aax files once the decoding is complete. 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 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 VALIDATE=0 # Validate the input aax file(s) only. No Transcoding of files will occur
DEBUG=0 # Default off, If set extremely verbose output. loglevel=1 # Loglevel: 0: Show progress only; 1: default; 2: a little more information, timestamps; 3: debug
noclobber=0 # Default off, clobber only if flag is enabled noclobber=0 # Default off, clobber only if flag is enabled
continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt. continue=0 # Default off, If set Transcoding is skipped and chapter splitting starts at chapter continueAt.
continueAt=1 # Optional chapter to continue splitting the chapters. continueAt=1 # Optional chapter to continue splitting the chapters.
@ -64,7 +64,9 @@ while true; do
# Don't overwrite the target directory if it already exists # Don't overwrite the target directory if it already exists
-n | --no-clobber ) noclobber=1; shift ;; -n | --no-clobber ) noclobber=1; shift ;;
# Extremely verbose output. # Extremely verbose output.
-d | --debug ) DEBUG=1; shift ;; -d | --debug ) loglevel=3; shift ;;
# Set loglevel.
-l | --loglevel ) loglevel="$2"; shift 2 ;;
# Validate ONLY the aax file(s) No transcoding occurs # Validate ONLY the aax file(s) No transcoding occurs
-V | --validate ) VALIDATE=1; shift ;; -V | --validate ) VALIDATE=1; shift ;;
# continue splitting chapters at chapter continueAt # continue splitting chapters at chapter continueAt
@ -98,7 +100,7 @@ set -o errexit -o noclobber -o nounset -o pipefail
# debug # debug
# debug "Some longish message" # debug "Some longish message"
debug() { debug() {
if [ $DEBUG == 1 ] ; then if [ $loglevel == 3 ] ; then
echo "$(date "+%F %T%z") DEBUG ${1}" echo "$(date "+%F %T%z") DEBUG ${1}"
fi fi
} }
@ -107,7 +109,7 @@ debug() {
# debug dump contents of a file to STDOUT # debug dump contents of a file to STDOUT
# debug "<full path to file>" # debug "<full path to file>"
debug_file() { debug_file() {
if [ $DEBUG == 1 ] ; then if [ $loglevel == 3 ] ; then
echo "$(date "+%F %T%z") DEBUG" echo "$(date "+%F %T%z") DEBUG"
echo "=Start==========================================================================" echo "=Start=========================================================================="
cat "${1}" cat "${1}"
@ -119,7 +121,7 @@ debug_file() {
# debug dump a list of internal script variables to STDOUT # debug dump a list of internal script variables to STDOUT
# debug_vars "Some Message" var1 var2 var3 var4 var5 # debug_vars "Some Message" var1 var2 var3 var4 var5
debug_vars() { debug_vars() {
if [ $DEBUG == 1 ] ; then if [ $loglevel == 3 ] ; then
msg="$1"; shift ; # Grab the message msg="$1"; shift ; # Grab the message
args=("$@") # Grab the rest of the args args=("$@") # Grab the rest of the args
@ -148,10 +150,37 @@ debug_vars() {
# ----- # -----
# log # log
log() { log() {
echo "$(date "+%F %T%z") ${1}" if [ "$((${loglevel} > 1))" == "1" ] ; then
echo "$(date "+%F %T%z") ${1}"
else
echo "${1}"
fi
} }
# ----- # -----
#progressbar produces a progressbar in the style of
# process: |####### | XX% (part/total unit)
# which is gonna be overwritten by the next line.
progressbar() {
#get input
part=${1}
total=${2}
#compute percentage and make print_percentage the same length regardless of the number of digits.
percentage=$((part*100/total))
if [ "$((percentage<10))" = "1" ]; then print_percentage=" $percentage"
elif [ "$((percentage<100))" = "1" ]; then print_percentage=" $percentage"
else print_percentage="$percentage"; fi
#draw progressbar with one # for every 5% and blank spaces for the missing part.
progressbar=""
for (( n=0; n<(percentage/5); n++ )) ; do progressbar="$progressbar#"; done
for (( n=0; n<(20-(percentage/5)); n++ )) ; do progressbar="$progressbar "; done
#print progressbar
echo -ne "Chapter splitting: |$progressbar| $print_percentage% ($part/$total chapters)\r"
}
# Print out what we have already after command line processing. # Print out what we have already after command line processing.
debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code debug_vars "Command line options as set" codec extension mode container targetdir completedir auth_code
@ -278,6 +307,17 @@ if [[ "x${completedir}" != "x" ]]; then
fi fi
fi fi
# -----
# Check whether the loglevel is valid
if [ "$((${loglevel} < 0 || ${loglevel} > 3 ))" = "1" ]; then
echo "ERROR loglevel has to be in the range from 0 to 3!"
echo " 0: Show progress only"
echo " 1: default"
echo " 2: a little more information, timestamps"
echo " 3: debug"
echo "$usage"
exit 1
fi
# ----- # -----
# If a compression level is given, check whether the given codec supports compression level specifiers and whether the level is valid. # If a compression level is given, check whether the given codec supports compression level specifiers and whether the level is valid.
if [ "${level}" != "-1" ]; then if [ "${level}" != "-1" ]; then
@ -472,16 +512,28 @@ do
fi fi
mkdir -p "${output_directory}" mkdir -p "${output_directory}"
# Fancy declaration of which book we are decoding. Including the AUTHCODE. if [ "$((${loglevel} > 0))" = "1" ]; then
dashline="----------------------------------------------------" # Fancy declaration of which book we are decoding. Including the AUTHCODE.
log "$(printf '\n----Decoding---%s%s--%s--' "${title}" "${dashline:${#title}}" "${auth_code}")" dashline="----------------------------------------------------"
log "Source ${aax_file}" log "$(printf '\n----Decoding---%s%s--%s--' "${title}" "${dashline:${#title}}" "${auth_code}")"
log "Source: ${aax_file}"
fi
# Big long DEBUG output. Fully describes the settings used for transcoding. # Big long DEBUG output. Fully describes the settings used for transcoding.
# Note this is a long debug command. It's not critical to operation. It's purely for people debugging # Note this is a long debug command. It's not critical to operation. It's purely for people debugging
# and coders wanting to extend the script. # and coders wanting to extend the script.
debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher currentDirNameScheme output_directory currentFileNameScheme output_file metadata_file working_directory debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher currentDirNameScheme output_directory currentFileNameScheme output_file metadata_file working_directory
# Display the total length of the audiobook in format hh:mm:ss
total_length="$(ffprobe -v error -activation_bytes "${auth_code}" -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 ${aax_file} | cut -d . -f 1)"
hours="$((total_length/3600))"
if [ "$((hours<10))" = "1" ]; then hours="0$hours"; fi
minutes="$((total_length/60-60*hours))"
if [ "$((minutes<10))" = "1" ]; then minutes="0$minutes"; fi
seconds="$((total_length-3600*hours-60*minutes))"
if [ "$((seconds<10))" = "1" ]; then seconds="0$seconds"; fi
log "Total length: $hours:$minutes:$seconds"
# If level != -1 specify a compression level in ffmpeg. # If level != -1 specify a compression level in ffmpeg.
compression_level_param="" compression_level_param=""
if [ "${level}" != "-1" ]; then if [ "${level}" != "-1" ]; then
@ -515,14 +567,17 @@ do
-metadata publisher="${publisher}" \ -metadata publisher="${publisher}" \
-f ${container} \ -f ${container} \
"${output_file}" "${output_file}"
if [ "$((${loglevel} > 0))" == "1" ]; then
log "Created ${output_file}." log "Created ${output_file}."
fi
# ----- # -----
fi fi
# Grab the cover art if available. # Grab the cover art if available.
cover_file="${output_directory}/cover.jpg" cover_file="${output_directory}/cover.jpg"
if [ "${continue}" == "0" ]; then if [ "${continue}" == "0" ]; then
log "Extracting cover into ${cover_file}..." if [ "$((${loglevel} > 1))" == "1" ]; then
log "Extracting cover into ${cover_file}..."
fi
</dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${aax_file}" -an -codec:v copy "${cover_file}" </dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${aax_file}" -an -codec:v copy "${cover_file}"
fi fi
# ----- # -----
@ -534,17 +589,25 @@ do
# Playlist m3u support # Playlist m3u support
playlist_file="${output_directory}/${currentFileNameScheme}.m3u" playlist_file="${output_directory}/${currentFileNameScheme}.m3u"
if [ "${continue}" == "0" ]; then if [ "${continue}" == "0" ]; then
log "Creating PlayList ${currentFileNameScheme}.m3u" if [ "$((${loglevel} > 0))" == "1" ]; then
log "Creating PlayList ${currentFileNameScheme}.m3u"
fi
echo '#EXTM3U' > "${playlist_file}" echo '#EXTM3U' > "${playlist_file}"
fi fi
# Determine the number of chapters. # Determine the number of chapters.
chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file) chaptercount=$($GREP -Pc "Chapter.*start.*end" $metadata_file)
log "Extracting ${chaptercount} chapter files from ${output_file}..." if [ "$((${loglevel} > 0))" == "1" ]; then
if [ "${continue}" == "1" ]; then log "Extracting ${chaptercount} chapter files from ${output_file}..."
log "Continuing at chapter ${continueAt}:" if [ "${continue}" == "1" ]; then
log "Continuing at chapter ${continueAt}:"
fi
fi fi
chapternum=1 chapternum=1
#start progressbar for loglevel 0 and 1
if [ "$((${loglevel} < 2))" == "1" ]; then
progressbar 0 ${chaptercount}
fi
# We pipe the metadata_file in read. # We pipe the metadata_file in read.
# Example of the section that we are interested in: # Example of the section that we are interested in:
# #
@ -596,7 +659,9 @@ do
if [ "$((${continueAt} > ${chapternum}))" = "0" ]; then if [ "$((${continueAt} > ${chapternum}))" = "0" ]; then
# Extract chapter by time stamps start and finish of chapter. # Extract chapter by time stamps start and finish of chapter.
# This extracts based on time stamps start and end. # This extracts based on time stamps start and end.
log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)" if [ "$((${loglevel} > 1))" == "1" ]; then
log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)"
fi
</dev/null ffmpeg -loglevel quiet \ </dev/null ffmpeg -loglevel quiet \
-nostats \ -nostats \
-ss "${chapter_start%?}" \ -ss "${chapter_start%?}" \
@ -616,6 +681,9 @@ do
-f ${container} \ -f ${container} \
"${chapter_file}" "${chapter_file}"
# ----- # -----
if [ "$((${loglevel} < 2))" == "1" ]; then
progressbar ${chapternum} ${chaptercount}
fi
# OK lets get what need for the next chapter in the Playlist m3u file. # OK lets get what need for the next chapter in the Playlist m3u file.
# Playlist creation. # Playlist creation.
duration=$(echo "${chapter_end} - ${chapter_start%?}" | bc) duration=$(echo "${chapter_end} - ${chapter_start%?}" | bc)
@ -628,7 +696,12 @@ do
# Clean up of working directory stuff. # Clean up of working directory stuff.
rm "${output_file}" rm "${output_file}"
log "Done creating chapters for ${output_directory}." if [ "$((${loglevel} > 1))" == "1" ]; then
log "Done creating chapters for ${output_directory}."
else
#ending progress bar
echo ""
fi
else else
# Perform file tasks on output file. # Perform file tasks on output file.
# ---- # ----
@ -641,14 +714,18 @@ do
# ----- # -----
# Announce that we have completed the transcode # Announce that we have completed the transcode
log "Complete ${title}" if [ "$((${loglevel} > 0))" == "1" ]; then
log "Complete ${title}"
fi
# Lastly get rid of any extra stuff. # Lastly get rid of any extra stuff.
rm "${metadata_file}" rm "${metadata_file}"
# Move the aax file if the decode is completed and the --complete_dir is set to a valid location. # 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 # Check the target dir for if set if it is writable
if [[ "x${completedir}" != "x" ]]; then if [[ "x${completedir}" != "x" ]]; then
log "Moving Transcoded ${aax_file} to ${completedir}" if [ "$((${loglevel} > 0))" == "1" ]; then
log "Moving Transcoded ${aax_file} to ${completedir}"
fi
mv "${aax_file}" "${completedir}" mv "${aax_file}" "${completedir}"
fi fi

View File

@ -51,10 +51,12 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level <COMPRESS
* **-c** or **--chaptered** Output a single file per chapter. The `--chaptered` will only work if it follows the `--aac -e:m4a -e:m4b --flac` options. * **-c** or **--chaptered** Output a single file per chapter. The `--chaptered` will only work if it follows the `--aac -e:m4a -e:m4b --flac` options.
* **--continue &lt;CHAPTERNUMBER&gt;** If the splitting into chapters gets interrupted (e.g. by a weak battery on your laptop) you can go on where the process got interrupted. Just delete the last chapter (which was incompletely generated) and redo the task with "--continue &lt;CHAPTERNUMBER&gt;" where CHAPTERNUMBER is the chapter that got interrupted. * **--continue &lt;CHAPTERNUMBER&gt;** If the splitting into chapters gets interrupted (e.g. by a weak battery on your laptop) you can go on where the process got interrupted. Just delete the last chapter (which was incompletely generated) and redo the task with "--continue &lt;CHAPTERNUMBER&gt;" where CHAPTERNUMBER is the chapter that got interrupted.
* **--level &lt;COMPRESSIONLEVEL&gt;** Set compression level. May be given for mp3, flac and opus. * **--level &lt;COMPRESSIONLEVEL&gt;** Set compression level. May be given for mp3, flac and opus.
* **-l** or **--loglevel &lt;LOGLEVEL&gt;** Set loglevel: 0 = progress only, 1 (default) = more information, output of chapter splitting progress is limitted to a progressbar, 2 = more information, especially on chapter splitting, 3 = debug mode
* **--dir-naming-scheme &lt;STRING&gt;** or **-D** Use a custom directory naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--dir-naming-scheme &lt;STRING&gt;** or **-D** Use a custom directory naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
* **--file-naming-scheme &lt;STRING&gt;** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--file-naming-scheme &lt;STRING&gt;** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
* **--chapter-naming-scheme &lt;STRING&gt;** Use a custom chapter naming scheme, with variables. See [below](#custom-naming-scheme) for more info. * **--chapter-naming-scheme &lt;STRING&gt;** Use a custom chapter naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
### [AUTHCODE] ### [AUTHCODE]
**Your** Audible auth code (it won't correctly decode otherwise) (required). **Your** Audible auth code (it won't correctly decode otherwise) (required).