2023-05-13 02:05:36 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
#
|
|
|
|
# Copyright (C) 2023 Skylar Widulski
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
|
|
# Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
# version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
RUNTIME="${XDG_RUNTIME_DIR:-/run}/wf-shadow"
|
2023-05-13 23:23:11 +00:00
|
|
|
CONFIG="${WF_SHADOW_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/wf-shadow/config.sh}"
|
|
|
|
|
|
|
|
if [ ! -d "${CONFIG%/*}" ]; then
|
|
|
|
mkdir -p "${CONFIG%/*}" 2>/dev/null
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -f "$CONFIG" ]; then
|
|
|
|
printf '' >> "$CONFIG"
|
|
|
|
fi
|
2023-05-13 02:05:36 +00:00
|
|
|
|
|
|
|
MONITOR=1
|
|
|
|
AUDIO_DEV=""
|
2023-05-14 00:38:34 +00:00
|
|
|
NO_AUDIO=""
|
2023-05-13 02:05:36 +00:00
|
|
|
VIDEO_DEV=""
|
|
|
|
VERBOSE=""
|
2023-05-14 00:38:34 +00:00
|
|
|
: "${WF_SHADOW_DIR:="$HOME"/Videos/wf-shadow}"
|
|
|
|
: "${WF_SHADOW_FORMAT:=%Y%m%d_%H:%M:%S}"
|
2023-05-13 23:23:11 +00:00
|
|
|
|
|
|
|
. "$CONFIG"
|
|
|
|
|
2023-05-14 00:38:34 +00:00
|
|
|
if [ -n "$NO_AUDIO" ]; then
|
|
|
|
NO_AUDIO=" "
|
|
|
|
fi
|
|
|
|
|
2023-05-13 23:23:11 +00:00
|
|
|
trap 'kill $(jobs -p) 2>/dev/null' EXIT
|
2023-05-13 02:05:36 +00:00
|
|
|
trap 'exit' INT
|
|
|
|
set -m
|
|
|
|
|
|
|
|
if [ ! -d "$RUNTIME" ]; then
|
|
|
|
mkdir -p "$RUNTIME" 2>/dev/null
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -d /tmp/wf-shadow ]; then
|
|
|
|
mkdir -p /tmp/wf-shadow 2>/dev/null
|
|
|
|
fi
|
|
|
|
|
2023-05-13 23:23:11 +00:00
|
|
|
if [ ! -d "$WF_SHADOW_DIR" ]; then
|
|
|
|
mkdir -p "$WF_SHADOW_DIR" 2>/dev/null
|
2023-05-13 02:05:36 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
if ! command -v wf-recorder &>/dev/null; then
|
|
|
|
printf "Need wf-recorder\n"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! command -v wofi &>/dev/null; then
|
|
|
|
printf "Need wofi\n"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
print_help() {
|
|
|
|
cat << EOF
|
|
|
|
wf-shadow: A Wayland shadow recorder using wf-recorder and wofi
|
|
|
|
|
|
|
|
USAGE: wf-shadow OPTION [OPTIONS...]
|
|
|
|
|
|
|
|
OPTIONS:
|
2023-05-13 23:23:11 +00:00
|
|
|
-s, --start [MONITOR] Start a wf-shadow instance with display number MONITOR.
|
|
|
|
-r, --record [MONITOR] Record the last few moments of video using a wofi menu.
|
|
|
|
-e, --end [MONITOR] End wf-shadow instance with display number MONITOR.
|
|
|
|
-a, --audio DEVICE Use DEVICE for audio recording. Passed to wf-recorder -a.
|
|
|
|
-V, --video DEVICE Use DEVICE for video encoding. Passed to wf-recorder -d.
|
2023-05-14 00:38:34 +00:00
|
|
|
-n, --no-audio Disable audio recording. Overrides -a.
|
2023-05-13 23:23:11 +00:00
|
|
|
-v, --verbose Verbose output.
|
|
|
|
-h, --help Show this menu.
|
|
|
|
|
|
|
|
For a more in-depth guide, see wf-shadow(1)
|
2023-05-13 02:05:36 +00:00
|
|
|
EOF
|
|
|
|
exit $1
|
|
|
|
}
|
|
|
|
|
|
|
|
record() {
|
2023-05-13 23:23:11 +00:00
|
|
|
local SAVE_FILE
|
|
|
|
if [ ! $WF_SHADOW_SAVE ]; then
|
|
|
|
SAVE_FILE="$WF_SHADOW_DIR"/"$(date +"$WF_SHADOW_FORMAT")__$2".mp4
|
|
|
|
else
|
|
|
|
SAVE_FILE="$(eval "$WF_SHADOW_SAVE")"
|
|
|
|
fi
|
|
|
|
if [ -n "$VERBOSE" ]; then
|
|
|
|
if ffmpeg -nostdin -y -sseof -"$2" -i "$1" "$SAVE_FILE" &>/dev/null; then
|
|
|
|
notify-send "Clip saved" "$2 second clip saved to $SAVE_FILE"
|
2023-05-13 02:05:36 +00:00
|
|
|
else
|
|
|
|
notify-send "Error saving clip" "Start a new session with --verbose to see ffmpeg output"
|
|
|
|
fi
|
|
|
|
else
|
2023-05-13 23:23:11 +00:00
|
|
|
if ffmpeg -nostdin -y -sseof -"$2" -i "$1" "$SAVE_FILE"; then
|
|
|
|
notify-send "Clip saved" "$2 second clip saved to $SAVE_FILE"
|
2023-05-13 02:05:36 +00:00
|
|
|
else
|
|
|
|
notify-send "Error saving clip" "Start a new session with --verbose to see ffmpeg output"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
start() {
|
|
|
|
local WOFI_STRING="5 seconds\n10 seconds\n15 seconds\n30 seconds\n1 minute\n5 minutes\n10 minutes\nCancel\n"
|
|
|
|
while true; do
|
2023-05-14 00:38:34 +00:00
|
|
|
for i in /tmp/wf-shadow/"$MONITOR"-{00..10}.mp4; do
|
2023-05-13 23:23:11 +00:00
|
|
|
printf '' >> "$i"
|
|
|
|
if [ -n "$VERBOSE" ]; then
|
2023-05-14 00:38:34 +00:00
|
|
|
wf-recorder ${VIDEO_DEV:+-d "$VIDEO_DEV"} ${NO_AUDIO:--a} ${AUDIO_DEV:+"${NO_AUDIO:-$AUDIO_DEV}"} -f "$i" <<< y$'\n'$MONITOR &
|
2023-05-13 02:05:36 +00:00
|
|
|
else
|
2023-05-14 00:38:34 +00:00
|
|
|
wf-recorder ${VIDEO_DEV:+-d "$VIDEO_DEV"} ${NO_AUDIO:--a} ${AUDIO_DEV:+"${NO_AUDIO:-$AUDIO_DEV}"} -f "$i" <<< y$'\n'$MONITOR &>/dev/null &
|
2023-05-13 02:05:36 +00:00
|
|
|
fi
|
|
|
|
printf "%s" "$!" > "$RUNTIME"/"$MONITOR".pid
|
|
|
|
fg || exit
|
|
|
|
|
2023-05-13 23:23:11 +00:00
|
|
|
case "$(if [ -n "$VERBOSE" ]; then
|
|
|
|
printf "$WOFI_STRING" | wofi --dmenu -i -H 500 -W 250 -x 0 -y 0
|
|
|
|
else
|
|
|
|
printf "$WOFI_STRING" | wofi --dmenu -i -H 500 -W 250 -x 0 -y 0 &> /dev/null
|
|
|
|
fi)" in
|
|
|
|
|
2023-05-13 02:05:36 +00:00
|
|
|
'5 seconds') record "$i" 5 ;;
|
|
|
|
'10 seconds') record "$i" 10 ;;
|
|
|
|
'15 seconds') record "$i" 15 ;;
|
|
|
|
'30 seconds') record "$i" 30 ;;
|
|
|
|
'1 minute') record "$i" 60 ;;
|
|
|
|
'5 minutes') record "$i" 300 ;;
|
|
|
|
'10 minutes') record "$I" 600 ;;
|
|
|
|
*) ;;
|
|
|
|
esac &
|
|
|
|
done
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
until [ -z "$1" ]; do
|
2023-05-13 23:23:11 +00:00
|
|
|
re="[0-9]+"
|
2023-05-13 02:05:36 +00:00
|
|
|
case "$1" in
|
|
|
|
'-h' | '--help') print_help ;;
|
|
|
|
'-e' | '--end')
|
|
|
|
END=1
|
2023-05-13 23:23:11 +00:00
|
|
|
if [[ "$2" =~ $re ]]; then
|
|
|
|
MONITOR="$2"
|
|
|
|
shift 2
|
|
|
|
else
|
|
|
|
shift 1
|
|
|
|
fi ;;
|
2023-05-13 02:05:36 +00:00
|
|
|
'-r' | '--record')
|
|
|
|
RECORD=1
|
2023-05-13 23:23:11 +00:00
|
|
|
if [[ "$2" =~ $re ]]; then
|
|
|
|
MONITOR="$2"
|
|
|
|
shift 2
|
|
|
|
else
|
|
|
|
shift 1
|
|
|
|
fi ;;
|
2023-05-13 02:05:36 +00:00
|
|
|
'-s' | '--start')
|
|
|
|
START=1
|
2023-05-13 23:23:11 +00:00
|
|
|
if [[ "$2" =~ $re ]]; then
|
|
|
|
MONITOR="$2"
|
|
|
|
shift 2
|
|
|
|
else
|
|
|
|
shift 1
|
|
|
|
fi ;;
|
2023-05-13 02:05:36 +00:00
|
|
|
'-a' | '--audio')
|
|
|
|
AUDIO_DEV="$2"
|
|
|
|
shift 2 ;;
|
2023-05-14 00:38:34 +00:00
|
|
|
'-n' | '--no-audio')
|
|
|
|
NO_AUDIO=1
|
|
|
|
shift 1 ;;
|
2023-05-13 02:05:36 +00:00
|
|
|
'-V' | '--video')
|
|
|
|
VIDEO_DEV="$2"
|
|
|
|
shift 2 ;;
|
|
|
|
'-v' | '--verbose')
|
|
|
|
VERBOSE="1"
|
|
|
|
shift 1 ;;
|
|
|
|
*) print_help ;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ "$START" == 1 ]; then
|
|
|
|
if [ "$MONITOR" ]; then
|
|
|
|
if [ ! -e "$RUNTIME"/"$MONITOR"_host.pid ]; then
|
|
|
|
printf "%s" "$$" > "$RUNTIME"/"$MONITOR"_host.pid
|
|
|
|
start
|
|
|
|
else
|
2023-05-14 00:43:49 +00:00
|
|
|
printf "A wf-shadow instance is already running on display %d (%s/%d_host.pid)\n" "$MONITOR" "$RUNTIME" "$MONITOR"
|
2023-05-13 02:05:36 +00:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
print_help 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "$RECORD" == 1 ]; then
|
|
|
|
if [ "$MONITOR" ]; then
|
|
|
|
kill -2 "$(<"$RUNTIME"/"$MONITOR".pid)"
|
|
|
|
else
|
|
|
|
print_help 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "$END" == 1 ]; then
|
|
|
|
if [ "$MONITOR" ]; then
|
|
|
|
kill "$(<"$RUNTIME"/"$MONITOR"_host.pid)" &&
|
|
|
|
rm -f "$RUNTIME"/"$MONITOR"_host.pid
|
|
|
|
else
|
|
|
|
print_help 1
|
|
|
|
fi
|
|
|
|
fi
|