From bcaec020ce22cc7607e4d71ad7a1e92d93e28f70 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sat, 6 Feb 2021 22:27:52 +0100 Subject: [PATCH 01/10] first commit --- AAXtoMP3 | 75 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index ec2ce38..6a77c98 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -12,6 +12,9 @@ level=-1 # Compression level. Can be given for mp3, flac and mode=chaptered # Multi file output auth_code= # Required to be set via file or option. targetdir= # Optional output location. Note default is basedir of AAX file. +dirNameScheme= # Custom directory naming scheme, default is $genre/$author/$title +fileNameScheme= # Custom file naming scheme, default is $title +chapterNameScheme= # Custom chapter naming scheme, default is '$title-$(printf %0${#chaptercount}d $chapternum) $chapter' (BookTitle-01 Chapter 1) 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 @@ -45,6 +48,12 @@ while true; do -e:m4b ) codec=copy; extension=m4b; mode=single; container=mp4; shift ;; # Change the working dir from AAX directory to what you choose. -t | --target_dir ) targetdir="$2"; shift 2 ;; + # Use a custom directory naming scheme, with variables. + -D | --dir-naming-scheme ) dirNameScheme="$2"; shift 2 ;; + # Use a custom file naming scheme, with variables. + -F | --file-naming-scheme ) fileNameScheme="$2"; shift 2 ;; + # Use a custom chapter naming schemr, with variables. + --chapter-naming-scheme ) chapterNameScheme="$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) @@ -413,17 +422,12 @@ do artist=$(get_metadata_value artist) title=$(get_metadata_value title | $SED 's/'\:'/'-'/g' | $SED 's/- /-/g' | xargs -0) title=${title:0:100} - if [ "x${targetdir}" != "x" ] ; then - output_directory="${targetdir}/${genre}/${artist}/${title}" - else - output_directory="$(dirname "${aax_file}")/${genre}/${artist}/${title}" - fi - output_file="${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)" + # Get more tags with mediainfo if [[ $(type -P mediainfo) ]]; then narrator="$(get_metadata_value nrt)" @@ -435,6 +439,33 @@ do publisher="" fi + # dirNameScheme= + # fileNameScheme= + # chapterNameScheme= + # Define the output_directory + if [ "x${dirNameScheme}" != "x" ]; then + dirNameScheme="$(eval echo "${dirNameScheme}")" + else + # The Default + dirNameScheme="${genre}/${artist}/${title}" + fi + + # If we defined a target directory, use it. Otherwise use the location of the AAX file + if [ "x${targetdir}" != "x" ] ; then + output_directory="${targetdir}/${dirNameScheme}/" + else + output_directory="$(dirname "${aax_file}")/${dirNameScheme}/" + fi + + # Define the output_file + if [ "x${fileNameScheme}" != "x" ]; then + fileNameScheme="$(eval echo "${fileNameScheme}")" + else + # The Default + fileNameScheme="${title}" + fi + output_file="${output_directory}/${fileNameScheme}.${extension}" + if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" exit 0 @@ -449,7 +480,7 @@ do # Big long DEBUG output. Fully describes the settings used for transcoding. # Note this is a long debug command. It's not critical to operation. It's purely for people debugging # and coders wanting to extend the script. - debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher 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 dirNameScheme output_directory fileNameScheme output_file metadata_file working_directory # If level != -1 specify a compression level in ffmpeg. compression_level_param="" @@ -501,9 +532,9 @@ do # for more detail if [ "${mode}" == "chaptered" ]; then # Playlist m3u support - playlist_file="${output_directory}/${title}.m3u" + playlist_file="${output_directory}/${fileNameScheme}.m3u" if [ "${continue}" == "0" ]; then - log "Creating PlayList ${title}.m3u" + log "Creating PlayList ${fileNameScheme}.m3u" echo '#EXTM3U' > "${playlist_file}" fi @@ -539,7 +570,13 @@ do # The formatting 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}" + # Define the chapter_file + if [ "x${chapterNameScheme}" != "x" ]; then + chapter_title="$(eval echo "${chapterNameScheme}")" + else + # The Default + chapter_title="${title}-$(printf %0${#chaptercount}d $chapternum) ${chapter}" + fi chapter_file="${output_directory}/${chapter_title}.${extension}" # the ID3 tags must only be specified for *.mp3 files, @@ -551,7 +588,7 @@ do fi # Big Long chapter debug - debug_vars "Chapter Variables:" cover_file chapter_start chapter_end id3_version_param chapternum chapter_title chapter_file + debug_vars "Chapter Variables:" cover_file chapter_start chapter_end id3_version_param chapternum chapterNameScheme chapter_title chapter_file if [ "$((${continueAt} > ${chapternum}))" = "0" ]; then # Extract chapter by time stamps start and finish of chapter. # This extracts based on time stamps start and end. @@ -583,14 +620,6 @@ do echo "${chapter_title}.${extension}" >> "${playlist_file}" fi chapternum=$((chapternum + 1 )) - - # ---- - # Add the cover art to m4a and m4b file types. - if [[ ${container} == "mp4" && $(type -P mp4art) ]]; then - mp4art -q --add "${cover_file}" "${chapter_file}" - log "Added cover art to ${chapter_title}" - fi - fi done 9< "$metadata_file" @@ -600,13 +629,9 @@ do else # Perform file tasks on output file. # ---- - # Add the cover art to m4a and m4b file types. - if [[ ${container} == "mp4" && $(type -P mp4art) ]]; then - mp4art -q --add "${cover_file}" "${output_file}" - log "Added cover art to ${title}.${extension}" - fi + # ffmpeg seems to copy only chapter position, not chapter names. if [[ ${container} == "mp4" && $(type -P mp4chaps) ]]; then - ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%02d=%02d:%02d:%02.3f\nCHAPTER%02dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${title}.chapters.txt" + ffprobe -i "${aax_file}" -print_format csv -show_chapters 2>/dev/null | awk -F "," '{printf "CHAPTER%02d=%02d:%02d:%02.3f\nCHAPTER%02dNAME=%s\n", NR, $5/60/60, $5/60%60, $5%60, NR, $8}' > "${output_directory}/${fileNameScheme}.chapters.txt" mp4chaps -i "${output_file}" fi fi From 7b602eaf5db43f14ee74886bfeb324b0dda01392 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 11:21:07 +0100 Subject: [PATCH 02/10] proper multi file support i hope --- AAXtoMP3 | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 6a77c98..4591b63 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -13,8 +13,11 @@ mode=chaptered # Multi file output auth_code= # Required to be set via file or option. targetdir= # Optional output location. Note default is basedir of AAX file. dirNameScheme= # Custom directory naming scheme, default is $genre/$author/$title +customDNS=0 fileNameScheme= # Custom file naming scheme, default is $title +customFNS=0 chapterNameScheme= # Custom chapter naming scheme, default is '$title-$(printf %0${#chaptercount}d $chapternum) $chapter' (BookTitle-01 Chapter 1) +customCNS=0 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 @@ -49,11 +52,11 @@ while true; do # Change the working dir from AAX directory to what you choose. -t | --target_dir ) targetdir="$2"; shift 2 ;; # Use a custom directory naming scheme, with variables. - -D | --dir-naming-scheme ) dirNameScheme="$2"; shift 2 ;; + -D | --dir-naming-scheme ) dirNameScheme="$2"; customDNS=1 shift 2 ;; # Use a custom file naming scheme, with variables. - -F | --file-naming-scheme ) fileNameScheme="$2"; shift 2 ;; - # Use a custom chapter naming schemr, with variables. - --chapter-naming-scheme ) chapterNameScheme="$2"; shift 2 ;; + -F | --file-naming-scheme ) fileNameScheme="$2"; customFNS=1 shift 2 ;; + # Use a custom chapter naming scheme, with variables. + --chapter-naming-scheme ) chapterNameScheme="$2"; customCNS=1 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) @@ -439,32 +442,29 @@ do publisher="" fi - # dirNameScheme= - # fileNameScheme= - # chapterNameScheme= # Define the output_directory - if [ "x${dirNameScheme}" != "x" ]; then - dirNameScheme="$(eval echo "${dirNameScheme}")" + if [ "${customDNS}" == "1" ]; then + currentDirNameScheme="$(eval echo "${dirNameScheme}")" else # The Default - dirNameScheme="${genre}/${artist}/${title}" + currentDirNameScheme="${genre}/${artist}/${title}" fi # If we defined a target directory, use it. Otherwise use the location of the AAX file if [ "x${targetdir}" != "x" ] ; then - output_directory="${targetdir}/${dirNameScheme}/" + output_directory="${targetdir}/${currentDirNameScheme}/" else - output_directory="$(dirname "${aax_file}")/${dirNameScheme}/" + output_directory="$(dirname "${aax_file}")/${currentDirNameScheme}/" fi # Define the output_file - if [ "x${fileNameScheme}" != "x" ]; then - fileNameScheme="$(eval echo "${fileNameScheme}")" + if [ "${customFNS}" == "1" ]; then + currentFileNameScheme="$(eval echo "${fileNameScheme}")" else # The Default - fileNameScheme="${title}" + currentFileNameScheme="${title}" fi - output_file="${output_directory}/${fileNameScheme}.${extension}" + output_file="${output_directory}/${currentFileNameScheme}.${extension}" if [[ "${noclobber}" = "1" ]] && [[ -d "${output_directory}" ]]; then log "Noclobber enabled but directory '${output_directory}' exists. Exiting to avoid overwriting" @@ -480,7 +480,7 @@ do # Big long DEBUG output. Fully describes the settings used for transcoding. # Note this is a long debug command. It's not critical to operation. It's purely for people debugging # and coders wanting to extend the script. - debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher dirNameScheme output_directory fileNameScheme 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 # If level != -1 specify a compression level in ffmpeg. compression_level_param="" @@ -571,7 +571,7 @@ do # The formatting of the chapters names and the file names. # Chapter names are used in a few place. # Define the chapter_file - if [ "x${chapterNameScheme}" != "x" ]; then + if [ "${customCNS}" == "1" ]; then chapter_title="$(eval echo "${chapterNameScheme}")" else # The Default From 8f0f8ec3e1e5d0757a63a02c666aa4dff647ba8f Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 11:24:23 +0100 Subject: [PATCH 03/10] forgot ; --- AAXtoMP3 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 4591b63..6ce970a 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -52,11 +52,11 @@ while true; do # Change the working dir from AAX directory to what you choose. -t | --target_dir ) targetdir="$2"; shift 2 ;; # Use a custom directory naming scheme, with variables. - -D | --dir-naming-scheme ) dirNameScheme="$2"; customDNS=1 shift 2 ;; + -D | --dir-naming-scheme ) dirNameScheme="$2"; customDNS=1; shift 2 ;; # Use a custom file naming scheme, with variables. - -F | --file-naming-scheme ) fileNameScheme="$2"; customFNS=1 shift 2 ;; + -F | --file-naming-scheme ) fileNameScheme="$2"; customFNS=1; shift 2 ;; # Use a custom chapter naming scheme, with variables. - --chapter-naming-scheme ) chapterNameScheme="$2"; customCNS=1 shift 2 ;; + --chapter-naming-scheme ) chapterNameScheme="$2"; customCNS=1; 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) From ffbc592bf89dafe8bb6a6fee0e3bfa8462a543e6 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Sun, 7 Feb 2021 11:32:18 +0100 Subject: [PATCH 04/10] correct playlist name? --- AAXtoMP3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 6ce970a..5524216 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -532,9 +532,9 @@ do # for more detail if [ "${mode}" == "chaptered" ]; then # Playlist m3u support - playlist_file="${output_directory}/${fileNameScheme}.m3u" + playlist_file="${output_directory}/${currentFileNameScheme}.m3u" if [ "${continue}" == "0" ]; then - log "Creating PlayList ${fileNameScheme}.m3u" + log "Creating PlayList ${currentFileNameScheme}.m3u" echo '#EXTM3U' > "${playlist_file}" fi From 1c4d67202a5a4ed325c40bef8cf519c52034f33b Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 9 Feb 2021 20:49:12 +0100 Subject: [PATCH 05/10] fix space --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7d9fc0e..86b47a8 100644 --- a/README.md +++ b/README.md @@ -126,11 +126,13 @@ The following flags can modify the default naming scheme: * **--dir-naming-scheme** * **--file-naming-scheme** * **--chapter-naming-scheme** + Each flag takes a string as argument. If the string contains a variable defined in the script (eg. artist, title, chapter, narrator...), the corresponding value is used. The default options correspond to the following flags: * `--dir-naming-scheme '$genre/$artist/$title'` * `--file-naming-scheme '$title'` * `--chapter-naming-scheme '$title-$(printf %0${#chaptercount}d $chapternum) $chapter'` + * If a command substitution is present in the passed string, (for example `$(printf %0${#chaptercount}d $chapternum)`, used to pad with zeros the chapter number), the commands are executed. So you can use `--dir-naming-scheme '$(date +%Y)/$artist'`, but using `--file-naming-scheme '$(rm -rf /)'` is a really bad idea. Be careful. * You can use basic text, like `--dir-naming-scheme 'Converted/$title'` From 184cece622789467a503a18abb7753f0b4d9c484 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 9 Feb 2021 20:49:44 +0100 Subject: [PATCH 06/10] fix space --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 86b47a8..301e9bd 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ The default options correspond to the following flags: * `--file-naming-scheme '$title'` * `--chapter-naming-scheme '$title-$(printf %0${#chaptercount}d $chapternum) $chapter'` +Additional notes: * If a command substitution is present in the passed string, (for example `$(printf %0${#chaptercount}d $chapternum)`, used to pad with zeros the chapter number), the commands are executed. So you can use `--dir-naming-scheme '$(date +%Y)/$artist'`, but using `--file-naming-scheme '$(rm -rf /)'` is a really bad idea. Be careful. * You can use basic text, like `--dir-naming-scheme 'Converted/$title'` From 4a8df563eb12f4228d540da845e8c63fa91394c3 Mon Sep 17 00:00:00 2001 From: fabh2o Date: Tue, 9 Feb 2021 20:53:53 +0100 Subject: [PATCH 07/10] fix short flags --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 301e9bd..803de69 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [--level Date: Tue, 9 Feb 2021 20:55:38 +0100 Subject: [PATCH 08/10] use --- AAXtoMP3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index c24e5a6..7799d46 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -5,7 +5,7 @@ # Command Line Options # Usage Synopsis. -usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber]\n[--target_dir ] [--complete_dir ] [--validate]\n[--continue ]{FILES}\n' +usage=$'\nUsage: AAXtoMP3 [--flac] [--aac] [--opus ] [--single] [--level ]\n[--chaptered] [-e:mp3] [-e:m4a] [-e:m4b] [--authcode ] [--no-clobber]\n[--target_dir ] [--complete_dir ] [--validate]\n[--{dir,file,chapter}-naming-scheme ]\n[--continue ]{FILES}\n' codec=libmp3lame # Default encoder. extension=mp3 # Default encoder extension. level=-1 # Compression level. Can be given for mp3, flac and opus. -1 = default/not specified. From 012749071e6e39d66ae28044f94b0aeb9f12d1bd Mon Sep 17 00:00:00 2001 From: fabh2o Date: Wed, 10 Feb 2021 20:48:14 +0100 Subject: [PATCH 09/10] force base-10 --- AAXtoMP3 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AAXtoMP3 b/AAXtoMP3 index 4bc09bc..6bfd636 100755 --- a/AAXtoMP3 +++ b/AAXtoMP3 @@ -494,12 +494,13 @@ do debug_vars "Book and Variable values" title auth_code mode aax_file container codec bitrate artist album_artist album album_date genre copyright narrator description publisher output_file metadata_file working_directory # Display the total length of the audiobook in format hh:mm:ss + # 10#$var force base-10 interpretation. By default it's base-8, so values like 08 or 09 are not octal numbers total_length="$(ffprobe -v error -activation_bytes "${auth_code}" -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 ${aax_file} | cut -d . -f 1)" hours="$((total_length/3600))" if [ "$((hours<10))" = "1" ]; then hours="0$hours"; fi - minutes="$((total_length/60-60*hours))" + minutes="$((total_length/60-60*10#$hours))" if [ "$((minutes<10))" = "1" ]; then minutes="0$minutes"; fi - seconds="$((total_length-3600*hours-60*minutes))" + seconds="$((total_length-3600*10#$hours-60*10#$minutes))" if [ "$((seconds<10))" = "1" ]; then seconds="0$seconds"; fi log "Total length: $hours:$minutes:$seconds" From f6661862defbe3202cd687294ded3f24cec7a34d Mon Sep 17 00:00:00 2001 From: fabh2o Date: Wed, 10 Feb 2021 21:22:46 +0100 Subject: [PATCH 10/10] mediainfo install in README --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8399692..a4c836c 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ brew install gnu-sed brew install grep ``` -#### mp4art +#### mp4art/mp4chaps _Note: This is an optional dependency._ __Ubuntu, Linux Mint, Debian__ @@ -200,13 +200,30 @@ __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 ``` - + +#### mediainfo +_Note: This is an optional dependency._ + +__Ubuntu, Linux Mint, Debian__ +``` +sudo apt-get update +sudo apt-get install mediainfo +``` +__CentOS, RHEL & Fedora__ +``` +yum install mediainfo +``` +__MacOS__ +``` +brew install mediainfo +``` + + ## Anti-Piracy Notice Note that this project **does NOT ‘crack’** the DRM. It simply allows the user to use their own encryption key (fetched from Audible servers) to decrypt the