Cap recordings to 4K and do start/stop correctly and no indicator until recording

This commit is contained in:
David Heinemeier Hansson
2026-02-28 17:46:57 +01:00
parent 7934b0d51b
commit aabaef83ea
+57 -30
View File
@@ -2,6 +2,8 @@
# Start and stop a screenrecording, which will be saved to ~/Videos by default. # Start and stop a screenrecording, which will be saved to ~/Videos by default.
# Alternative location can be set via OMARCHY_SCREENRECORD_DIR or XDG_VIDEOS_DIR ENVs. # Alternative location can be set via OMARCHY_SCREENRECORD_DIR or XDG_VIDEOS_DIR ENVs.
# Resolution is capped to 4K for monitors above 4K, native otherwise.
# Override via --resolution= (e.g. --resolution=1920x1080, --resolution=0x0 for native).
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs [[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}" OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
@@ -15,7 +17,9 @@ DESKTOP_AUDIO="false"
MICROPHONE_AUDIO="false" MICROPHONE_AUDIO="false"
WEBCAM="false" WEBCAM="false"
WEBCAM_DEVICE="" WEBCAM_DEVICE=""
RESOLUTION=""
STOP_RECORDING="false" STOP_RECORDING="false"
RECORDING_FILE="/tmp/omarchy-screenrecord-filename"
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
@@ -23,10 +27,25 @@ for arg in "$@"; do
--with-microphone-audio) MICROPHONE_AUDIO="true" ;; --with-microphone-audio) MICROPHONE_AUDIO="true" ;;
--with-webcam) WEBCAM="true" ;; --with-webcam) WEBCAM="true" ;;
--webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;; --webcam-device=*) WEBCAM_DEVICE="${arg#*=}" ;;
--stop-recording) STOP_RECORDING="true" --resolution=*) RESOLUTION="${arg#*=}" ;;
--stop-recording) STOP_RECORDING="true" ;;
esac esac
done done
default_resolution() {
local width height
read -r width height < <(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | "\(.width) \(.height)"')
if ((width > 3840 || height > 2160)); then
echo "3840x2160"
else
echo "0x0"
fi
}
toggle_screenrecording_indicator() {
pkill -RTMIN+8 waybar
}
cleanup_webcam() { cleanup_webcam() {
pkill -f "WebcamOverlay" 2>/dev/null pkill -f "WebcamOverlay" 2>/dev/null
} }
@@ -36,7 +55,7 @@ start_webcam_overlay() {
# Auto-detect first available webcam if none specified # Auto-detect first available webcam if none specified
if [[ -z $WEBCAM_DEVICE ]]; then if [[ -z $WEBCAM_DEVICE ]]; then
WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^\s*/dev/video" | tr -d '\t') WEBCAM_DEVICE=$(v4l2-ctl --list-devices 2>/dev/null | grep -m1 "^[[:space:]]*/dev/video" | tr -d '\t')
if [[ -z $WEBCAM_DEVICE ]]; then if [[ -z $WEBCAM_DEVICE ]]; then
notify-send "No webcam devices found" -u critical -t 3000 notify-send "No webcam devices found" -u critical -t 3000
return 1 return 1
@@ -74,7 +93,7 @@ start_webcam_overlay() {
start_screenrecording() { start_screenrecording() {
local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4" local filename="$OUTPUT_DIR/screenrecording-$(date +'%Y-%m-%d_%H-%M-%S').mp4"
local audio_devices="" local audio_devices=""
local audio_args="" local audio_args=()
[[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output" [[ $DESKTOP_AUDIO == "true" ]] && audio_devices+="default_output"
@@ -84,21 +103,21 @@ start_screenrecording() {
audio_devices+="default_input" audio_devices+="default_input"
fi fi
[[ -n $audio_devices ]] && audio_args+="-a $audio_devices" [[ -n $audio_devices ]] && audio_args+=(-a "$audio_devices" -ac aac)
gpu-screen-recorder -w portal -k h264 -f 60 -fallback-cpu-encoding yes -o "$filename" $audio_args -ac aac & local resolution="${RESOLUTION:-$(default_resolution)}"
gpu-screen-recorder -w portal -k auto -s "$resolution" -f 60 -fallback-cpu-encoding yes -o "$filename" "${audio_args[@]}" &
local pid=$!
# Wait for recording to actually start (file appears after portal selection)
while kill -0 $pid 2>/dev/null && [[ ! -f $filename ]]; do
sleep 0.2
done
if kill -0 $pid 2>/dev/null; then
echo "$filename" >"$RECORDING_FILE"
toggle_screenrecording_indicator toggle_screenrecording_indicator
}
trim_first_frame() {
local latest=$(ls -t "$OUTPUT_DIR"/screenrecording-*.mp4 2>/dev/null | head -1)
if [[ -n $latest ]]; then
local trimmed="${latest%.mp4}-trimmed.mp4"
if ffmpeg -y -ss 0.1 -i "$latest" -c copy "$trimmed" -loglevel quiet 2>/dev/null; then
mv "$trimmed" "$latest"
else
rm -f "$trimmed"
fi
fi fi
} }
@@ -112,36 +131,44 @@ stop_screenrecording() {
count=$((count + 1)) count=$((count + 1))
done done
toggle_screenrecording_indicator
cleanup_webcam
if pgrep -f "^gpu-screen-recorder" >/dev/null; then if pgrep -f "^gpu-screen-recorder" >/dev/null; then
pkill -9 -f "^gpu-screen-recorder" pkill -9 -f "^gpu-screen-recorder"
cleanup_webcam
notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000 notify-send "Screen recording error" "Recording process had to be force-killed. Video may be corrupted." -u critical -t 5000
else else
cleanup_webcam
trim_first_frame trim_first_frame
notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000 notify-send "Screen recording saved to $OUTPUT_DIR" -t 2000
fi fi
toggle_screenrecording_indicator
}
toggle_screenrecording_indicator() { rm -f "$RECORDING_FILE"
pkill -RTMIN+8 waybar
} }
screenrecording_active() { screenrecording_active() {
pgrep -f "^gpu-screen-recorder" >/dev/null || pgrep -f "WebcamOverlay" >/dev/null pgrep -f "^gpu-screen-recorder" >/dev/null
}
trim_first_frame() {
local latest
latest=$(cat "$RECORDING_FILE" 2>/dev/null)
if [[ -n $latest && -f $latest ]]; then
local trimmed="${latest%.mp4}-trimmed.mp4"
if ffmpeg -y -ss 0.1 -i "$latest" -c copy "$trimmed" -loglevel quiet 2>/dev/null; then
mv "$trimmed" "$latest"
else
rm -f "$trimmed"
fi
fi
} }
if screenrecording_active; then if screenrecording_active; then
if pgrep -f "WebcamOverlay" >/dev/null && ! pgrep -f "^gpu-screen-recorder" >/dev/null; then
cleanup_webcam
else
stop_screenrecording stop_screenrecording
fi elif [[ $STOP_RECORDING == "true" ]]; then
elif [[ $STOP_RECORDING == "false" ]]; then exit 1
else
[[ $WEBCAM == "true" ]] && start_webcam_overlay [[ $WEBCAM == "true" ]] && start_webcam_overlay
start_screenrecording || cleanup_webcam start_screenrecording || cleanup_webcam
else
exit 1
fi fi