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} 44 45# Determine the action to run 46case $1 in 47 aud ) action="scr_aud" ;; 48 pic ) action="scr_pic" ;; 49 rec ) action="scr_rec" ;; 50 *h|*help ) usage; exit 0 ;; 51 * ) printf '%s\n' "${0##*/}: $1: invalid action" 1>&2; usage 1>&2; exit 1 ;; 52esac 53shift 54 55# Determine options to run with based on arguments 56for flag in "$@" 57do 58 # Make sure arguments start with '-' and are atleast 2 characters long 59 case $flag in 60 - ) continue ;; 61 -- ) break ;; 62 -* ) ;; 63 * ) continue;; 64 esac 65 66 # Split arguments to be 1 character long and determine options to use 67 flag=${flag#-} 68 while [ "$flag" ] 69 do 70 a=${flag%${flag#?}} 71 case $a in 72 a ) desktop_audio=true ;; 73 c ) copy_clipboard=true ;; 74 h ) usage; exit 0 ;; 75 m ) microphone=true ;; 76 * ) printf '%s\n' "${0##*/}: -$a: invalid argument" 1>&2 77 usage 1>&2; exit 1 ;; 78 esac 79 flag=${flag#?} 80 done 81done 82unset args arg 83 84# Simple function to print out an error message and exit 85die() { 86 printf '%s\n' "${0##*/}: $*" 1>&2 87 exit 1 88} 89 90# Record Audio 91scr_aud() { 92 # Create the directory to store audio recordings if it does not already exist 93 [ -d "$scr_aud_dir" ] || \ 94 { mkdir -p "$scr_aud_dir" || die "failed to make directory: $scr_aud_dir"; } 95 96 # Create the directory to store logs if it does not already exist 97 [ -d "$SCR_CACHE_DIR" ] || \ 98 { mkdir -p "$SCR_CACHE_DIR" || \ 99 die "failed to make directory: $SCR_CACHE_DIR"; } 100 101 filename="$scr_aud_dir/$aud_filename" 102 103 # Require atleast one of the arguments: -a or -m 104 [ "$microphone" ] || [ "$desktop_audio" ] || \ 105 { die "aud: argument -a or -m is required to record audio"; } 106 107 # Set ffmpeg options based on script options 108 [ "$microphone" ] && { args="-f pulse -i $aud_source"; } 109 [ "$desktop_audio" ] && { args="$args -f pulse -i $aud_sink"; } 110 [ "$microphone" ] && [ "$desktop_audio" ] && \ 111 { args="$args -filter_complex amix=inputs=2"; } 112 113 # Pressing Ctrl+C will exit the script instead of just wf-recorder. 114 # Intercept Ctrl+C and exit wf-recorder instead of the script 115 trap 'kill -2 $aud_pid' INT 116 117 # shellcheck disable=SC2086 118 # Word splitting is favorable here 119 ffmpeg $args "$filename" > "$SCR_CACHE_DIR/aud.log" 2>&1 & 120 aud_pid=$! 121 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 122 wait $aud_pid 123 124 # Reset the trap 125 trap - INT 126 127 printf '\n%s\n' "$filename" 128} 129 130# Take a screenshot 131scr_pic() { 132 # Create directories if they do not already exist 133 [ -d "$scr_pic_dir" ] || \ 134 { mkdir -p "$scr_pic_dir" || die "failed to make directory: $scr_pic_dir"; } 135 136 [ -d "$SCR_CACHE_DIR" ] || \ 137 { mkdir -p "$SCR_CACHE_DIR" || \ 138 die "failed to create directory: $SCR_CACHE_DIR"; } 139 140 filename="$scr_pic_dir/$pic_filename" 141 142 # Get the geometry of the screenshot from the user and take the screenshot 143 grim -g "$(slurp)" "$filename" > "$SCR_CACHE_DIR/pic.log" 2>&1 144 145 # Copy the image to the system clipboard 146 $copy_clipboard && { wl-copy <"$filename" > "$SCR_CACHE_DIR/copy.log" 2>&1; } 147 148 printf '%s\n' "$filename" 149} 150 151scr_rec() { 152 # Create directories if they do not already exist 153 [ -d "$scr_rec_dir" ] || \ 154 { mkdir -p "$scr_rec_dir" || die "failed to make directory: $scr_pic_dir"; } 155 156 [ -d "$SCR_CACHE_DIR" ] || \ 157 { mkdir -p "$SCR_CACHE_DIR" || \ 158 die "failed to make directory: $SCR_CACHE_DIR"; } 159 160 filename="$scr_rec_dir/$rec_filename" 161 162 # Set wf-recorder arguments based on script options 163 [ "$microphone" ] && args="-a$aud_source" 164 [ "$desktop_audio" ] && args="-a$aud_sink" 165 166 # If both microphone and desktop_audio is set, create a loopback devices pointing to 167 # scr_inputs. wf-record does not support multiple audio devices. This is how they 168 # recomend you record two devices at the same time. 169 [ "$microphone" ] && [ "$desktop_audio" ] && { 170 unload_pulse_modules=true 171 null_sink=$(pactl load-module module-null-sink sink_name=aud_both) 172 lb_desk=$(pactl load-module module-loopback sink=aud_both source="$aud_sink") 173 lb_mic=$(pactl load-module module-loopback sink=aud_both source="$aud_source") 174 args="-aaud_both.monitor" 175 } 176 177 # Pressing Ctrl+C will exit the script instead of just wf-recorder. 178 # Intercept Ctrl+C and exit wf-recorder instead of the script 179 trap 'kill -2 $rec_pid' INT 180 181 # Word splitting is favorable here 182 # shellcheck disable=SC2086 183 wf-recorder $args -g "$(slurp)" -f "$filename" > "$SCR_CACHE_DIR/rec.log" 2>&1 & 184 rec_pid=$! 185 printf '%s' "Press Ctrl+C to stop recording. " 1>&2 186 wait $rec_pid 187 188 # Reset the trap 189 trap - INT 190 191 # Clean up pulseaudio modules that the script created 192 [ "$unload_pulse_modules" ] && { 193 pactl unload-module "$lb_mic" 194 pactl unload-module "$lb_desk" 195 pactl unload-module "$null_sink" 196 } 197 198 printf '\n%s\n' "$filename" 199} 200 201$action