A collection of scripts
1#!/bin/sh 2# shellcheck disable=SC1090,SC1091,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/home/cfg/scr/config.sh 28. "$SCR_CFG_DIR/config.sh" || { 29 printf '%s\n' "${0##*/}: failed to source $SCR_CFG_DIR/config.sh" 1>&2; exit 1 30} 31 32# Usage statement for the script 33usage() { 34 printf '%s\n' "usage: ${0##*/} action [options]" \ 35 "actions:" \ 36 "\taud - audio" \ 37 "\tpic - picture" \ 38 "\trec - record" \ 39 "options:" \ 40 "\t-a - record desktop audio (aud,rec)" \ 41 "\t-c - copy image to clipboard (pic)" \ 42 "\t-h - display this message" \ 43 "\t-m - record microphone audio (aud,rec)" \ 44 "\t-o - output to use (pic,rec)" \ 45 "\t-d - all displays (pic)" 46} 47 48# Determine the action to run 49case $1 in 50 aud ) action="scr_aud" ;; 51 pic ) action="scr_pic" ;; 52 rec ) action="scr_rec" ;; 53 *h|*help ) usage; exit 0 ;; 54 * ) printf '%s\n' "${0##*/}: $1: invalid action" 1>&2; usage 1>&2; exit 1 ;; 55esac 56shift 57 58# Determine options to run with based on arguments 59# (I need to stop) 60for flag in "$@" 61do 62 # Make sure arguments start with '-' and are atleast 2 characters long 63 case $flag in 64 - ) continue ;; 65 -- ) break ;; 66 -* ) ;; 67 * ) continue;; 68 esac 69 70 # Split arguments to be 1 character long and determine options to use 71 args=${flag#-} 72 73 while [ "$args" ] 74 do 75 a=${args%${args#?}} 76 77 case $a in 78 a ) desktop_audio=true ;; 79 c ) copy_clipboard=true ;; 80 d ) output=all ;; # Kinda redundent lol 81 h ) usage; exit 0 ;; 82 m ) microphone=true ;; 83 o ) aargs=$* 84 output=${aargs##*${flag}}; output=${output#\ }; output=${output%%\ *} 85 [ "${output}" ] || printf '%s\n' "${0##*/}: -o: missing output" 1>&2 ;; 86 * ) printf '%s\n' "${0##*/}: -$a: invalid argument" 1>&2 87 usage 1>&2; exit 1 ;; 88 esac 89 90 args=${args#?} 91 done 92done 93unset args arg 94 95# Simple function to print out an error message and exit 96die() { 97 printf '%s\n' "${0##*/}: $*" 1>&2 98 exit 1 99} 100 101# Record Audio 102scr_aud() { 103 # Create the directory to store audio recordings if it does not already exist 104 [ -d "$scr_aud_dir" ] || \ 105 { mkdir -p "$scr_aud_dir" || die "failed to make directory: $scr_aud_dir"; } 106 107 # Create the directory to store logs if it does not already exist 108 [ -d "$SCR_CACHE_DIR" ] || \ 109 { mkdir -p "$SCR_CACHE_DIR" || \ 110 die "failed to make directory: $SCR_CACHE_DIR"; } 111 112 filename="$scr_aud_dir/$aud_filename" 113 114 # Require atleast one of the arguments: -a or -m 115 [ "$microphone" ] || [ "$desktop_audio" ] || \ 116 { die "aud: argument -a or -m is required to record audio"; } 117 118 # Set ffmpeg options based on script options 119 [ "$microphone" ] && { args="-f pulse -i $aud_source"; } 120 [ "$desktop_audio" ] && { args="$args -f pulse -i $aud_sink"; } 121 [ "$microphone" ] && [ "$desktop_audio" ] && \ 122 { args="$args -filter_complex amix=inputs=2"; } 123 124 # Pressing Ctrl+C will exit the script instead of just ffmpeg. 125 # Intercept Ctrl+C and do nothing. 126 trap '' INT 127 128 # shellcheck disable=SC2086 129 # Word splitting is favorable here 130 ffmpeg $args "$filename" > "$SCR_CACHE_DIR/aud.log" 2>&1 & 131 aud_pid=$! 132 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 133 wait $aud_pid 134 135 # Reset the trap 136 trap - INT 137 138 printf '\n%s\n' "$filename" 139} 140 141# Take a screenshot 142scr_pic() { 143 # Create directories if they do not already exist 144 [ -d "$scr_pic_dir" ] || \ 145 { mkdir -p "$scr_pic_dir" || die "failed to make directory: $scr_pic_dir"; } 146 147 [ -d "$SCR_CACHE_DIR" ] || \ 148 { mkdir -p "$SCR_CACHE_DIR" || \ 149 die "failed to create directory: $SCR_CACHE_DIR"; } 150 151 filename="$scr_pic_dir/$pic_filename" 152 153 if [ "$output" = "all" ] 154 then 155 # Grim will screenshot all monitors by default 156 grim "$filename" > "$SCR_CACHE_DIR/pic.log" 2>&1 157 else 158 # Get the geometry of the screenshot from the user and take the screenshot 159 if [ "$output" ]; then set -- -o "$output"; else set -- -g "$(slurp)"; fi 160 grim "$@" "$filename" > "$SCR_CACHE_DIR/pic.log" 2>&1 161 fi 162 163 164 # Copy the image to the system clipboard 165 $copy_clipboard && { wl-copy <"$filename" > "$SCR_CACHE_DIR/copy.log" 2>&1; } 166 167 printf '%s\n' "$filename" 168} 169 170scr_rec() { 171 # Create directories if they do not already exist 172 [ -d "$scr_rec_dir" ] || \ 173 { mkdir -p "$scr_rec_dir" || die "failed to make directory: $scr_pic_dir"; } 174 175 [ -d "$SCR_CACHE_DIR" ] || \ 176 { mkdir -p "$SCR_CACHE_DIR" || \ 177 die "failed to make directory: $SCR_CACHE_DIR"; } 178 179 filename="$scr_rec_dir/$rec_filename" 180 181 # Set wf-recorder arguments based on script options 182 [ "$microphone" ] && args="-a$aud_source" 183 [ "$desktop_audio" ] && args="-a$aud_sink" 184 185 # If both microphone and desktop_audio is set, create a loopback devices pointing to 186 # scr_inputs. wf-record does not support multiple audio devices. This is how they 187 # recomend you record two devices at the same time. 188 [ "$microphone" ] && [ "$desktop_audio" ] && { 189 unload_pulse_modules=true 190 null_sink=$(pactl load-module module-null-sink sink_name=aud_both) 191 lb_desk=$(pactl load-module module-loopback sink=aud_both source="$aud_sink") 192 lb_mic=$(pactl load-module module-loopback sink=aud_both source="$aud_source") 193 args="-aaud_both.monitor" 194 } 195 196 # Pressing Ctrl+C will exit the script instead of just wf-recorder. 197 # Intercept Ctrl+C and exit wf-recorder instead of the script 198 trap '' INT 199 200 if [ "$output" ]; then set -- -o "$output"; else set -- -g "$(slurp)"; fi 201 # Word splitting is favorable here 202 # shellcheck disable=SC2086 203 wf-recorder $args $rec_extraflags "$@" -f "$filename" > "$SCR_CACHE_DIR/rec.log" 2>&1 & 204 rec_pid=$! 205 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 206 wait $rec_pid 207 208 # Reset the trap 209 trap - INT 210 211 # Clean up pulseaudio modules that the script created 212 [ "$unload_pulse_modules" ] && { 213 pactl unload-module "$lb_mic" 214 pactl unload-module "$lb_desk" 215 pactl unload-module "$null_sink" 216 } 217 218 printf '\n%s\n' "$filename" 219} 220 221$action 222 223# Run post scripts 224# Scripts in the directory `$SCR_CFG_DIR/scripts` will 225# take in `$action` as `$1` and `$filename` as `$2`. 226# Sample scripts can be found in my dotfiles at: 227# https://github.com/yemouu/setup/blob/master/home/cfg/scr/scripts 228for i in "$SCR_CFG_DIR/scripts/"* 229do 230 [ -x "$i" ] && { 231 printf '%s\n' "# $i --- START" >> "$SCR_CACHE_DIR/scripts.log" 232 $i "$action" "$filename" > "$SCR_CACHE_DIR/scripts.log" 2>&1 233 printf '%s\n' "# $i --- END" >> "$SCR_CACHE_DIR/scripts.log" 234 } 235done