From 8a3ae0f6bda0869416d32331c4e11707cbb203a1 Mon Sep 17 00:00:00 2001 From: Steve Beaulac Date: Fri, 28 Aug 2026 11:52:43 -0400 Subject: [PATCH] feat: add screen recording, OCR capture, and improved screenshot workflow --- config/hypr/hyprland.lua | 20 ++++++++- mise.toml | 1 + packages/sjb-desktop.packages | 2 + script/screen-recorder | 83 +++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100755 script/screen-recorder diff --git a/config/hypr/hyprland.lua b/config/hypr/hyprland.lua index 6ff25d0..a5c840e 100644 --- a/config/hypr/hyprland.lua +++ b/config/hypr/hyprland.lua @@ -192,8 +192,24 @@ hl.bind(HYPR .. "B", hl.dsp.exec_cmd("blueberry"), { description = "Bluetooth ma hl.bind(HYPR .. "semicolon", hl.dsp.exec_cmd("~/.local/bin/set-wallpaper.sh categories/quotes"), { description = "get new wallpaper" }) -hl.bind("Print", hl.dsp.exec_cmd("hyprshot -m window"), { description = "Take screenshot" }) -hl.bind("SHIFT + Print", hl.dsp.exec_cmd("hyprshot -m region"), { description = "Take screenshot" }) +hl.bind("Print", + hl.dsp.exec_cmd("hyprshot -m window -o ~/Pictures/ -- tensaku-edit"), + { description = "Take screenshot" }) +hl.bind("SHIFT + Print", + hl.dsp.exec_cmd("hyprshot -m region -o ~/Pictures/ -- tensaku-edit"), + { description = "Take screenshot" }) + +hl.bind("ALT + Print", + hl.dsp.exec_cmd("hyprshot -m region --raw -z | /usr/bin/tesseract stdin stdout --oem 1 --psm 6 -l eng | wl-copy"), + { description = "Capture text" }) + +hl.bind("SUPER + Print", + hl.dsp.exec_cmd("~/.local/bin/screen-recorder -o ~/Videos/$(date +'%Y-%m-%d_%H%M%S')_recording.mp4"), + { description = "Start/Stop screen recording" }) + +hl.bind("SUPER + SHIFT + Print", + hl.dsp.exec_cmd("~/.local/bin/screen-recorder stop"), + { description = "Stop screen recording" }) hl.bind(HYPR .. "A", hl.dsp.exec_cmd("gtk-launch pi.desktop"), { description = "Open pi tui" }) hl.bind(HYPR .. "C", dispatch_focus_or_launch({ diff --git a/mise.toml b/mise.toml index 16349c3..a35b822 100644 --- a/mise.toml +++ b/mise.toml @@ -88,6 +88,7 @@ dotfiles.default_mode = "symlink-each" "~/.local/bin/hyprland-fetch-client" = { source = "script/hyprland-fetch-client", mode = "symlink" } "~/.local/bin/hyprland-focus-client" = { source = "script/hyprland-focus-client", mode = "symlink" } "~/.local/bin/terminal-launcher" = { source = "script/terminal-launcher", mode = "symlink" } +"~/.local/bin/screen-recorder" = { source = "script/screen-recorder", mode = "symlink" } "~/.local/bin/battery" = { source = "script/battery", mode = "symlink" } # "~/.config/bin/ec" = { source = "script/ec", mode = "symlink" } diff --git a/packages/sjb-desktop.packages b/packages/sjb-desktop.packages index 899a69c..ed6f123 100644 --- a/packages/sjb-desktop.packages +++ b/packages/sjb-desktop.packages @@ -79,6 +79,8 @@ slurp spotify tenacity tensaku-bin +tesseract +tesseract-data-eng ttf-0xproto-nerd ttf-bitstream-vera ttf-dejavu diff --git a/script/screen-recorder b/script/screen-recorder new file mode 100755 index 0000000..f93c86f --- /dev/null +++ b/script/screen-recorder @@ -0,0 +1,83 @@ +#!/bin/sh + +LOG_FILE=$([[ ${DEBUG_SCREENRECORDER:-false} == "true" ]] && echo "/tmp/screenrecord.log" || echo "/dev/null") + +usage() { + echo "Usage: screen-recorder stop | screen-recorder [-a] [-m region|monitor|window] -o " >&2 +} + +if [ "$#" -eq 1 ] && [ "$1" = stop ]; then + pkill -SIGINT -f "gpu-screen-recorder" + + count=0 + while pgrep -f "gpu-screen-recorder" >/dev/null && ((count < 50)); do + sleep 0.1 + count=$((count + 1)) + done + + if pgrep -f "gpu-screen-recorder" >/dev/null; then + pkill -9 -f "gpu-screen-recorder" + fi + notify-send "Screen Recorder" "Recording stopped" -t 2000 + exit $? +fi + +if pgrep -f "gpu-screen-recorder" >/dev/null; then + notify-send "Screen Recorder" "Recording is already in progress" -t 2000 + exit 1 +fi + +mode=monitor +output_filename="/tmp/output.mp4" +audio_args=() +while getopts ":am:o:h" opt; do + case "$opt" in + a) audio_args=(-a default_input -ac aac) ;; + m) mode=$OPTARG ;; + o) output_filename=$OPTARG ;; + h) usage; exit 0 ;; + :) usage; exit 1 ;; + \?) usage; exit 1 ;; + esac +done +shift $((OPTIND - 1)) + +if [ "$#" -ne 0 ] || [ -z "$output_filename" ]; then + usage + exit 1 +fi + +script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +recorder=$(PATH=$(printf '%s' "$PATH" | awk -v RS=: -v ORS=: -v script_dir="$script_dir" '$0 != script_dir') command -v gpu-screen-recorder) +if [ -z "$recorder" ]; then + echo "gpu-screen-recorder executable not found" >&2 + exit 1 +fi + +capture_args=() +case "$mode" in + monitor) + target=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .name') + [ -n "$target" ] || exit 1 + capture_args=(-w "$target") + ;; + region) + target=$(slurp -f '%wx%h+%x+%y') || exit 1 + [ -n "$target" ] || exit 1 + capture_args=(-w region -region "$target") + ;; + window) + target=$(hyprctl clients -j | + jq -r '.[] | select(.mapped == true and .hidden == false and .at != null and .size != null) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1]) \((.title // .class // "window") | gsub("[\\r\\n]"; " "))"' | + slurp -r) || exit 1 + [ -n "$target" ] || exit 1 + capture_args=(-w region -region "$target") + ;; + *) + echo "Invalid mode: $mode" >&2 + usage + exit 1 + ;; +esac + +exec "$recorder" "${capture_args[@]}" "${audio_args[@]}" -k auto -f 60 -fm cfr -fallback-cpu-encoding yes -o "$output_filename" 2>>"$LOG_FILE" &