#!/bin/bash # ============================================================================= # Batch Audio Compressor - 96 kbps AAC # Preserves folder structure, uses ffmpeg + GNU parallel + hardware acceleration # ============================================================================= set -euo pipefail # ------------------------------- # Configuration # ------------------------------- SOURCE_DIR="${1:-./audio_source}" OUTPUT_DIR="${2:-./audio_96kbps}" LOG_FILE="./compression.log" #NUM_JOBS="1" NUM_JOBS="${PARALLEL_JOBS:-$(nproc)}" # Use all cores by default # Supported input audio extensions (lowercase) declare -a AUDIO_EXTS=("wav" "flac" "aiff" "aif" "mp3" "m4a" "ogg" "wma" "ac3" "alac") # ------------------------------- # Functions # ------------------------------- log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" } detect_hw_accel() { echo "vdpau" return # Cuda? if ffmpeg -hwaccels 2>/dev/null | grep -q cuda; then echo "cuda" # Try to detect available hardware acceleration elif ffmpeg -hwaccels 2>/dev/null | grep -q vaapi; then echo "vaapi" elif ffmpeg -buildconf 2>&1 | grep -q "enable-vdpau"; then echo "vdpau" elif [[ "$(uname)" == "Darwin" ]] && ffmpeg -codecs 2>/dev/null | grep -q 'h264.* videotoolbox'; then echo "videotoolbox" else echo "none" fi } get_hw_args() { local hw_accel="$1" local input_file="$2" case "$hw_accel" in "vaapi") echo "-vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload' -c:a aac -b:a 64k" ;; "videotoolbox") # Apple's VideoToolbox (macOS) — fast for H.264, less useful for audio, but can accelerate some codecs # Note: Audio encoding isn't accelerated, but we include for completeness if video is present echo "-c:a aac -b:a 64k -c:v h264_videotoolbox" ;; *) echo "-c:a libmp3lame -b:a 64k" # Fallback to software encoding ;; esac } # ------------------------------- # Input validation # ------------------------------- if [[ ! -d "$SOURCE_DIR" ]]; then echo "Error: Source directory does not exist: $SOURCE_DIR" echo "Usage: $0 " exit 1 fi mkdir -p "$OUTPUT_DIR" log "Starting compression of '$SOURCE_DIR' -> '$OUTPUT_DIR' at 96 kbps AAC" log "Using $NUM_JOBS parallel jobs" # ------------------------------- # Detect hardware acceleration # ------------------------------- HW_ACCEL="$(detect_hw_accel)" log "Hardware acceleration detected: $HW_ACCEL" # ------------------------------- # Find all audio files and process them via parallel # ------------------------------- # Export functions and variables for GNU parallel export -f get_hw_args export SOURCE_DIR export OUTPUT_DIR export HW_ACCEL # Build find command for all audio extensions find_cmd="find \"$SOURCE_DIR\" -type f \\( " for ext in "${AUDIO_EXTS[@]}"; do find_cmd+=" -iname \"*.${ext}\" -o" done # Replace trailing "-o" with "\\)" find_cmd="${find_cmd% -o} \\)" # Use eval to execute the dynamic find command and pipe to parallel eval "$find_cmd" | sort | parallel -j"$NUM_JOBS" --progress --bar --joblog parallel_jobs.log --eta ' input_file="{}" rel_path="${SOURCE_DIR:+${input_file#"$SOURCE_DIR"/}}" output_file="'$OUTPUT_DIR'/${rel_path%.*}.mp3" # Create output directory if needed mkdir -p "$(dirname "$output_file")" if [[ -f "$output_file" ]]; then echo "Skipped (exists): $rel_path" exit 0 fi hw_args=$(get_hw_args "'$HW_ACCEL'" "$input_file") ffmpeg -v warning -stats \ -i "$input_file" \ $hw_args \ -y "$output_file" \ && echo "Converted: $rel_path" ' log "Compression complete. Output saved to: $OUTPUT_DIR"