Adding updates to fartmachine
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# to_mp3.sh — Convert .m4a and .wav files to .mp3
|
||||
#
|
||||
# Usage:
|
||||
# ./to_mp3.sh <file_or_folder> [options]
|
||||
#
|
||||
# Options:
|
||||
# --quality N VBR quality 0-9 (default: 2 ≈ 190kbps; lower = better)
|
||||
# --bitrate N CBR bitrate e.g. 192k (overrides --quality)
|
||||
# --replace Delete originals after successful conversion
|
||||
# --dry-run Show what would be converted without doing anything
|
||||
#
|
||||
# Examples:
|
||||
# ./to_mp3.sh recordings/
|
||||
# ./to_mp3.sh interview.m4a
|
||||
# ./to_mp3.sh recordings/ --replace
|
||||
# ./to_mp3.sh recordings/ --bitrate 128k
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
QUALITY=2
|
||||
BITRATE=""
|
||||
REPLACE=false
|
||||
DRY_RUN=false
|
||||
TARGET=""
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--quality) QUALITY="$2"; shift 2 ;;
|
||||
--bitrate) BITRATE="$2"; shift 2 ;;
|
||||
--replace) REPLACE=true; shift ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
-*) echo "Unknown option: $1" >&2; exit 1 ;;
|
||||
*) TARGET="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$TARGET" ]]; then
|
||||
echo "Usage: $(basename "$0") <file_or_folder> [--quality N] [--bitrate N] [--replace] [--dry-run]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ffmpeg &>/dev/null; then
|
||||
echo "Error: ffmpeg not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Collect files
|
||||
files=()
|
||||
if [[ -f "$TARGET" ]]; then
|
||||
files=("$TARGET")
|
||||
elif [[ -d "$TARGET" ]]; then
|
||||
while IFS= read -r -d '' f; do
|
||||
files+=("$f")
|
||||
done < <(find "$TARGET" -maxdepth 1 -type f \( -iname "*.m4a" -o -iname "*.wav" \) -print0 | sort -z)
|
||||
else
|
||||
echo "Error: '$TARGET' is not a file or directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ${#files[@]} -eq 0 ]]; then
|
||||
echo "No .m4a or .wav files found in: $TARGET"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Build audio quality flags
|
||||
if [[ -n "$BITRATE" ]]; then
|
||||
audio_flags=(-b:a "$BITRATE")
|
||||
quality_desc="CBR ${BITRATE}"
|
||||
else
|
||||
audio_flags=(-q:a "$QUALITY")
|
||||
quality_desc="VBR quality ${QUALITY}"
|
||||
fi
|
||||
|
||||
echo "Converting ${#files[@]} file(s) to MP3 (${quality_desc})"
|
||||
[[ "$REPLACE" == true ]] && echo " Originals will be deleted after conversion."
|
||||
[[ "$DRY_RUN" == true ]] && echo " Dry-run mode — no files will be written."
|
||||
echo ""
|
||||
|
||||
converted=0
|
||||
skipped=0
|
||||
errors=0
|
||||
|
||||
for src in "${files[@]}"; do
|
||||
out="${src%.*}.mp3"
|
||||
|
||||
if [[ -f "$out" && "$DRY_RUN" == false ]]; then
|
||||
echo " $(basename "$src"): output already exists, skipping"
|
||||
((skipped++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
size_mb=$(( $(stat -f%z "$src" 2>/dev/null || stat -c%s "$src") / 1048576 ))
|
||||
printf " %-40s (%d MB)" "$(basename "$src")" "$size_mb"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo " [dry-run] → $(basename "$out")"
|
||||
continue
|
||||
fi
|
||||
|
||||
if ffmpeg -i "$src" -vn "${audio_flags[@]}" -y "$out" -loglevel error; then
|
||||
out_kb=$(( $(stat -f%z "$out" 2>/dev/null || stat -c%s "$out") / 1024 ))
|
||||
echo " → $(basename "$out") (${out_kb} KB)"
|
||||
((converted++)) || true
|
||||
if [[ "$REPLACE" == true ]]; then
|
||||
rm "$src"
|
||||
fi
|
||||
else
|
||||
echo " ERROR"
|
||||
((errors++)) || true
|
||||
[[ -f "$out" ]] && rm "$out"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Done: ${converted} converted, ${skipped} skipped, ${errors} errors."
|
||||
Reference in New Issue
Block a user