A collection of scripts
1#!/bin/sh 2# shellcheck disable=SC1090,SC2154 3 4# SC1090 & SC2154 5# The files sourced are user generated files that should contain the needed 6# variables for the script to function correctly. It should be safe to ignore 7# these warnings. 8 9# Required Commands 10# ffmpeg - needed for aud 11# grim - needed for pic 12# mkdir - create missing directories 13# pactl - create loopback devices for multi-device audio recording in wf-recorder 14# slurp - make a selection 15# wf-recorder - needed for rec 16# wl-copy - copy images to clipboard 17 18# This script is intended for use on wayland; however, `scr aud` should work fine without 19# wayland. 20 21# Set required variables if needed 22[ "$SCR_CFG_DIR" ] || SCR_CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/scr" 23[ "$SCR_CACHE_DIR" ] || SCR_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/scr" 24 25# Source the configuration file 26# A sample configuration can be found in my dotfiles at: 27# https://github.com/yemouu/setup/blob/master/root/home/cfg/scr/config.sh 28. "$SCR_CFG_DIR/config.sh" || \ 29 { printf '%s\n' "${0##*/}: failed to source $SCR_CONFIG_DIR/config.sh" 1>&2; exit 1; } 30 31# Usage statement for the script 32usage() { 33 printf '%s\n' "usage: ${0##*/} action [options]" \ 34 "actions:" \ 35 " aud - audio" \ 36 " pic - picture" \ 37 " rec - record" \ 38 "options:" \ 39 " -a - record desktop audio" \ 40 " -c - copy image to clipboard" \ 41 " -h - display this message" \ 42 " -m - record microphone audio" \ 43 " -o - output to use" 44} 45 46# Determine the action to run 47case $1 in 48 aud ) action="scr_aud" ;; 49 pic ) action="scr_pic" ;; 50 rec ) action="scr_rec" ;; 51 *h|*help ) usage; exit 0 ;; 52 * ) printf '%s\n' "${0##*/}: $1: invalid action" 1>&2; usage 1>&2; exit 1 ;; 53esac 54shift 55 56# Determine options to run with based on arguments 57# (I need to stop) 58for flag in "$@" 59do 60 # Make sure arguments start with '-' and are atleast 2 characters long 61 case $flag in 62 - ) continue ;; 63 -- ) break ;; 64 -* ) ;; 65 * ) continue;; 66 esac 67 68 # Split arguments to be 1 character long and determine options to use 69 args=${flag#-} 70 while [ "$args" ] 71 do 72 a=${args%${args#?}} 73 case $a in 74 a ) desktop_audio=true ;; 75 c ) copy_clipboard=true ;; 76 h ) usage; exit 0 ;; 77 m ) microphone=true ;; 78 o ) aargs=$* 79 output=${aargs##*${flag}}; output=${output#\ }; output=${output%%\ *} 80 [ "${output}" ] || printf '%s\n' "${0##*/}: -o: missing output" 1>&2 ;; 81 * ) printf '%s\n' "${0##*/}: -$a: invalid argument" 1>&2 82 usage 1>&2; exit 1 ;; 83 esac 84 args=${args#?} 85 done 86done 87unset args arg 88 89# Simple function to print out an error message and exit 90die() { 91 printf '%s\n' "${0##*/}: $*" 1>&2 92 exit 1 93} 94 95# Record Audio 96scr_aud() { 97 # Create the directory to store audio recordings if it does not already exist 98 [ -d "$scr_aud_dir" ] || \ 99 { mkdir -p "$scr_aud_dir" || die "failed to make directory: $scr_aud_dir"; } 100 101 # Create the directory to store logs if it does not already exist 102 [ -d "$SCR_CACHE_DIR" ] || \ 103 { mkdir -p "$SCR_CACHE_DIR" || \ 104 die "failed to make directory: $SCR_CACHE_DIR"; } 105 106 filename="$scr_aud_dir/$aud_filename" 107 108 # Require atleast one of the arguments: -a or -m 109 [ "$microphone" ] || [ "$desktop_audio" ] || \ 110 { die "aud: argument -a or -m is required to record audio"; } 111 112 # Set ffmpeg options based on script options 113 [ "$microphone" ] && { args="-f pulse -i $aud_source"; } 114 [ "$desktop_audio" ] && { args="$args -f pulse -i $aud_sink"; } 115 [ "$microphone" ] && [ "$desktop_audio" ] && \ 116 { args="$args -filter_complex amix=inputs=2"; } 117 118 # Pressing Ctrl+C will exit the script instead of just wf-recorder. 119 # Intercept Ctrl+C and exit wf-recorder instead of the script 120 trap 'kill -2 $aud_pid' INT 121 122 # shellcheck disable=SC2086 123 # Word splitting is favorable here 124 ffmpeg $args "$filename" > "$SCR_CACHE_DIR/aud.log" 2>&1 & 125 aud_pid=$! 126 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 127 wait $aud_pid 128 129 # Reset the trap 130 trap - INT 131 132 printf '\n%s\n' "$filename" 133} 134 135# Take a screenshot 136scr_pic() { 137 # Create directories if they do not already exist 138 [ -d "$scr_pic_dir" ] || \ 139 { mkdir -p "$scr_pic_dir" || die "failed to make directory: $scr_pic_dir"; } 140 141 [ -d "$SCR_CACHE_DIR" ] || \ 142 { mkdir -p "$SCR_CACHE_DIR" || \ 143 die "failed to create directory: $SCR_CACHE_DIR"; } 144 145 filename="$scr_pic_dir/$pic_filename" 146 147 # Get the geometry of the screenshot from the user and take the screenshot 148 if [ "$output" ]; then set -- -o "$output"; else set -- -g "$(slurp)"; fi 149 grim "$@" "$filename" > "$SCR_CACHE_DIR/pic.log" 2>&1 150 151 # Copy the image to the system clipboard 152 $copy_clipboard && { wl-copy <"$filename" > "$SCR_CACHE_DIR/copy.log" 2>&1; } 153 154 printf '%s\n' "$filename" 155} 156 157scr_rec() { 158 # Create directories if they do not already exist 159 [ -d "$scr_rec_dir" ] || \ 160 { mkdir -p "$scr_rec_dir" || die "failed to make directory: $scr_pic_dir"; } 161 162 [ -d "$SCR_CACHE_DIR" ] || \ 163 { mkdir -p "$SCR_CACHE_DIR" || \ 164 die "failed to make directory: $SCR_CACHE_DIR"; } 165 166 filename="$scr_rec_dir/$rec_filename" 167 168 # Set wf-recorder arguments based on script options 169 [ "$microphone" ] && args="-a$aud_source" 170 [ "$desktop_audio" ] && args="-a$aud_sink" 171 172 # If both microphone and desktop_audio is set, create a loopback devices pointing to 173 # scr_inputs. wf-record does not support multiple audio devices. This is how they 174 # recomend you record two devices at the same time. 175 [ "$microphone" ] && [ "$desktop_audio" ] && { 176 unload_pulse_modules=true 177 null_sink=$(pactl load-module module-null-sink sink_name=aud_both) 178 lb_desk=$(pactl load-module module-loopback sink=aud_both source="$aud_sink") 179 lb_mic=$(pactl load-module module-loopback sink=aud_both source="$aud_source") 180 args="-aaud_both.monitor" 181 } 182 183 # Pressing Ctrl+C will exit the script instead of just wf-recorder. 184 # Intercept Ctrl+C and exit wf-recorder instead of the script 185 trap 'kill -2 $rec_pid' INT 186 187 if [ "$output" ]; then set -- -o "$output"; else set -- -g "$(slurp)"; fi 188 # Word splitting is favorable here 189 # shellcheck disable=SC2086 190 wf-recorder $args "$@" -f "$filename" > "$SCR_CACHE_DIR/rec.log" 2>&1 & 191 rec_pid=$! 192 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 193 wait $rec_pid 194 195 # Reset the trap 196 trap - INT 197 198 # Clean up pulseaudio modules that the script created 199 [ "$unload_pulse_modules" ] && { 200 pactl unload-module "$lb_mic" 201 pactl unload-module "$lb_desk" 202 pactl unload-module "$null_sink" 203 } 204 205 printf '\n%s\n' "$filename" 206} 207 208$action