VideoTools/video-tools.sh

170 lines
5.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Simple FFmpeg CLI Toolset
# -------------------------
# Provides easy commands for single or multi-file video conversion.
# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed.
#
set -euo pipefail
# ==========================================================
# Configuration system
# ==========================================================
CONFIG_FILE="$(dirname "$0")/config/config.json"
# -------------------------
# Default configuration
# -------------------------
OUTPUT_DIR="$HOME/Videos"
VIDEO_CODEC="libx264"
AUDIO_CODEC="aac"
CRF="18" # lower = higher quality
PRESET="slow" # slower = better compression
AUDIO_BITRATE="192k"
VERSION="0.1.0"
# ==========================================================
# Utility: Colour logging
# ==========================================================
RED="\033[31m"
YELLOW="\033[33m"
GREEN="\033[32m"
BLUE="\033[34m"
NC="\033[0m" # reset
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
# ==========================================================
# Check dependencies early
# ==========================================================
if ! command -v ffmpeg >/dev/null 2>&1; then
error "ffmpeg is not installed or not in PATH."
exit 1
fi
if [[ -f "$CONFIG_FILE" ]] && command -v jq >/dev/null 2>&1; then
info "Loading configuration from: $CONFIG_FILE"
OUTPUT_DIR="$(eval echo "$(jq -r '.output_dir // empty' "$CONFIG_FILE")")" || true
VIDEO_CODEC="$(jq -r '.video_codec // empty' "$CONFIG_FILE" 2>/dev/null || echo "$VIDEO_CODEC")"
AUDIO_CODEC="$(jq -r '.audio_codec // empty' "$CONFIG_FILE" 2>/dev/null || echo "$AUDIO_CODEC")"
CRF="$(jq -r '.crf // empty' "$CONFIG_FILE" 2>/dev/null || echo "$CRF")"
PRESET="$(jq -r '.preset // empty' "$CONFIG_FILE" 2>/dev/null || echo "$PRESET")"
AUDIO_BITRATE="$(jq -r '.audio_bitrate // empty' "$CONFIG_FILE" 2>/dev/null || echo "$AUDIO_BITRATE")"
VERSION="$(jq -r '.version // empty' "$CONFIG_FILE" 2>/dev/null || echo "$VERSION")"
elif [[ ! -f "$CONFIG_FILE" ]]; then
warn "No config.json found — using internal defaults."
else
warn "jq not found — skipping config.json parsing."
fi
mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; }
# ==========================================================
# Header output
# ==========================================================
print_header() {
echo "----------------------------------------------"
echo "Video Tools v$VERSION"
echo "Output directory: $OUTPUT_DIR"
echo "Video codec : $VIDEO_CODEC"
echo "Audio codec : $AUDIO_CODEC"
echo "CRF : $CRF"
echo "Preset : $PRESET"
echo "Audio rate : $AUDIO_BITRATE"
echo "----------------------------------------------"
}
# ==========================================================
# Convert one file
# ==========================================================
convert_single() {
local input="$1"
local output_name="$2"
local output_path="$OUTPUT_DIR/$output_name"
print_header
info "Converting single video..."
info "Input : $input"
info "Output: $output_path"
if [[ ! -f "$input" ]]; then
error "Input file not found: $input"
exit 1
fi
ffmpeg -hide_banner -loglevel info -fflags +genpts \
-i "$input" \
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
"$output_path" || { error "Conversion failed."; exit 1; }
success "Conversion complete: $output_path"
}
# ==========================================================
# Combine multiple files
# ==========================================================
convert_multiple() {
local args=("$@")
local output_name="${args[-1]}"
unset 'args[-1]'
local list_file
list_file=$(mktemp)
local output_path="$OUTPUT_DIR/$output_name"
print_header
info "Combining multiple videos..."
for input in "${args[@]}"; do
if [[ ! -f "$input" ]]; then
error "Missing input file: $input"
rm -f "$list_file"
exit 1
fi
echo "file '$input'" >> "$list_file"
info " + Added: $input"
done
echo "----------------------------------------------"
ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
"$output_path" || { error "Merge failed."; rm -f "$list_file"; exit 1; }
rm -f "$list_file"
success "Combined video created: $output_path"
}
# ==========================================================
# Dispatcher
# ==========================================================
case "${1:-}" in
convert-single)
shift
if [[ $# -ne 2 ]]; then
error "Usage: $0 convert-single <input> <output.mp4>"
exit 1
fi
convert_single "$@"
;;
convert-multiple)
shift
if [[ $# -lt 3 ]]; then
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4>"
exit 1
fi
convert_multiple "$@"
;;
*)
echo "Video Tools v$VERSION"
echo "Usage:"
echo " $0 convert-single <input> <output.mp4>"
echo " $0 convert-multiple <input1> <input2> ... <output.mp4>"
echo ""
echo "All outputs will be saved in: $OUTPUT_DIR"
;;
esac