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