feat(scripts): add screenshot.sh

This commit is contained in:
Tibo De Peuter 2026-06-21 14:48:27 +02:00
parent f5d6149d03
commit e158449bf3
No known key found for this signature in database
GPG key ID: 9187B5FA0F4B6F6D

178
scripts/screenshot.sh Executable file
View file

@ -0,0 +1,178 @@
#!/usr/bin/env bash
# Take screenshots of areas, windows, or screens, interactively or immediately.
# Usage: screenshot [-t area|window|screen|all] [-a copy|save] [-i]
set -u
TARGET='area'
ACTION='copy'
INTERACTIVE='false'
DATE_STR="$( date '+%F-%H-%M-%S' )"
SAVE_DIR="${HOME}/Nextcloud/Afbeeldingen/Screenshots"
panic () {
>&2 echo 'Usage: screenshot [-t area|window|screen|all] [-a copy|save] [-i]'
exit 1
}
# Get options
while getopts ':t:a:i' option; do
case "${option}" in
t)
if [[ "${OPTARG}" =~ ^(area|window|screen|all)$ ]]; then
TARGET="${OPTARG}"
else
>&2 printf "Error: Invalid target '%s'.\n" "${OPTARG}"
panic
fi
;;
a)
if [[ "${OPTARG}" =~ ^(copy|save)$ ]]; then
ACTION="${OPTARG}"
else
>&2 printf "Error: Invalid action '%s'.\n" "${OPTARG}"
fi
;;
i)
INTERACTIVE='true'
;;
*)
panic
;;
esac
done
if [[ "${ACTION}" == 'save' ]]; then
SAVE_PATH="${SAVE_DIR}/${DATE_STR}.png"
else
SAVE_PATH="/tmp/screenshot_${DATE_STR}.png"
fi
mkdir -p "${SAVE_DIR}"
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]] && command -v hyprctl >/dev/null 2>&1 ; then
WM='hyprland'
else
>&2 echo 'Error: Unsupported or undetected Window Manager.'
exit 1
fi
for tool in grim slurp wl-copy jq; do
if ! command -v "${tool}" >/dev/null 2>&1; then
>&2 echo "Error: Required dependency '${tool}' is missing."
exit 1
fi
done
# Helper functions
target_area () {
slurp || true
}
hyprland_target_window () {
hyprctl activewindow -j \
| jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"'
}
hyprland_target_window_interactive () {
local ws_id
ws_id="$( hyprctl activeworkspace -j | jq -r '.id' )"
hyprctl clients -j \
| jq -r --arg ws "${ws_id}" '.[] | select(.workspace.id == ($ws | tonumber)) | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' \
| slurp -d \
|| true
}
hyprland_target_screen () {
local ws_id
ws_id="$(hyprctl activeworkspace -j | jq -r '.id')"
hyprctl monitors -j \
| jq -r --arg ws "${ws_id}" '.[] | select(.activeWorkspace.id == ($ws | tonumber)) | .name'
}
hyprland_target_screen_interactive () {
hyprctl monitors -j \
| jq -r '.[] | "\(.x),\(.y) \(.width)x\(.height)"' \
| slurp -d \
|| true
}
# Capturing the screenshot
GEOMETRY=''
OUTPUT=''
fetch_target_data () {
if [[ "${TARGET}" == 'area' ]]; then
GEOMETRY="$( target_area )"
return 0
fi
local route_key="${WM}_${TARGET}_${INTERACTIVE}"
case "${route_key}" in
'hyprland_window_false')
GEOMETRY="$( hyprland_target_window )"
;;
'hyprland_window_true')
GEOMETRY="$( hyprland_target_window_interactive )"
;;
'hyprland_screen_false')
OUTPUT="$( hyprland_target_screen )"
;;
'hyprland_screen_true')
GEOMETRY="$( hyprland_target_screen_interactive )"
;;
*)
>&2 echo 'Error: Unmapped execution route.'
exit 1
;;
esac
}
if [[ "${TARGET}" != 'all' ]]; then
fetch_target_data
fi
# Detect cancellation, Escape pressed during slurp results in empty string.
if [[ "${INTERACTIVE}" == 'true' || "${TARGET}" == 'area' ]]; then
if [[ -z "${GEOMETRY}" && -z "${OUTPUT}" ]]; then
exit 0
fi
fi
# Take the screenshot
if [[ -n "${GEOMETRY}" ]]; then
grim -g "${GEOMETRY}" "${SAVE_PATH}"
elif [[ -n "${OUTPUT}" ]]; then
grim -o "${OUTPUT}" "${SAVE_PATH}"
else
grim "${SAVE_PATH}"
fi
# Route to clipboard
if [[ "${ACTION}" == 'copy' ]]; then
wl-copy < "${SAVE_PATH}"
fi
# Notifications
if [[ "${TARGET}" != 'area' || "${INTERACTIVE}" == 'true' ]]; then
NOTIF_ICON="${SAVE_PATH}"
if command -v magick >/dev/null 2>&1; then
THUMB_PATH="/tmp/thumb_${DATE_STR}.png"
if magick "${SAVE_PATH}" -thumbnail '320x320^' -gravity center -extent 320x320 "${THUMB_PATH}" >/dev/null 2>&1; then
NOTIF_ICON="${THUMB_PATH}"
fi
fi
if [[ "${ACTION}" == 'copy' ]]; then
notify-send -a 'Grim' -i "${NOTIF_ICON}" 'Screenshot Captured' 'Copied to clipboard'
else
notify-send -a 'Grim' -i "${NOTIF_ICON}" 'Screenshot Captured' "Saved to ${SAVE_PATH}"
fi
fi