#!/usr/bin/env bash # # Copyright (C) 2024 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 . # VER="v1.3.1" RUNTIME="${XDG_RUNTIME_DIR:-/run}/wf-shadow" CONFIG="${WF_SHADOW_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/wf-shadow/config.sh}" AUDIO_DEV="" AUDIO_CODEC="" NO_AUDIO="" VIDEO_DEV="" VIDEO_CODEC="" NO_VIDEO="" : "${WF_SHADOW_DIR:="$HOME"/Videos/wf-shadow}" : "${WF_SHADOW_FMT:=%Y%m%d_%H:%M:%S}" : "${WF_SHADOW_EXT:=mp4}" . "$CONFIG" TITLE='--title wf-shadow-tui' if ! command -v wf-shadow &>/dev/null; then printf 'Need wf-shadow\n' fi if ! command -v wlr-randr &>/dev/null; then printf 'Need wlr-randr\n' fi if ! command -v dialog &>/dev/null; then printf 'Need dialog\n' fi if command -v tput &>/dev/null; then tput smcup fi trap 'if command -v tput &>/dev/null; then tput rmcup; fi' EXIT get_output() { RANDR="$(wlr-randr)" OUTPUT="$(eval "dialog $TITLE --menu 'Output:' 24 64 24 $(while read -r line; do if [[ "$line" =~ - ]]; then tmp="${line#*(}" tmp="${tmp%)*}" printf "'%s' \t" "$tmp" tmp=${line#*\"} tmp="${tmp% (*}" printf "'%s' " "$tmp" fi done <<< "$RANDR") 3>&1 1>&2 2>&3")" } get_action() { ACTION="$(eval "dialog $TITLE --menu 'Action for output $OUTPUT:' 24 64 24 $([ ! -f "$RUNTIME/${OUTPUT}_host.pid" ] && printf "'Start' 'Start a session of wf-shadow on this output'") $([ -f "$RUNTIME/${OUTPUT}_host.pid" ] && printf "'Record' 'Clip the last few seconds of video' 'End' 'End the wf-shadow session'") 3>&1 1>&2 2>&3")" } get_seconds() { TIME="$(eval "dialog $TITLE --inputbox 'Seconds to clip:' 0 0 30 3>&1 1>&2 2>&3")" } get_seconds_wrap() { unset TIME get_seconds if [ -z "$TIME" ]; then get_action_wrap else wf-shadow -R "$OUTPUT" "$(<"$RUNTIME/${OUTPUT}_current")" "$TIME" & get_action_wrap fi } get_output_wrap() { unset OUTPUT get_output if [ -z "$OUTPUT" ]; then get_main_wrap else get_action_wrap fi } get_action_wrap() { unset ACTION get_action if [ -z "$ACTION" ]; then get_output_wrap else case "$ACTION" in Start) wf-shadow --start "$OUTPUT" &>/dev/null & disown sleep 0.1 get_action_wrap ;; End) wf-shadow --end "$OUTPUT" sleep 0.1 get_action_wrap ;; Record) get_seconds_wrap ;; esac fi } get_option() { OPTION="$(eval "dialog $TITLE --menu "Configuration" 24 125 24 'AUDIO_DEV' 'PulseAudio device to record' 'AUDIO_CODEC' 'FFmepg audio codec' 'NO_AUDIO' 'Whether or not no audio should be recorded' 'VIDEO_DEV' 'DRI render device (/dev/dri/renderDxxx) to use to encode video' 'VIDEO_CODEC' 'FFmpeg video codec' 'NO_VIDEO' 'Whether or not no video should be encoded into the final clips' 'WF_SHADOW_DIR' 'Directory to store clips in' 'WF_SHADOW_FMT' '\`date\` format to use in file names of clips' 'WF_SHADOW_EXT' 'Container and file extension to use in clip file names' 'WF_SHADOW_SAVE' 'Command used to get the path to the file in which clips should be saved. Overrides the last 3 options.' 3>&1 1>&2 2>&3")" } option_inputbox() { eval "dialog $TITLE --inputbox '$1' 0 '$2' $3 3>&1 1>&2 2>&3" } option_yesno() { eval "dialog $TITLE --yesno 'NO_$1' 5 24 3>&1 1>&2 2>&3" case $? in 0) printf 1 ;; esac } option_dir() { eval "dialog $TITLE --dselect $HOME 60 80 3>&1 1>&2 2>&3" } config_to_file() { declare -p AUDIO_DEV > "$CONFIG" declare -p AUDIO_CODEC >> "$CONFIG" declare -p NO_AUDIO >> "$CONFIG" declare -p VIDEO_DEV >> "$CONFIG" declare -p VIDEO_CODEC >> "$CONFIG" declare -p NO_VIDEO >> "$CONFIG" declare -p WF_SHADOW_DIR >> "$CONFIG" declare -p WF_SHADOW_FMT >> "$CONFIG" declare -p WF_SHADOW_EXT >> "$CONFIG" declare -p WF_SHADOW_SAVE >> "$CONFIG" } get_option_wrap() { unset OPTION get_option case "$OPTION" in AUDIO_DEV) AUDIO_DEV="$(option_inputbox AUDIO_DEV 120 ${AUDIO_DEV:-$(pactl list sources | sed -n 's/\s*Name:\s*\(.*\)/\1/p' | tail -1 2>/dev/null)})" ;; AUDIO_CODEC) AUDIO_CODEC="$(option_inputbox AUDIO_CODEC 24 ${AUDIO_CODEC:-aac})" ;; NO_AUDIO) NO_AUDIO="$(option_yesno AUDIO)" ;; VIDEO_DEV) VIDEO_DEV="$(option_inputbox VIDEO_DEV 64 ${VIDEO_DEV:-/dev/dri/renderD128})" ;; VIDEO_CODEC) VIDEO_CODEC="$(option_inputbox VIDEO_CODEC 24 ${VIDEO_CODEC:-libx264})" ;; NO_VIDEO) NO_VIDEO="$(option_yesno VIDEO)" ;; WF_SHADOW_DIR) WF_SHADOW_DIR="$(option_dir)" ;; WF_SHADOW_FMT) WF_SHADOW_FMT="$(option_inputbox WF_SHADOW_FMT 24 ${WF_SHADOW_FMT:-%Y%m%d_%H:%M:%S})" ;; WF_SHADOW_EXT) WF_SHADOW_EXT="$(option_inputbox WF_SHADOW_EXT 24 ${WF_SHADOW_EXT:-mp4})" ;; WF_SHADOW_SAVE) WF_SHADOW_SAVE="$(option_inputbox WF_SHADOW_SAVE 120)" ;; *) config_to_file; get_main_wrap; exit ;; esac get_option_wrap } get_main() { MAIN="$(eval "dialog $TITLE --menu 'Main Menu' 9 64 9 'Outputs' 'Start, record, or end a wf-shadow session' 'Config' 'Configure wf-shadow' 3>&1 1>&2 2>&3")" } get_main_wrap() { unset MAIN get_main case "$MAIN" in Outputs) get_output_wrap ;; Config) get_option_wrap ;; esac } until [ -z "$1" ]; do case "$1" in '-v' | '--version') printf "wf-shadow-tui %s\n" "$VER" wf-shadow --version printf "dialog %s\n" "$(dialog --version)" exit ;; '-h' | '--help') cat << EOF USAGE: wf-shadow-tui [OPTION] OPTIONS: -h, --help Show this help menu -v, --version Show version information EOF exit ;; esac done get_main_wrap