screen-toolkit : full screen utility (#221)

* screen-toolkit: add Noctalia v5 plugin

* screen-toolkit: credit original plugin

* screen-toolkit: fix recording, OCR capture, and result panel UX

* screen-toolkit: rename record tool labels to Record / Rec FS

* screen-toolkit: update plugin thumbnail

* screen-toolkit: fix README validation (backtick deps, result panel toggle)

* screen-toolkit: fix OCR results and dependencies

* screen-toolkit: backtick recording and annotator deps in README

---------

Co-authored-by: Ahmed5Emad <ahmed5emad@users.noreply.github.com>
This commit is contained in:
Ahmed Emad
2026-08-03 08:22:08 -04:00
committed by GitHub
co-authored by Ahmed5Emad
parent 57227f8b51
commit 636317303c
15 changed files with 2860 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env bash
# record.sh <action> [args...]
#
# Actions:
# thumb <src> — extract mid-frame thumbnail → /tmp/screen-toolkit-record-thumb.png
# convert-mp4 <input> <output> — finalize MP4: stream-copy (fast path)
# convert-mp4 <input> <output> --recode — finalize MP4: re-encode audio to AAC 128k + faststart
# convert-gif <input> <output> [maxsec] — convert MP4 → palette-optimized GIF at 15 fps
# convert-mov <input> <output> — remux MP4 → MOV (stream copy)
# stop <recorder-bin> — send SIGINT to the named recorder process
#
# Exit codes:
# 1 — missing / invalid arguments
# 2 — input file not found
# 3 — missing dependency (ffmpeg, ffprobe, pkill)
# 4 — conversion or process command failed
#
# Used by: service.luau
set -euo pipefail
ACTION="${1:-}"
THUMB_OUT="/tmp/screen-toolkit-record-thumb.png"
PALETTE="/tmp/screen-toolkit-record-palette.png"
_require() {
command -v "$1" >/dev/null 2>&1 \
|| { echo "ERROR: missing dependency: $1" >&2; exit 3; }
}
_thumb() {
local src="$1"
_require ffprobe
_require ffmpeg
local dur
dur=$(ffprobe -v error \
-show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 \
"$src" 2>/dev/null) || dur=""
[[ -z "$dur" || "$dur" == "N/A" ]] && dur=1
local mid
mid=$(echo "$dur / 2" | bc -l 2>/dev/null) || mid="0.5"
ffmpeg -y -ss "$mid" -i "$src" -frames:v 1 "$THUMB_OUT" 2>/dev/null
}
case "$ACTION" in
thumb)
SRC="${2:-}"
[ -n "$SRC" ] || { echo "ERROR: thumb: missing <src>" >&2; exit 1; }
[ -f "$SRC" ] || { echo "ERROR: thumb: file not found: $SRC" >&2; exit 2; }
_thumb "$SRC"
;;
convert-mp4)
INPUT="${2:-}"
OUTPUT="${3:-}"
RECODE="${4:-}"
[ -n "$INPUT" ] || { echo "ERROR: convert-mp4: missing <input>" >&2; exit 1; }
[ -n "$OUTPUT" ] || { echo "ERROR: convert-mp4: missing <output>" >&2; exit 1; }
[ -f "$INPUT" ] || { echo "ERROR: convert-mp4: file not found: $INPUT" >&2; exit 2; }
_require ffmpeg
if [ "$RECODE" = "--recode" ]; then
ffmpeg -y -i "$INPUT" \
-c:v copy -c:a aac -b:a 128k -movflags +faststart \
"$OUTPUT" 2>/dev/null \
|| { echo "ERROR: convert-mp4: ffmpeg recode failed" >&2; exit 4; }
rm -f "$INPUT"
else
mv "$INPUT" "$OUTPUT" \
|| { echo "ERROR: convert-mp4: mv failed" >&2; exit 4; }
fi
_thumb "$OUTPUT"
;;
convert-gif)
INPUT="${2:-}"
OUTPUT="${3:-}"
MAXSEC="${4:-}"
[ -n "$INPUT" ] || { echo "ERROR: convert-gif: missing <input>" >&2; exit 1; }
[ -n "$OUTPUT" ] || { echo "ERROR: convert-gif: missing <output>" >&2; exit 1; }
[ -f "$INPUT" ] || { echo "ERROR: convert-gif: file not found: $INPUT" >&2; exit 2; }
_require ffmpeg
DURATION=""
if [ -n "$MAXSEC" ] && [ "$MAXSEC" -gt 0 ] 2>/dev/null; then
DURATION="-t $MAXSEC"
fi
ffmpeg -y $DURATION -i "$INPUT" \
-vf 'fps=15,scale=trunc(iw/2)*2:trunc(ih/2)*2:flags=lanczos,palettegen' \
"$PALETTE" 2>/dev/null \
|| { echo "ERROR: convert-gif: palettegen pass failed" >&2; exit 4; }
ffmpeg -y $DURATION -i "$INPUT" -i "$PALETTE" \
-lavfi 'fps=15,scale=trunc(iw/2)*2:trunc(ih/2)*2:flags=lanczos[x];[x][1:v]paletteuse' \
"$OUTPUT" 2>/dev/null \
|| { echo "ERROR: convert-gif: paletteuse pass failed" >&2; exit 4; }
rm -f "$PALETTE" "$INPUT"
_thumb "$OUTPUT"
;;
convert-mov)
INPUT="${2:-}"
OUTPUT="${3:-}"
[ -n "$INPUT" ] || { echo "ERROR: convert-mov: missing <input>" >&2; exit 1; }
[ -n "$OUTPUT" ] || { echo "ERROR: convert-mov: missing <output>" >&2; exit 1; }
[ -f "$INPUT" ] || { echo "ERROR: convert-mov: file not found: $INPUT" >&2; exit 2; }
_require ffmpeg
ffmpeg -y -i "$INPUT" -c copy -movflags +faststart "$OUTPUT" 2>/dev/null \
|| { echo "ERROR: convert-mov: ffmpeg failed" >&2; exit 4; }
rm -f "$INPUT"
_thumb "$OUTPUT"
;;
stop)
BIN="${2:-}"
[ -n "$BIN" ] || { echo "ERROR: stop: missing <recorder-bin>" >&2; exit 1; }
_require pkill
pkill -INT "$BIN" 2>/dev/null || true
;;
*)
echo "ERROR: unknown action '${ACTION}'. Expected: thumb | convert-mp4 | convert-gif | convert-mov | stop" >&2
exit 1
;;
esac