mirror of
				https://github.com/KrumpetPirate/AAXtoMP3.git
				synced 2025-10-30 19:10:42 +01:00 
			
		
		
		
	
							
								
								
									
										97
									
								
								AAXtoMP3
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								AAXtoMP3
									
									
									
									
									
								
							| @@ -1,10 +1,39 @@ | |||||||
| #!/usr/bin/env bash | #!/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 <AUTHCODE>]\n[--output_dir <PATH>] {FILES}\n' | ||||||
| codec=libmp3lame | codec=libmp3lame | ||||||
| extension=mp3 | extension=mp3 | ||||||
| mode=chaptered | mode=chaptered | ||||||
|  | auth_code= | ||||||
|  | targetdir= | ||||||
|  |  | ||||||
|  | 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 ;;              # 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") | GREP=$(grep --version | grep -q GNU && echo "grep" || echo "ggrep") | ||||||
|  |  | ||||||
| if ! [[ $(type -P "$GREP") ]]; then | if ! [[ $(type -P "$GREP") ]]; then | ||||||
| @@ -14,30 +43,29 @@ if ! [[ $(type -P "$GREP") ]]; then | |||||||
|     exit 1 |     exit 1 | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [ "$#" -eq 0 ]; then | # Obtain the authcode from either the command line,  local directory or home directory. | ||||||
|         echo "Usage: bash AAXtoMP3.sh [--flac] [--single] AUTHCODE {FILES}" | 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   |   exit 1   | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ "$1" = '--flac' ]] | # Check the target dir for if set if it is writable | ||||||
| then | if [[ ! -w "${targetdir}" || ! -d "${targetdir}" ]] ; then | ||||||
|     codec=flac |   echo "ERROR Target Directory is not writable: \"$targetdir\"" | ||||||
|     extension=flac |   echo "$usage" | ||||||
|     shift |   exit 1  | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ "$1" == '--single' ]] | # ======================================================================== | ||||||
| then | # Utility Functions | ||||||
|     mode=single |  | ||||||
|     shift |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| if [ ! -f .authcode ]; then |  | ||||||
|     auth_code=$1 |  | ||||||
|     shift |  | ||||||
| else |  | ||||||
|     auth_code=`head -1 .authcode` |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| debug() { | debug() { | ||||||
|     echo "$(date "+%F %T%z") ${1}" |     echo "$(date "+%F %T%z") ${1}" | ||||||
| @@ -67,28 +95,44 @@ normalize_whitespace() { | |||||||
|     echo $* |     echo $* | ||||||
| } | } | ||||||
|  |  | ||||||
|  | # ======================================================================== | ||||||
|  | # Main Transcode Loop | ||||||
| for path | for path | ||||||
| do | do | ||||||
|     debug "Decoding ${path} with auth code ${auth_code}..." |     debug "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 | ||||||
|  |  | ||||||
|     save_metadata "${path}" |     save_metadata "${path}" | ||||||
|     genre=$(get_metadata_value genre) |     genre=$(get_metadata_value genre) | ||||||
|     artist=$(get_metadata_value artist) |     artist=$(get_metadata_value artist) | ||||||
|     title=$(get_metadata_value 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}" |       output_directory="$(dirname "${path}")/${genre}/${artist}/${title}" | ||||||
|  |     fi | ||||||
|     mkdir -p "${output_directory}" |     mkdir -p "${output_directory}" | ||||||
|     full_file_path="${output_directory}/${title}.${extension}" |     full_file_path="${output_directory}/${title}.${extension}" | ||||||
|  |  | ||||||
|  |     # This is the primary transcode. All the heavy lifting is here. | ||||||
|     </dev/null ffmpeg -loglevel error -stats -activation_bytes "${auth_code}" -i "${path}" -vn -codec:a "${codec}" -ab "$(get_bitrate)k" -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="$(get_metadata_value album_artist)" -metadata album="$(get_metadata_value album)" -metadata date="$(get_metadata_value date)" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="$(get_metadata_value copyright)" "${full_file_path}" |     </dev/null ffmpeg -loglevel error -stats -activation_bytes "${auth_code}" -i "${path}" -vn -codec:a "${codec}" -ab "$(get_bitrate)k" -map_metadata -1 -metadata title="${title}" -metadata artist="${artist}" -metadata album_artist="$(get_metadata_value album_artist)" -metadata album="$(get_metadata_value album)" -metadata date="$(get_metadata_value date)" -metadata track="1/1" -metadata genre="${genre}" -metadata copyright="$(get_metadata_value copyright)" "${full_file_path}" | ||||||
|  |  | ||||||
|     debug "Created ${full_file_path}." |     debug "Created ${full_file_path}." | ||||||
|  |  | ||||||
|  |     # Grab the cover art if available. | ||||||
|     cover_path="${output_directory}/cover.jpg" |     cover_path="${output_directory}/cover.jpg" | ||||||
|  |  | ||||||
|     debug "Extracting cover into ${cover_path}..." |     debug "Extracting cover into ${cover_path}..." | ||||||
|     </dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${path}" -an -codec:v copy "${cover_path}"     |     </dev/null ffmpeg -loglevel error -activation_bytes "${auth_code}" -i "${path}" -an -codec:v copy "${cover_path}"     | ||||||
|  |  | ||||||
|  |     # If we want multiple file we take the big mp3 and split it by chapter. | ||||||
|     if [ "${mode}" == "chaptered" ]; then |     if [ "${mode}" == "chaptered" ]; then | ||||||
|  |         # Playlist m3u support | ||||||
|         playlist_file="${output_directory}/${title}.m3u" |         playlist_file="${output_directory}/${title}.m3u" | ||||||
|         debug "Creating PlayList ${title}.m3u" |         debug "Creating PlayList ${title}.m3u" | ||||||
|         echo '#EXTM3U' > "${playlist_file}" |         echo '#EXTM3U' > "${playlist_file}" | ||||||
| @@ -105,7 +149,16 @@ do | |||||||
|                 read -r -u9 _ _ chapter |                 read -r -u9 _ _ chapter | ||||||
|                 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}" |                 chapter_file="${output_directory}/${chapter_title}.${extension}" | ||||||
|                 </dev/null ffmpeg -loglevel error -stats -i "${full_file_path}" -i "${cover_path}" -ss "${start%?}" -to "${end}" -c copy -map 0:0 -map 1:0 -id3v2_version 3 \ |                  | ||||||
|  |                 # 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 | ||||||
|  |  | ||||||
|  |                 </dev/null ffmpeg -loglevel error -stats -i "${full_file_path}" -i "${cover_path}" -ss "${start%?}" -to "${end}" -map 0:0 -map 1:0 -acodec copy ${id3_version_param} \ | ||||||
|                     -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (Front)" -metadata track="${chapternum}" -metadata title="${chapter_title}" \ |                     -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (Front)" -metadata track="${chapternum}" -metadata title="${chapter_title}" \ | ||||||
|                     "${chapter_file}" |                     "${chapter_file}" | ||||||
|                  |                  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
| The purpose of this software is to convert AAX files to common MP3, M4A and M4B formats | 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. | 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 | books and if you download your book through your library it will be | ||||||
| stored in this format. | stored in this format. | ||||||
|  |  | ||||||
| @@ -31,7 +31,7 @@ Thanks to kbabioch, this script has also been packaged in the [AUR](https://aur. | |||||||
|  |  | ||||||
| ## Usage(s) | ## Usage(s) | ||||||
| ``` | ``` | ||||||
| bash AAXtoMP3 [--flac] [--single] [AUTHCODE] <AAX INPUT_FILES>... | bash AAXtoMP3 [-f|--flac] [-o|--opus] [-a|-aac] [-s|--single] [-A|--authcode <AUTHCODE>] [-o|--output_dir <PATH>] <AAX INPUT_FILES>... | ||||||
| bash AAXtoM4A [AUTHCODE] <AAX INPUT_FILES>... | bash AAXtoM4A [AUTHCODE] <AAX INPUT_FILES>... | ||||||
| bash AAXtoM4B [AUTHCODE] <AAX INPUT_FILES>... | bash AAXtoM4B [AUTHCODE] <AAX INPUT_FILES>... | ||||||
| ``` | ``` | ||||||
| @@ -41,20 +41,33 @@ bash AAXtoM4B [AUTHCODE] <AAX INPUT_FILES>... | |||||||
|  |  | ||||||
|  |  | ||||||
| ### MP3 Encoding | ### 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 | * 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 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 | ### M4B Encoding | ||||||
|  |  | ||||||
| ### Defaults | ### Defaults | ||||||
| * Specifying the AUTHCODE. | * Specifying the AUTHCODE. | ||||||
|     In order of __precidence__. |     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. |     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). | 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 | ## Anti-Piracy Notice | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user