Skip to content

Instantly share code, notes, and snippets.

@Plasmoxy
Created December 11, 2025 12:23
Show Gist options
  • Select an option

  • Save Plasmoxy/a07c1963c6ced09f682c138292799fc2 to your computer and use it in GitHub Desktop.

Select an option

Save Plasmoxy/a07c1963c6ced09f682c138292799fc2 to your computer and use it in GitHub Desktop.
#!/bin/sh
# VidMod v2 clip editor script
# ASCII intro
cat << "EOF"
╦ β•¦β”¬β”Œβ”¬β”β•”β•¦β•—β”Œβ”€β”β”Œβ”¬β”
β•šβ•—β•”β•β”‚ β”‚β”‚β•‘β•‘β•‘β”‚ β”‚ β”‚β”‚
β•šβ• β”΄β”€β”΄β”˜β•© β•©β””β”€β”˜β”€β”΄β”˜
🌸 v2 by Plasmoxy 🌸
EOF
echo ""
# Discord mode constants
MAX_DISCORD_FILE_SIZE_MB=7.7 # Safety margin (Discord limit is 8MB for free users)
DISCORD_AUDIO_BITRATE_K=128 # Assumed audio bitrate in kbps
DISCORD_MIN_VIDEO_BITRATE_K=100 # Minimum video bitrate
DISCORD_HD_THRESHOLD=1080 # Resolution threshold for auto-desize
DISCORD_TARGET_HEIGHT=720 # Target height for Discord videos (HD 720p)
# Initialize variables
start_time=""
end_time=""
do_desize=false
scale_filter=""
bitrate=""
srt_track=""
discord_mode=false
input_file=""
output_file=""
# Parse arguments
while [ $# -gt 0 ]; do
case $1 in
-s)
start_time="$2"
shift 2
;;
-e)
end_time="$2"
shift 2
;;
-d)
do_desize=true
shift
;;
-b)
bitrate="$2"
shift 2
;;
-discord)
discord_mode=true
shift
;;
-srt)
srt_track="$2"
shift 2
;;
-*)
echo "❌ Unknown option: $1"
exit 1
;;
*)
if [ -z "$input_file" ]; then
input_file="$1"
elif [ -z "$output_file" ]; then
output_file="$1"
else
echo "❌ Too many arguments"
exit 1
fi
shift
;;
esac
done
# Check if input file is provided
if [ -z "$input_file" ]; then
echo "πŸ“– Usage: vidmod [options] input_file [output_file]"
echo ""
echo "Options:"
echo " -s TIME ⏱️ Start time (e.g., 0:15)"
echo " -e TIME ⏱️ End time (e.g., 0:30)"
echo " -d πŸ“ Downscale by half (desize)"
echo " -b BITRATE πŸ’Ύ Set bitrate (e.g., 2M, 64k)"
echo " -discord πŸ’¬ Optimize for Discord (auto-scale to ~${DISCORD_TARGET_HEIGHT}p, limit to ${MAX_DISCORD_FILE_SIZE_MB}MB)"
echo " -srt TRACK πŸ“ Extract subtitle track (standalone command)"
exit 1
fi
echo "πŸ“ Input: $input_file"
# Handle SRT extraction (standalone command)
if [ -n "$srt_track" ]; then
if [ -z "$output_file" ]; then
output_file="${input_file%.*}.${srt_track}.srt"
fi
echo "πŸ“ Extracting subtitle track $srt_track"
echo "πŸ’Ύ Output: $output_file"
echo ""
ffmpeg -i "$input_file" -map "0:s:$srt_track" "$output_file" -hide_banner -loglevel error -stats
if [ $? -eq 0 ]; then
echo ""
echo "βœ… Subtitle extraction complete!"
else
echo ""
echo "❌ Subtitle extraction failed!"
fi
exit 0
fi
# Handle Discord mode
if [ "$discord_mode" = true ]; then
echo "πŸ’¬ Discord mode enabled"
# Get video resolution and duration using ffprobe
echo "πŸ” Analyzing video..."
probe_output=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration -of csv=p=0 "$input_file" 2>/dev/null)
width=$(echo "$probe_output" | cut -d',' -f1)
height=$(echo "$probe_output" | cut -d',' -f2)
duration=$(echo "$probe_output" | cut -d',' -f3)
# If duration is not in video stream, try format duration
if [ -z "$duration" ] || [ "$duration" = "N/A" ]; then
duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$input_file" 2>/dev/null)
fi
echo "πŸ“Ί Resolution: ${width}x${height}"
# Adjust duration based on time cuts
if [ -n "$start_time" ] && [ -n "$end_time" ]; then
# Convert times to seconds for calculation
start_sec=$(echo "$start_time" | awk -F: '{ if (NF==3) print ($1 * 3600) + ($2 * 60) + $3; else if (NF==2) print ($1 * 60) + $2; else print $1 }')
end_sec=$(echo "$end_time" | awk -F: '{ if (NF==3) print ($1 * 3600) + ($2 * 60) + $3; else if (NF==2) print ($1 * 60) + $2; else print $1 }')
duration=$(echo "$end_sec - $start_sec" | bc)
elif [ -n "$start_time" ]; then
start_sec=$(echo "$start_time" | awk -F: '{ if (NF==3) print ($1 * 3600) + ($2 * 60) + $3; else if (NF==2) print ($1 * 60) + $2; else print $1 }')
duration=$(echo "$duration - $start_sec" | bc)
elif [ -n "$end_time" ]; then
end_sec=$(echo "$end_time" | awk -F: '{ if (NF==3) print ($1 * 3600) + ($2 * 60) + $3; else if (NF==2) print ($1 * 60) + $2; else print $1 }')
duration=$end_sec
fi
# Determine if we need to scale based on resolution
# Check both width and height to handle both landscape and portrait videos
if [ "$width" -ge 1920 ] || [ "$height" -ge "$DISCORD_HD_THRESHOLD" ]; then
do_desize=true
# Determine orientation and calculate target dimensions
if [ "$width" -gt "$height" ]; then
# Landscape video - scale based on height
target_height=$DISCORD_TARGET_HEIGHT
# Calculate width maintaining aspect ratio: width * (target_height / height)
# Use -2 to ensure even number (required by some codecs)
scale_filter="scale=-2:${target_height}"
target_width=$(echo "scale=0; $width * $target_height / $height" | bc)
target_width=$(( (target_width + 1) / 2 * 2 )) # Round to even
else
# Portrait video - scale based on width
target_width=$DISCORD_TARGET_HEIGHT
# Calculate height maintaining aspect ratio
scale_filter="scale=${target_width}:-2"
target_height=$(echo "scale=0; $height * $target_width / $width" | bc)
target_height=$(( (target_height + 1) / 2 * 2 )) # Round to even
fi
echo "πŸ“ Auto-scale enabled: ${width}x${height} β†’ ${target_width}x${target_height}"
echo " ℹ️ Targeting ~${DISCORD_TARGET_HEIGHT}p while preserving aspect ratio"
fi
# Calculate target bitrate to stay under MAX_DISCORD_FILE_SIZE_MB
# Formula: (MAX_SIZE_MB * 8 * 1024 / duration_sec) - AUDIO_BITRATE_K
if [ -n "$duration" ] && [ "$(echo "$duration > 0" | bc)" -eq 1 ]; then
duration_rounded=$(printf "%.1f" "$duration")
echo "⏱️ Duration: ${duration_rounded}s"
target_bitrate=$(echo "scale=0; ($MAX_DISCORD_FILE_SIZE_MB * 8 * 1024 / $duration) - $DISCORD_AUDIO_BITRATE_K" | bc)
# Ensure bitrate is at least minimum
if [ "$(echo "$target_bitrate < $DISCORD_MIN_VIDEO_BITRATE_K" | bc)" -eq 1 ]; then
target_bitrate=$DISCORD_MIN_VIDEO_BITRATE_K
echo "⚠️ Using minimum video bitrate: ${DISCORD_MIN_VIDEO_BITRATE_K}k"
else
echo "πŸ“Š Calculated video bitrate: ${target_bitrate}k"
fi
bitrate="${target_bitrate}k"
else
# Fallback if we can't determine duration
bitrate="1M"
echo "⚠️ Couldn't determine duration, using fallback bitrate: ${bitrate}"
fi
fi
# Build output filename if not provided
if [ -z "$output_file" ]; then
base="${input_file%.*}"
suffix=""
if [ "$discord_mode" = true ]; then
suffix="${suffix}_discord"
fi
if [ -n "$start_time" ] || [ -n "$end_time" ]; then
suffix="${suffix}_${start_time:-0}-${end_time:-end}"
suffix=$(echo "$suffix" | tr ':' '-')
fi
if [ "$do_desize" = true ] && [ "$discord_mode" = false ]; then
suffix="${suffix}_d"
fi
if [ -n "$bitrate" ] && [ "$discord_mode" = false ]; then
suffix="${suffix}_b${bitrate}"
fi
output_file="${base}${suffix}.mp4"
else
# Add .mp4 extension if no extension provided
case "$output_file" in
*.*)
# Has extension, keep as is
;;
*)
# No extension, add .mp4
output_file="${output_file}.mp4"
;;
esac
fi
echo "πŸ’Ύ Output: $output_file"
echo ""
# Show active operations
echo "🎬 Active operations:"
if [ -n "$start_time" ]; then
echo " ⏱️ Start time: $start_time"
fi
if [ -n "$end_time" ]; then
echo " ⏱️ End time: $end_time"
fi
if [ "$do_desize" = true ]; then
if [ "$discord_mode" = true ]; then
echo " πŸ“ Scale to ~${DISCORD_TARGET_HEIGHT}p (aspect ratio preserved)"
else
echo " πŸ“ Desize (scale Γ·2)"
fi
fi
if [ -n "$bitrate" ]; then
echo " πŸ’Ύ Bitrate: $bitrate"
fi
echo ""
# Build ffmpeg command
ffmpeg_cmd="ffmpeg -i \"$input_file\""
# Add time parameters
if [ -n "$start_time" ]; then
ffmpeg_cmd="$ffmpeg_cmd -ss \"$start_time\""
fi
if [ -n "$end_time" ]; then
ffmpeg_cmd="$ffmpeg_cmd -to \"$end_time\""
fi
# Build filter chain
filter=""
if [ "$do_desize" = true ]; then
if [ -n "$scale_filter" ]; then
# Discord mode with custom scale filter
filter="$scale_filter"
else
# Regular desize mode (Γ·2)
filter="scale=iw/2:ih/2"
fi
fi
if [ -n "$filter" ]; then
ffmpeg_cmd="$ffmpeg_cmd -vf \"$filter\""
fi
# Add bitrate
if [ -n "$bitrate" ]; then
ffmpeg_cmd="$ffmpeg_cmd -b:v $bitrate"
fi
# Add async for time cuts
if [ -n "$start_time" ] || [ -n "$end_time" ]; then
ffmpeg_cmd="$ffmpeg_cmd -async 1"
fi
# Add output file with ffmpeg logging options
ffmpeg_cmd="$ffmpeg_cmd \"$output_file\" -hide_banner -loglevel error -stats"
# Execute
echo "βš™οΈ Processing..."
eval $ffmpeg_cmd
# Check if ffmpeg succeeded
if [ $? -ne 0 ]; then
echo ""
echo "❌ Processing failed!"
exit 1
fi
echo ""
echo "βœ… Processing complete!"
# Verify file size in Discord mode
if [ "$discord_mode" = true ]; then
file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null)
file_size_mb=$(echo "scale=2; $file_size / 1048576" | bc)
echo "πŸ“Š Final file size: ${file_size_mb} MB (limit: ${MAX_DISCORD_FILE_SIZE_MB} MB)"
if [ "$(echo "$file_size_mb > $MAX_DISCORD_FILE_SIZE_MB" | bc)" -eq 1 ]; then
echo "⚠️ Warning: File size exceeds ${MAX_DISCORD_FILE_SIZE_MB} MB! Consider cutting the video shorter."
else
echo "βœ… File is within Discord size limit!"
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment