128 lines
3.6 KiB
Bash
128 lines
3.6 KiB
Bash
#!/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 <source_dir> <output_dir>"
|
|
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"
|