mirror of
https://github.com/KrumpetPirate/AAXtoMP3.git
synced 2024-11-17 18:58:58 +01:00
commit
43d96f0118
49
AAXtoMP3
49
AAXtoMP3
@ -34,6 +34,7 @@ authorOverride= # Override the author, ignoring the metadata
|
|||||||
audibleCli=0 # Default off, Use additional data gathered from mkb79/audible-cli
|
audibleCli=0 # Default off, Use additional data gathered from mkb79/audible-cli
|
||||||
aaxc_key= # Initialize variables, in case we need them in debug_vars
|
aaxc_key= # Initialize variables, in case we need them in debug_vars
|
||||||
aaxc_iv= # Initialize variables, in case we need them in debug_vars
|
aaxc_iv= # Initialize variables, in case we need them in debug_vars
|
||||||
|
ffmpegPath= # Set a custom path, useful for using the updated version that supports aaxc
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Code tip Do not have any script above this point that calls a function or a binary. If you do
|
# Code tip Do not have any script above this point that calls a function or a binary. If you do
|
||||||
@ -88,6 +89,8 @@ while true; do
|
|||||||
--keep-author ) keepArtist="$2"; shift 2 ;;
|
--keep-author ) keepArtist="$2"; shift 2 ;;
|
||||||
# Author override
|
# Author override
|
||||||
--author ) authorOverride="$2"; shift 2 ;;
|
--author ) authorOverride="$2"; shift 2 ;;
|
||||||
|
# Ffmpeg path override
|
||||||
|
--ffmpeg-path ) ffmpegPath="$2"; shift 2 ;;
|
||||||
# Command synopsis.
|
# Command synopsis.
|
||||||
-h | --help ) printf "$usage" $0 ; exit ;;
|
-h | --help ) printf "$usage" $0 ; exit ;;
|
||||||
# Standard flag signifying the end of command line processing.
|
# Standard flag signifying the end of command line processing.
|
||||||
@ -212,6 +215,16 @@ else
|
|||||||
SED="gsed"
|
SED="gsed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Use custom ffmpeg (and ffprobe) binary ( --ffmpeg-path flag)
|
||||||
|
if [ -n "$ffmpegPath" ]; then
|
||||||
|
FFMPEG="$ffmpegPath/ffmpeg"
|
||||||
|
FFPROBE="$ffmpegPath/ffprobe"
|
||||||
|
else
|
||||||
|
FFMPEG="ffmpeg"
|
||||||
|
FFPROBE="ffprobe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug_vars "ffmpeg/ffprobe paths" FFMPEG FFPROBE
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Detect which annoying version of grep we have
|
# Detect which annoying version of grep we have
|
||||||
@ -242,7 +255,7 @@ fi
|
|||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Detect ffmpeg and ffprobe
|
# Detect ffmpeg and ffprobe
|
||||||
if [[ "x$(type -P ffmpeg)" == "x" ]]; then
|
if [[ "x$(type -P "$FFMPEG")" == "x" ]]; then
|
||||||
echo "ERROR ffmpeg was not found on your env PATH variable"
|
echo "ERROR ffmpeg was not found on your env PATH variable"
|
||||||
echo "Without it, this script will break."
|
echo "Without it, this script will break."
|
||||||
echo "INSTALL:"
|
echo "INSTALL:"
|
||||||
@ -255,7 +268,7 @@ fi
|
|||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Detect ffmpeg and ffprobe
|
# Detect ffmpeg and ffprobe
|
||||||
if [[ "x$(type -P ffprobe)" == "x" ]]; then
|
if [[ "x$(type -P "$FFPROBE")" == "x" ]]; then
|
||||||
echo "ERROR ffprobe was not found on your env PATH variable"
|
echo "ERROR ffprobe was not found on your env PATH variable"
|
||||||
echo "Without it, this script will break."
|
echo "Without it, this script will break."
|
||||||
echo "INSTALL:"
|
echo "INSTALL:"
|
||||||
@ -381,13 +394,6 @@ trap 'rm -r -f "${working_directory}"' EXIT
|
|||||||
# Set up some basic working files ASAP. Note the trap will clean this up no matter what.
|
# 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'`
|
working_directory=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'`
|
||||||
metadata_file="${working_directory}/metadata.txt"
|
metadata_file="${working_directory}/metadata.txt"
|
||||||
# Creating a temp file to store the chapter data collected in save_metadata, as the output
|
|
||||||
# folder will only be defined after save_metadata has been executed.
|
|
||||||
# This file is only required when using audible-cli data and executing in single mode to
|
|
||||||
# get proper chapter titles in single file m4b output.
|
|
||||||
if [[ "${audibleCli}" == "1" && "${mode}" == "single" ]] ; then
|
|
||||||
tmp_chapter_file="${working_directory}/chapter.txt"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Validate the AAX and extract the metadata associated with the file.
|
# Validate the AAX and extract the metadata associated with the file.
|
||||||
@ -409,7 +415,7 @@ validate_aax() {
|
|||||||
set +e errexit
|
set +e errexit
|
||||||
|
|
||||||
# Take a look at the aax file and see if it is valid. If the source file is aaxc, we give ffprobe additional flags
|
# Take a look at the aax file and see if it is valid. If the source file is aaxc, we give ffprobe additional flags
|
||||||
output="$(ffprobe -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)"
|
output="$("$FFPROBE" -loglevel warning ${decrypt_param} -i "${media_file}" 2>&1)"
|
||||||
|
|
||||||
# If invalid then say something.
|
# If invalid then say something.
|
||||||
if [[ $? != "0" ]] ; then
|
if [[ $? != "0" ]] ; then
|
||||||
@ -422,7 +428,7 @@ validate_aax() {
|
|||||||
|
|
||||||
# This is a big test only performed when the --validate switch is passed.
|
# This is a big test only performed when the --validate switch is passed.
|
||||||
if [[ "${VALIDATE}" == "1" ]]; then
|
if [[ "${VALIDATE}" == "1" ]]; then
|
||||||
output="$(ffmpeg -hide_banner ${decrypt_param} -i "${media_file}" -vn -f null - 2>&1)"
|
output="$("$FFMPEG" -hide_banner ${decrypt_param} -i "${media_file}" -vn -f null - 2>&1)"
|
||||||
if [[ $? != "0" ]] ; then
|
if [[ $? != "0" ]] ; then
|
||||||
log "ERROR: Invalid File: ${media_file}"
|
log "ERROR: Invalid File: ${media_file}"
|
||||||
else
|
else
|
||||||
@ -492,7 +498,7 @@ validate_extra_files() {
|
|||||||
save_metadata() {
|
save_metadata() {
|
||||||
local media_file
|
local media_file
|
||||||
media_file="$1"
|
media_file="$1"
|
||||||
ffprobe -i "$media_file" 2> "$metadata_file"
|
"$FFPROBE" -i "$media_file" 2> "$metadata_file"
|
||||||
if [[ $(type -P mediainfo) ]]; then
|
if [[ $(type -P mediainfo) ]]; then
|
||||||
echo "Mediainfo data START" >> "$metadata_file"
|
echo "Mediainfo data START" >> "$metadata_file"
|
||||||
# Mediainfo output is structured like ffprobe, so we append it to the metadata file and then parse it with get_metadata_value()
|
# Mediainfo output is structured like ffprobe, so we append it to the metadata file and then parse it with get_metadata_value()
|
||||||
@ -521,6 +527,11 @@ save_metadata() {
|
|||||||
# chapter titles from the .json generated by audible–cli and store
|
# chapter titles from the .json generated by audible–cli and store
|
||||||
# them correctly formatted for mp4chaps in a chapter.txt
|
# them correctly formatted for mp4chaps in a chapter.txt
|
||||||
if [ "${mode}" == "single" ]; then
|
if [ "${mode}" == "single" ]; then
|
||||||
|
# Creating a temp file to store the chapter data collected in save_metadata, as the output
|
||||||
|
# folder will only be defined after save_metadata has been executed.
|
||||||
|
# This file is only required when using audible-cli data and executing in single mode to
|
||||||
|
# get proper chapter titles in single file m4b output.
|
||||||
|
tmp_chapter_file="${working_directory}/chapter.txt"
|
||||||
jq -r \
|
jq -r \
|
||||||
'def pad(n): tostring | if (n > length) then ((n - length) * "0") + . else . end;
|
'def pad(n): tostring | if (n > length) then ((n - length) * "0") + . else . end;
|
||||||
.content_metadata.chapter_info.chapters |
|
.content_metadata.chapter_info.chapters |
|
||||||
@ -693,7 +704,7 @@ do
|
|||||||
|
|
||||||
# Display the total length of the audiobook in format hh:mm:ss
|
# Display the total length of the audiobook in format hh:mm:ss
|
||||||
# 10#$var force base-10 interpretation. By default it's base-8, so values like 08 or 09 are not octal numbers
|
# 10#$var force base-10 interpretation. By default it's base-8, so values like 08 or 09 are not octal numbers
|
||||||
total_length="$(ffprobe -v error ${decrypt_param} -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${aax_file}" | cut -d . -f 1)"
|
total_length="$("$FFPROBE" -v error ${decrypt_param} -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${aax_file}" | cut -d . -f 1)"
|
||||||
hours="$((total_length/3600))"
|
hours="$((total_length/3600))"
|
||||||
if [ "$((hours<10))" = "1" ]; then hours="0$hours"; fi
|
if [ "$((hours<10))" = "1" ]; then hours="0$hours"; fi
|
||||||
minutes="$((total_length/60-60*10#$hours))"
|
minutes="$((total_length/60-60*10#$hours))"
|
||||||
@ -712,8 +723,8 @@ do
|
|||||||
if [ "${continue}" == "0" ]; then
|
if [ "${continue}" == "0" ]; then
|
||||||
# This is the main work horse command. This is the primary transcoder.
|
# This is the main work horse command. This is the primary transcoder.
|
||||||
# This is the primary transcode. All the heavy lifting is here.
|
# This is the primary transcode. All the heavy lifting is here.
|
||||||
debug 'ffmpeg -loglevel error -stats ${decrypt_param} -i "${aax_file}" -vn -codec:a "${codec}" -ab ${bitrate} -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="${album_artist}" -metadata album="${album}" -metadata date="${album_date}" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="${copyright}" "${output_file}"'
|
debug '"$FFMPEG" -loglevel error -stats ${decrypt_param} -i "${aax_file}" -vn -codec:a "${codec}" -ab ${bitrate} -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="${album_artist}" -metadata album="${album}" -metadata date="${album_date}" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="${copyright}" "${output_file}"'
|
||||||
</dev/null ffmpeg -loglevel error \
|
</dev/null "$FFMPEG" -loglevel error \
|
||||||
-stats \
|
-stats \
|
||||||
${decrypt_param} \
|
${decrypt_param} \
|
||||||
-i "${aax_file}" \
|
-i "${aax_file}" \
|
||||||
@ -761,7 +772,7 @@ do
|
|||||||
if [ "$((${loglevel} > 1))" == "1" ]; then
|
if [ "$((${loglevel} > 1))" == "1" ]; then
|
||||||
log "Extracting cover into ${cover_file}..."
|
log "Extracting cover into ${cover_file}..."
|
||||||
fi
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -842,7 +853,7 @@ do
|
|||||||
#ffmpeg version 4+ and on the output for all older versions.
|
#ffmpeg version 4+ and on the output for all older versions.
|
||||||
split_input=""
|
split_input=""
|
||||||
split_output=""
|
split_output=""
|
||||||
if [ "$(($(ffmpeg -version | $SED -E 's/[^0-9]*([0-9]).*/\1/g;1q') > 3))" = "1" ]; then
|
if [ "$(($("$FFMPEG" -version | $SED -E 's/[^0-9]*([0-9]).*/\1/g;1q') > 3))" = "1" ]; then
|
||||||
split_input="-ss ${chapter_start%?} -to ${chapter_end}"
|
split_input="-ss ${chapter_start%?} -to ${chapter_end}"
|
||||||
else
|
else
|
||||||
split_output="-ss ${chapter_start%?} -to ${chapter_end}"
|
split_output="-ss ${chapter_start%?} -to ${chapter_end}"
|
||||||
@ -856,7 +867,7 @@ do
|
|||||||
if [ "$((${loglevel} > 1))" == "1" ]; then
|
if [ "$((${loglevel} > 1))" == "1" ]; then
|
||||||
log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)"
|
log "Splitting chapter ${chapternum}/${chaptercount} start:${chapter_start%?}(s) end:${chapter_end}(s)"
|
||||||
fi
|
fi
|
||||||
</dev/null ffmpeg -loglevel quiet \
|
</dev/null "$FFMPEG" -loglevel quiet \
|
||||||
-nostats \
|
-nostats \
|
||||||
${split_input} \
|
${split_input} \
|
||||||
-i "${output_file}" \
|
-i "${output_file}" \
|
||||||
@ -907,7 +918,7 @@ do
|
|||||||
if [ "${audibleCli}" == "1" ]; then
|
if [ "${audibleCli}" == "1" ]; then
|
||||||
mv "${tmp_chapter_file}" "${output_directory}/${currentFileNameScheme}.chapters.txt"
|
mv "${tmp_chapter_file}" "${output_directory}/${currentFileNameScheme}.chapters.txt"
|
||||||
else
|
else
|
||||||
ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt"
|
"$FFPROBE" -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%d=%02d:%02d:%02.3f\nCHAPTER%dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${currentFileNameScheme}.chapters.txt"
|
||||||
fi
|
fi
|
||||||
mp4chaps -i "${output_file}"
|
mp4chaps -i "${output_file}"
|
||||||
fi
|
fi
|
||||||
|
@ -57,6 +57,7 @@ bash interactiveAAXtoMP3 [-a|--advanced] [-h|--help]
|
|||||||
* **--file-naming-scheme <STRING>** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
|
* **--file-naming-scheme <STRING>** or **-F** Use a custom file naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
|
||||||
* **--chapter-naming-scheme <STRING>** Use a custom chapter naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
|
* **--chapter-naming-scheme <STRING>** Use a custom chapter naming scheme, with variables. See [below](#custom-naming-scheme) for more info.
|
||||||
* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more info. Needed for the files in the `aaxc` format.
|
* **--use-audible-cli-data** Use additional data got with mkb79/audible-cli. See [below](#audible-cli-integration) for more info. Needed for the files in the `aaxc` format.
|
||||||
|
* **--ffmpeg-path** Set the ffmpeg/ffprobe binaries folder. Both of them must be executable and in the same folder.
|
||||||
|
|
||||||
## Options for interactiveAAXtoMP3
|
## Options for interactiveAAXtoMP3
|
||||||
* **-a** or **--advanced** Get more options to choose. Not used right now.
|
* **-a** or **--advanced** Get more options to choose. Not used right now.
|
||||||
@ -164,6 +165,9 @@ In Debian-based system's repositories the ffmpeg version is often outdated. If y
|
|||||||
to convert .aaxc files, you need at least ffmpeg 4.4. So if your installed version
|
to convert .aaxc files, you need at least ffmpeg 4.4. So if your installed version
|
||||||
needs to be updated, you can either install a custom repository that has the newer version,
|
needs to be updated, you can either install a custom repository that has the newer version,
|
||||||
compile ffmpeg from source or download pre-compiled binaries.
|
compile ffmpeg from source or download pre-compiled binaries.
|
||||||
|
You can then tell AAXtoMP3 to use the compiled binaries with the `--ffmpeg-path` flag.
|
||||||
|
You need to specify the folder where the ffmpeg and ffprobe binaries are. Make sure
|
||||||
|
they are both executable.
|
||||||
|
|
||||||
__Fedora__
|
__Fedora__
|
||||||
|
|
||||||
@ -244,6 +248,7 @@ Since getting those keys is not simple, for now the method used to get them
|
|||||||
is handled by the package audible-cli, that stores
|
is handled by the package audible-cli, that stores
|
||||||
them in a file when downloading the aaxc file. This means that in order to
|
them in a file when downloading the aaxc file. This means that in order to
|
||||||
decrypt the aaxc files, they must be downloaded with audible-cli.
|
decrypt the aaxc files, they must be downloaded with audible-cli.
|
||||||
|
Note that you need at least [ffmpeg 4.4](#ffmpegffprobe).
|
||||||
|
|
||||||
## Audible-cli integration
|
## Audible-cli integration
|
||||||
Some information are not present in the AAX file. For example the chapters's
|
Some information are not present in the AAX file. For example the chapters's
|
||||||
|
Loading…
Reference in New Issue
Block a user