Skip to content

Instantly share code, notes, and snippets.

@eloyesp
Created June 18, 2026 02:51
Show Gist options
  • Select an option

  • Save eloyesp/1637eaa9960769ebf764a92e90851283 to your computer and use it in GitHub Desktop.

Select an option

Save eloyesp/1637eaa9960769ebf764a92e90851283 to your computer and use it in GitHub Desktop.
Automatic (safe) video compression (scaling)
#!/bin/bash
set -e
# --- Default Variables ---
AUTO_DELETE=false
DRY_RUN=false
DEBUG=false
LOG_FILE="${HOME}/video-scale.log"
# --- Argument Parsing ---
FILES=()
while [[ "$#" -gt 0 ]]; do
case $1 in
-y) AUTO_DELETE=true ;;
-n) DRY_RUN=true ;;
--debug) DEBUG=true ;;
-*) echo "Warning: Unknown parameter '$1'" ;;
*) FILES+=("$1") ;;
esac
shift
done
# Enable or disable debug mode based on flag
if [[ "$DEBUG" == true ]]; then
set -x
else
set +x
fi
# --- Main Processing Loop ---
PROCESSED_COUNT=0
for INPUT in "${FILES[@]}"; do
# 1. Skip if already compressed
if [[ "$INPUT" == *".comp."* ]]; then
echo "Warning: Skipping '$INPUT' (already contains '.comp.')."
continue
fi
# 2. Skip if source doesn't exist
if [[ ! -f "$INPUT" ]]; then
echo "Warning: Source file '$INPUT' does not exist."
continue
fi
OUTPUT="${INPUT%.*}.comp.mp4"
# 3. Skip if output already exists
if [[ -f "$OUTPUT" ]]; then
echo "Warning: Output file '$OUTPUT' already exists. Skipping."
continue
fi
CRF="${CRF:-24}"
RES="${RES:-1080}"
# 4. Dry-run mode
if [[ "$DRY_RUN" == true ]]; then
echo "[Dry Run] Would process: '$INPUT' -> '$OUTPUT' (CRF: $CRF, RES: $RES)"
[[ "$AUTO_DELETE" == true ]] && echo "[Dry Run] Would auto-delete original: '$INPUT'"
continue
fi
# 5. Delay 30 seconds between files (skipped for the first processed file)
if [[ "$PROCESSED_COUNT" -gt 0 ]]; then
sleep 30
fi
# Get initial sizes (wc -c is cross-platform friendly for bytes)
ORIG_SIZE_BYTES=$(wc -c < "$INPUT")
ORIG_SIZE_DISPLAY=$(du -hs "$INPUT" | cut -f1)
# 6. Run ffmpeg and log output
echo "--- Starting ffmpeg for $INPUT at $(date) ---" >> "$LOG_FILE"
ffmpeg -y -i "$INPUT" \
-vf "scale=w='if(gt(iw\,ih)\,$RES\,-2)':h='if(gt(iw\,ih)\,-2\,$RES)'" \
-c:v libx264 -preset fast -crf "$CRF" -c:a copy \
"$OUTPUT" >> "$LOG_FILE" 2>&1
# Get final sizes
NEW_SIZE_BYTES=$(wc -c < "$OUTPUT")
NEW_SIZE_DISPLAY=$(du -hs "$OUTPUT" | cut -f1)
# Calculate compression percentage (New Size / Old Size * 100)
if [[ -n "$ORIG_SIZE_BYTES" && "$ORIG_SIZE_BYTES" -gt 0 ]]; then
PERCENT=$(awk "BEGIN { printf \"%.0f\", ($NEW_SIZE_BYTES / $ORIG_SIZE_BYTES) * 100 }")
else
PERCENT=0
fi
# 7. Output summary line
echo "Processed $INPUT -> $OUTPUT | $ORIG_SIZE_DISPLAY -> $NEW_SIZE_DISPLAY | ${PERCENT}%"
# 8. Deletion logic
if [[ "$AUTO_DELETE" == true ]]; then
trash "$INPUT"
else
read -rp "Borro el archivo original $INPUT? [y/N] " yn
# Note: Your original regex `^([Yy]|)$` makes pressing Enter (empty) default to Yes.
[[ $yn =~ ^([Yy]|)$ ]] && trash "$INPUT"
fi
PROCESSED_COUNT=$((PROCESSED_COUNT + 1))
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment