Created
February 4, 2026 17:46
-
-
Save itsanishjain/4da9cd14dbad4c0bb1146109e8a9be8a to your computer and use it in GitHub Desktop.
Instagram Reels Video Cropper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ============================================================================== | |
| # Instagram Reels Video Cropper | |
| # ============================================================================== | |
| # Converts any video to 9:16 aspect ratio (1080x1920) for Instagram Reels | |
| # | |
| # Usage: ./crop-for-reels.sh <input_video> [output_video] | |
| # | |
| # Requirements: ffmpeg (brew install ffmpeg) | |
| # ============================================================================== | |
| set -e | |
| # Colors for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[0;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| # Instagram Reels dimensions (9:16 aspect ratio) | |
| TARGET_WIDTH=1080 | |
| TARGET_HEIGHT=1920 | |
| # Check if ffmpeg is installed | |
| if ! command -v ffmpeg &> /dev/null; then | |
| echo -e "${RED}Error: ffmpeg is not installed.${NC}" | |
| echo "Install it with: brew install ffmpeg" | |
| exit 1 | |
| fi | |
| # Check if input file is provided | |
| if [ -z "$1" ]; then | |
| echo -e "${RED}Error: No input video provided.${NC}" | |
| echo "" | |
| echo "Usage: $0 <input_video> [output_video]" | |
| echo "" | |
| echo "Examples:" | |
| echo " $0 my_video.mp4" | |
| echo " $0 my_video.mp4 my_reel.mp4" | |
| exit 1 | |
| fi | |
| INPUT_FILE="$1" | |
| # Check if input file exists | |
| if [ ! -f "$INPUT_FILE" ]; then | |
| echo -e "${RED}Error: Input file '$INPUT_FILE' not found.${NC}" | |
| exit 1 | |
| fi | |
| # Generate output filename if not provided | |
| if [ -z "$2" ]; then | |
| FILENAME=$(basename -- "$INPUT_FILE") | |
| EXTENSION="${FILENAME##*.}" | |
| BASENAME="${FILENAME%.*}" | |
| OUTPUT_FILE="${BASENAME}_reel.${EXTENSION}" | |
| else | |
| OUTPUT_FILE="$2" | |
| fi | |
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | |
| echo -e "${BLUE} 📱 Instagram Reels Video Cropper${NC}" | |
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | |
| echo "" | |
| # Get input video dimensions | |
| echo -e "${YELLOW}Analyzing input video...${NC}" | |
| INPUT_WIDTH=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=s=x:p=0 "$INPUT_FILE") | |
| INPUT_HEIGHT=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 "$INPUT_FILE") | |
| DURATION=$(ffprobe -v error -show_entries format=duration -of csv=s=x:p=0 "$INPUT_FILE" 2>/dev/null | cut -d. -f1) | |
| echo -e " Input: ${GREEN}${INPUT_WIDTH}x${INPUT_HEIGHT}${NC}" | |
| echo -e " Output: ${GREEN}${TARGET_WIDTH}x${TARGET_HEIGHT}${NC} (9:16)" | |
| echo -e " Duration: ${GREEN}${DURATION:-unknown}s${NC}" | |
| echo "" | |
| # Determine the video orientation and build the appropriate filter | |
| INPUT_ASPECT=$(echo "scale=6; $INPUT_WIDTH / $INPUT_HEIGHT" | bc) | |
| TARGET_ASPECT=$(echo "scale=6; $TARGET_WIDTH / $TARGET_HEIGHT" | bc) # 0.5625 | |
| # Check if input is landscape (wider than 9:16) | |
| IS_LANDSCAPE=$(echo "$INPUT_ASPECT > $TARGET_ASPECT" | bc) | |
| if [ "$IS_LANDSCAPE" -eq 1 ]; then | |
| echo -e "${YELLOW}Detected: Landscape video → Converting to portrait${NC}" | |
| echo -e "${YELLOW}Mode: Blurred background with centered video${NC}" | |
| echo "" | |
| # For landscape videos: Create blurred background + overlay original centered | |
| # This preserves the entire video content with a nice blurred background | |
| FILTER_COMPLEX=" | |
| [0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20:5[bg]; | |
| [0:v]scale=1080:-2:force_original_aspect_ratio=decrease[fg]; | |
| [bg][fg]overlay=(W-w)/2:(H-h)/2,setsar=1 | |
| " | |
| else | |
| echo -e "${YELLOW}Detected: Portrait/Square video → Cropping to 9:16${NC}" | |
| echo "" | |
| # For portrait or square videos: Scale and crop to exactly 9:16 | |
| FILTER_COMPLEX=" | |
| [0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,setsar=1 | |
| " | |
| fi | |
| echo -e "${YELLOW}Processing video...${NC}" | |
| # Run ffmpeg with progress indicator | |
| ffmpeg -i "$INPUT_FILE" \ | |
| -filter_complex "$FILTER_COMPLEX" \ | |
| -c:v libx264 \ | |
| -preset medium \ | |
| -crf 23 \ | |
| -c:a aac \ | |
| -b:a 128k \ | |
| -movflags +faststart \ | |
| -y \ | |
| "$OUTPUT_FILE" \ | |
| 2>&1 | while read line; do | |
| if [[ "$line" == *"frame="* ]]; then | |
| echo -ne "\r $line" | |
| fi | |
| done | |
| echo "" | |
| echo "" | |
| # Verify output file was created and has content | |
| if [ ! -f "$OUTPUT_FILE" ] || [ ! -s "$OUTPUT_FILE" ]; then | |
| echo -e "${RED}Error: Failed to create output file.${NC}" | |
| exit 1 | |
| fi | |
| echo -e "${GREEN}✓ Successfully created Instagram Reel!${NC}" | |
| echo "" | |
| # Get output file size | |
| OUTPUT_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1) | |
| echo -e " Output file: ${BLUE}$OUTPUT_FILE${NC}" | |
| echo -e " File size: ${GREEN}$OUTPUT_SIZE${NC}" | |
| echo "" | |
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | |
| echo -e " 📤 Ready to upload to Instagram Reels!" | |
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment