screenrecord (4287B)
1 #!/usr/bin/env bash 2 3 OUTPUT_DIR="${XDG_VIDEOS_DIR:-$HOME/Videos/screenrecordings}" 4 5 if [[ ! -d "$OUTPUT_DIR" ]]; then 6 mkdir -p "$OUTPUT_DIR" 7 fi 8 9 SCOPE="" 10 AUDIO="false" 11 WEBCAM="false" 12 13 for arg in "$@"; do 14 case "$arg" in 15 --with-audio) AUDIO="true" ;; 16 --with-webcam) WEBCAM="true" ;; 17 output | region) SCOPE="$arg" ;; 18 esac 19 done 20 21 cleanup_webcam() { 22 pkill -f "WebcamOverlay" 2>/dev/null 23 } 24 25 start_webcam_overlay() { 26 cleanup_webcam 27 28 # Get monitor scale 29 local scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale') 30 31 # Target width (base 360px, scaled to monitor) 32 local target_width=$(awk "BEGIN {printf \"%.0f\", 360 * $scale}") 33 34 # Try preferred 16:9 resolutions in order, use first available 35 local preferred_resolutions=("640x360" "1280x720" "1920x1080") 36 local video_size_arg="" 37 local available_formats=$(v4l2-ctl --list-formats-ext -d /dev/video0 2>/dev/null) 38 39 for resolution in "${preferred_resolutions[@]}"; do 40 if echo "$available_formats" | grep -q "$resolution"; then 41 video_size_arg="-video_size $resolution" 42 break 43 fi 44 done 45 46 ffplay -f v4l2 $video_size_arg -framerate 30 /dev/video0 \ 47 -vf "scale=${target_width}:-1" \ 48 -window_title "WebcamOverlay" \ 49 -noborder \ 50 -fflags nobuffer -flags low_delay \ 51 -probesize 32 -analyzeduration 0 \ 52 -loglevel quiet & 53 sleep 1 54 } 55 56 start_screenrecording() { 57 local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4" 58 local audio_args="" 59 60 # Merge audio tracks into one - separate tracks only play one at a time in most players 61 [[ "$AUDIO" == "true" ]] && audio_args="-a default_output|default_input" 62 63 gpu-screen-recorder -w "$@" -f 60 -c mp4 -o "$filename" $audio_args & 64 toggle_screenrecording_indicator 65 } 66 67 stop_screenrecording() { 68 pkill -SIGINT -f "gpu-screen-recorder" # SIGINT required to save video properly 69 70 # Wait a maximum of 5 seconds to finish before hard killing 71 local count=0 72 while pgrep -f "gpu-screen-recorder" >/dev/null && [ $count -lt 50 ]; do 73 sleep 0.1 74 count=$((count + 1)) 75 done 76 77 if pgrep -f "gpu-screen-recorder" >/dev/null; then 78 pkill -9 -f "gpu-screen-recorder" 79 cleanup_webcam 80 notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000 81 else 82 cleanup_webcam 83 notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000 84 fi 85 toggle_screenrecording_indicator 86 } 87 88 toggle_screenrecording_indicator() { 89 pkill -RTMIN+8 waybar 90 } 91 92 screenrecording_active() { 93 pgrep -f "gpu-screen-recorder" >/dev/null || pgrep -x slurp >/dev/null || pgrep -f "WebcamOverlay" >/dev/null 94 } 95 96 if screenrecording_active; then 97 if pgrep -x slurp >/dev/null; then 98 pkill -x slurp 2>/dev/null 99 elif pgrep -f "WebcamOverlay" >/dev/null && ! pgrep -f "gpu-screen-recorder" >/dev/null; then 100 cleanup_webcam 101 else 102 stop_screenrecording 103 fi 104 elif [[ "$SCOPE" == "output" ]]; then 105 [[ "$WEBCAM" == "true" ]] && start_webcam_overlay 106 107 if ! output=$(slurp -o -f "%o"); then 108 [[ "$WEBCAM" == "true" ]] && cleanup_webcam 109 exit 1 110 fi 111 112 if [[ -z "$output" ]]; then 113 notify-send "Error" "Could not detect monitor" -u critical 114 [[ "$WEBCAM" == "true" ]] && cleanup_webcam 115 exit 1 116 fi 117 118 start_screenrecording "$output" 119 else 120 [[ "$WEBCAM" == "true" ]] && start_webcam_overlay 121 122 scale=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .scale') 123 124 if ! region=$(slurp -f "%wx%h+%x+%y"); then 125 [[ "$WEBCAM" == "true" ]] && cleanup_webcam 126 exit 1 127 fi 128 129 if [[ "$region" =~ ^([0-9]+)x([0-9]+)\+([0-9]+)\+([0-9]+)$ ]]; then 130 w=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[1]} * $scale}") 131 h=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[2]} * $scale}") 132 x=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[3]} * $scale}") 133 y=$(awk "BEGIN {printf \"%.0f\", ${BASH_REMATCH[4]} * $scale}") 134 scaled_region="${w}x${h}+${x}+${y}" 135 else 136 scaled_region="$region" 137 fi 138 139 start_screenrecording region -region "$scaled_region" 140 fi