Files
marketing/remove-text.sh
2025-10-25 18:17:56 +01:00

125 lines
3.6 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
# remove_text.sh — conceal on-screen text in a rectangular area for a chosen time window.
# Requires: ffmpeg (with delogo filter)
show_help() {
cat <<'EOF'
Usage:
remove_text.sh -i INPUT -o OUTPUT --x X --y Y --w W --h H [--start SEC] [--end SEC] [--feather PX] [--preview] [--dry-run]
Params:
-i, --input Input video file
-o, --output Output video file
--x Left coordinate of the box (pixels)
--y Top coordinate of the box (pixels)
--w Box width (pixels)
--h Box height (pixels)
--start Start time in seconds (e.g. 12 or 12.5). If omitted, applies from t=0.
--end End time in seconds (exclusive). If omitted, applies to end of video.
--feather Feather thickness for delogo (default: 8). Higher = softer edge.
--preview Instead of removing, draw a red box to help align the area.
--dry-run Print the ffmpeg command but don't execute it.
-h, --help Show this help
Examples:
Preview the area (draws box only):
remove_text.sh -i in.mp4 -o preview.mp4 --x 120 --y 940 --w 680 --h 60 --start 12.5 --end 28.3 --preview
Remove text in that area/time range:
remove_text.sh -i in.mp4 -o out.mp4 --x 120 --y 940 --w 680 --h 60 --start 12.5 --end 28.3
EOF
}
# ---- defaults ----
INPUT=""
OUTPUT=""
X=""
Y=""
W=""
H=""
START=""
END=""
FEATHER="8"
PREVIEW="0"
DRYRUN="0"
# ---- parse args ----
if [[ $# -eq 0 ]]; then show_help; exit 1; fi
while [[ $# -gt 0 ]]; do
case "$1" in
-i|--input) INPUT="${2:-}"; shift 2;;
-o|--output) OUTPUT="${2:-}"; shift 2;;
--x) X="${2:-}"; shift 2;;
--y) Y="${2:-}"; shift 2;;
--w) W="${2:-}"; shift 2;;
--h) H="${2:-}"; shift 2;;
--start) START="${2:-}"; shift 2;;
--end) END="${2:-}"; shift 2;;
--feather) FEATHER="${2:-}"; shift 2;;
--preview) PREVIEW="1"; shift;;
--dry-run) DRYRUN="1"; shift;;
-h|--help) show_help; exit 0;;
*) echo "Unknown argument: $1"; echo; show_help; exit 1;;
esac
done
# ---- validation ----
if [[ -z "$INPUT" || -z "$OUTPUT" || -z "$X" || -z "$Y" || -z "$W" || -z "$H" ]]; then
echo "Error: Missing required arguments."; echo
show_help; exit 1
fi
if ! command -v ffmpeg >/dev/null 2>&1; then
echo "Error: ffmpeg not found in PATH."; exit 1
fi
# Build enable expression based on start/end
ENABLE_EXPR=""
if [[ -n "$START" && -n "$END" ]]; then
ENABLE_EXPR="between(t\,${START}\,${END})"
elif [[ -n "$START" ]]; then
ENABLE_EXPR="gte(t\,${START})"
elif [[ -n "$END" ]]; then
ENABLE_EXPR="lte(t\,${END})"
else
ENABLE_EXPR="" # apply for whole video
fi
# Build filter chain
if [[ "$PREVIEW" == "1" ]]; then
if [[ -n "$ENABLE_EXPR" ]]; then
VFILTER="drawbox=x=${X}:y=${Y}:w=${W}:h=${H}:color=red@0.5:thickness=2:enable='${ENABLE_EXPR}'"
else
VFILTER="drawbox=x=${X}:y=${Y}:w=${W}:h=${H}:color=red@0.5:thickness=2"
fi
else
# delogo: x, y, w, h, t = feather thickness; show=0 (no outline)
# delogo: x, y, w, h, band = feather thickness; show=0 (no outline)
if [[ -n "$ENABLE_EXPR" ]]; then
VFILTER="delogo=x=${X}:y=${Y}:w=${W}:h=${H}:show=0:enable='${ENABLE_EXPR}'"
else
VFILTER="delogo=x=${X}:y=${Y}:w=${W}:h=${H}:show=0"
fi
fi
# Assemble ffmpeg command
# -c:v libx264 -crf 18: quality/size balance; adjust as needed
# -preset medium: speed/efficiency tradeoff
# -c:a copy: keep original audio
CMD=(ffmpeg -hide_banner -y -i "$INPUT" -vf "$VFILTER" -c:v libx264 -crf 18 -preset medium -c:a copy "$OUTPUT")
echo "Running:"
printf ' %q' "${CMD[@]}"; echo
if [[ "$DRYRUN" == "1" ]]; then
exit 0
fi
"${CMD[@]}"
echo "Done: $OUTPUT"