xiandie/compress_audio.sh

68 lines
2.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# ==============================================================================
# WORKER SCRIPT: compress_audio.sh (v6.1 - libvorbis only, bug-fix)
# ==============================================================================
set -Eeuo pipefail
trap 'echo "❌ 发生错误 (line $LINENO)" >&2' ERR
# ---------- 可调环境变量 ----------
SOURCE_DIR="${SOURCE_DIR:-./asset/audio}"
OUTPUT_DIR="${OUTPUT_DIR:-./compressed_audio}"
BYTE_RATE_THRESHOLD="${BYTE_RATE_THRESHOLD:-60000}" # < 60 kB/s 视为已压缩
OVERWRITE="${OVERWRITE:-0}" # 0=跳过已存在
AUDIO_RATE="${AUDIO_RATE:-44100}" # Vorbis 常用 44.1 kHz
DRY_RUN="${DRY_RUN:-0}"
LOG_LEVEL="${LOG_LEVEL:-info}" # info / debug
# ---------- 固定编解码参数 ----------
OUTPUT_EXT="ogg"
ENC_OPTS="-c:a libvorbis -q:a 5" # 010, 5≈~160 kbps
# ---------- 参数检查 ----------
[[ $# -eq 0 || -z ${1:-} ]] && { echo "用法: $0 <audio-file>" >&2; exit 2; }
audio_file=$1
[[ ! -f $audio_file ]] && { echo "文件不存在: $audio_file" >&2; exit 2; }
# ---------- 辅助 ----------
log(){ [[ $LOG_LEVEL == debug || $1 != debug ]] && echo "[$1] $2" >&2; }
get_size(){ [[ $(uname) == Darwin ]] && stat -f%z "$1" || stat -c%s "$1"; }
# ---------- 输出路径 ----------
relative="${audio_file#$SOURCE_DIR/}"
base="${relative%.*}"
output="$OUTPUT_DIR/${base}.${OUTPUT_EXT}"
# ---------- 跳过已存在 ----------
if [[ $OVERWRITE -eq 0 && -f $output ]]; then
log info "SKIP(已存在): $output"; exit 2; fi
# ---------- 获取时长 ----------
duration=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 "$audio_file" | head -n1)
if [[ -z $duration || $(awk "BEGIN{print ($duration<=0)}") -eq 1 ]]; then
log info "SKIP(无效): $audio_file"; exit 2; fi
# ---------- 获取比特率 ----------
bitrate=$(ffprobe -v error -select_streams a:0 -show_entries stream=bit_rate \
-of default=noprint_wrappers=1:nokey=1 "$audio_file" | head -n1)
# 某些文件无 bit_rate回退到 size/duration
if [[ -z $bitrate || $bitrate == N/A || $bitrate == 0 ]]; then
size=$(get_size "$audio_file")
bitrate=$(awk "BEGIN{printf \"%.0f\", $size/$duration}")
fi
if (( bitrate < BYTE_RATE_THRESHOLD )); then
log info "SKIP(已压缩, ${bitrate}B/s): $audio_file"; exit 2; fi
[[ $DRY_RUN -eq 1 ]] && { log info "DRY-RUN: $audio_file$output"; exit 0; }
mkdir -p "$(dirname "$output")"
log info "COMPRESS → $output"
ffmpeg -hide_banner -loglevel error -y \
-i "$audio_file" -vn -sn $ENC_OPTS -ar "$AUDIO_RATE" -map_metadata -1 \
"$output" \
&& { log info "SUCCESS"; exit 0; } \
|| { log info "FAILED"; exit 1; }